Skip to content
This repository was archived by the owner on Mar 24, 2022. It is now read-only.

Commit e71f190

Browse files
formalize codegen toggles, add that and version info to modules
also add a check in lucet-runtime that modules loaded have capabilities (and thus, version information) present, rejecting modules that do not
1 parent f495487 commit e71f190

11 files changed

Lines changed: 203 additions & 40 deletions

File tree

lucet-analyze/src/main.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use lucet_module::{
44
FunctionSpec, Module, ModuleData, SerializedModule, TableElement, TrapManifest, TrapSite,
5+
VersionInfo,
56
};
67

78
use byteorder::{LittleEndian, ReadBytesExt};
@@ -102,7 +103,12 @@ impl<'a> ArtifactSummary<'a> {
102103
.unwrap();
103104
let mut rdr = Cursor::new(buffer);
104105

106+
let version = unsafe {
107+
std::mem::transmute::<u64, VersionInfo>(rdr.read_u64::<LittleEndian>().unwrap())
108+
};
109+
105110
SerializedModule {
111+
version,
106112
module_data_ptr: rdr.read_u64::<LittleEndian>().unwrap(),
107113
module_data_len: rdr.read_u64::<LittleEndian>().unwrap(),
108114
tables_ptr: rdr.read_u64::<LittleEndian>().unwrap(),
@@ -211,6 +217,7 @@ fn load_module<'b, 'a: 'b>(
211217
)
212218
};
213219
Module {
220+
version: serialized_module.version.clone(),
214221
module_data,
215222
tables,
216223
function_manifest,

lucet-module/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod signature;
1717
mod tables;
1818
mod traps;
1919
mod types;
20+
mod version_info;
2021

2122
pub use crate::error::Error;
2223
pub use crate::functions::{
@@ -32,6 +33,7 @@ pub use crate::signature::{ModuleSignature, PublicKey};
3233
pub use crate::tables::TableElement;
3334
pub use crate::traps::{TrapCode, TrapManifest, TrapSite};
3435
pub use crate::types::{Signature, ValueType};
36+
pub use crate::version_info::{Capabilities, CapabilitiesBuilder, VersionInfo};
3537

3638
/// Owned variants of the module data types, useful for serialization and testing.
3739
pub mod owned {

lucet-module/src/module.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use crate::functions::FunctionSpec;
22
use crate::module_data::ModuleData;
33
use crate::tables::TableElement;
4+
use crate::version_info::VersionInfo;
45

56
pub const LUCET_MODULE_SYM: &str = "lucet_module";
67

78
/// Module is the exposed structure that contains all the data backing a Lucet-compiled object.
89
#[derive(Debug)]
910
pub struct Module<'a> {
11+
pub version: VersionInfo,
1012
pub module_data: ModuleData<'a>,
1113
pub tables: &'a [&'a [TableElement]],
1214
pub function_manifest: &'a [FunctionSpec],
@@ -18,6 +20,7 @@ pub struct Module<'a> {
1820
#[repr(C)]
1921
#[derive(Debug)]
2022
pub struct SerializedModule {
23+
pub version: VersionInfo,
2124
pub module_data_ptr: u64,
2225
pub module_data_len: u64,
2326
pub tables_ptr: u64,

lucet-module/src/version_info.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/// VersionInfo is information about a Lucet module to allow the Lucet runtime to determine if or
2+
/// how the module can be loaded, if so requested. The information here describes implementation
3+
/// details in runtime support for `lucetc`-produced modules, and nothing higher level.
4+
#[repr(C)]
5+
#[derive(Debug, Clone)]
6+
pub struct VersionInfo {
7+
major: u8,
8+
minor: u8,
9+
patch: u8,
10+
reserved: u8,
11+
pub capabilities: Capabilities,
12+
}
13+
14+
impl VersionInfo {
15+
pub fn current() -> Self {
16+
VersionInfo {
17+
major: 0,
18+
minor: 1,
19+
patch: 0,
20+
reserved: 0,
21+
capabilities: Capabilities::default(),
22+
}
23+
}
24+
}
25+
26+
const INSTRUCTIONS_COUNTED_BIT: u8 = 0;
27+
28+
// This bit will always be 1 if capabilities and version info are present.
29+
//
30+
// The reasoning for this is as follows:
31+
// `SerializedModule`, in version before version information was introduced, began with a pointer -
32+
// `module_data_ptr`. This pointer would be relocated to somewhere in user space for the embedder
33+
// of `lucet-runtime`. On x86_64, hopefully, that's userland code in some OS, meaning the pointer
34+
// will be a pointer to user memory, and will be below 0x8000_0000_0000_0000. By setting bit 31 in
35+
// capabilities, we set what would be the highest bit in `module_data_ptr` in an old
36+
// `lucet-runtime` and guarantee a segmentation fault when loading these newer modules with version
37+
// information.
38+
const CAPABILITIES_BIT: u8 = 31;
39+
40+
/// In addition to structure compatibility, a module can declare capabilities to the runtime. These
41+
/// do not necessarily require any runtime support, but indicate variations to the module that the
42+
/// runtime may find interesting.
43+
#[repr(C)]
44+
#[derive(Debug, Clone)]
45+
pub struct Capabilities {
46+
caps: u32,
47+
}
48+
49+
impl From<u32> for Capabilities {
50+
fn from(caps: u32) -> Capabilities {
51+
Capabilities { caps }
52+
}
53+
}
54+
55+
impl Capabilities {
56+
fn get_bit(&self, bit_num: u8) -> bool {
57+
assert!(bit_num < 32);
58+
let bit = (self.caps >> bit_num) & 1;
59+
if bit == 0 {
60+
false
61+
} else {
62+
true
63+
}
64+
}
65+
66+
pub fn instructions_counted(&self) -> bool {
67+
self.get_bit(INSTRUCTIONS_COUNTED_BIT)
68+
}
69+
70+
pub fn present(&self) -> bool {
71+
self.get_bit(CAPABILITIES_BIT)
72+
}
73+
}
74+
75+
impl Default for Capabilities {
76+
fn default() -> Self {
77+
CapabilitiesBuilder::new().build()
78+
}
79+
}
80+
81+
#[derive(Debug, Clone)]
82+
pub struct CapabilitiesBuilder {
83+
caps: u32,
84+
}
85+
86+
impl CapabilitiesBuilder {
87+
/// A CapabilitiesBuilder with all capabilities disabled
88+
pub fn new() -> Self {
89+
let mut caps = CapabilitiesBuilder { caps: 0u32 };
90+
caps.set_bit(CAPABILITIES_BIT, true);
91+
caps
92+
}
93+
94+
fn set_bit(&mut self, bit_num: u8, setting: bool) {
95+
assert!(bit_num < 32);
96+
self.caps &= !(1 << bit_num);
97+
self.caps |= (setting as u32) << bit_num;
98+
}
99+
100+
pub fn instructions_counted(&mut self, setting: bool) {
101+
self.set_bit(INSTRUCTIONS_COUNTED_BIT, setting);
102+
}
103+
104+
pub fn with_instructions_counted(mut self, setting: bool) -> Self {
105+
self.instructions_counted(setting);
106+
self
107+
}
108+
109+
pub fn build(self) -> Capabilities {
110+
self.caps.into()
111+
}
112+
}

lucet-runtime/lucet-runtime-internals/src/module/dl.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ impl DlModule {
6161
let serialized_module: &SerializedModule =
6262
unsafe { serialized_module_ptr.as_ref().unwrap() };
6363

64+
let version = serialized_module.version.clone();
65+
66+
if !version.capabilities.present() {
67+
return Err(lucet_incorrect_module!("error loading module: capabilities are not present. This module is likely too old for this lucet-runtime to load."));
68+
}
69+
6470
// Deserialize the slice into ModuleData, which will hold refs into the loaded
6571
// shared object file in `module_data_slice`. Both of these get a 'static lifetime because
6672
// Rust doesn't have a safe way to describe that their lifetime matches the containing
@@ -115,6 +121,7 @@ impl DlModule {
115121
lib,
116122
fbase,
117123
module: lucet_module::Module {
124+
version,
118125
module_data,
119126
tables,
120127
function_manifest,

lucet-spectest/src/script.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::bindings;
22
use failure::{format_err, Error, Fail};
3+
use lucet_module::CapabilitiesBuilder;
34
use lucet_runtime::{self, MmapRegion, Module as LucetModule, Region, UntypedRetVal, Val};
45
use lucetc::{Compiler, HeapSettings, LucetcError, LucetcErrorKind, OptLevel};
56
use std::io;
@@ -72,7 +73,9 @@ impl ScriptEnv {
7273
OptLevel::Fast,
7374
&bindings,
7475
HeapSettings::default(),
75-
true,
76+
CapabilitiesBuilder::new()
77+
.with_instructions_counted(true)
78+
.build(),
7679
)
7780
.map_err(program_error)?;
7881

lucet-wasi-sdk/tests/lucetc.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
mod lucetc_tests {
33
use failure::Error;
44
use lucet_module::bindings::Bindings;
5+
use lucet_module::Capabilities;
56
use lucet_wasi_sdk::*;
67
use lucetc::{Compiler, HeapSettings, OptLevel};
78
use std::collections::HashMap;
@@ -39,7 +40,8 @@ mod lucetc_tests {
3940
let m = module_from_c(&["empty"], &[]).expect("build module for empty");
4041
let b = Bindings::empty();
4142
let h = HeapSettings::default();
42-
let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile empty");
43+
let c = Compiler::new(&m, OptLevel::Fast, &b, h, Capabilities::default())
44+
.expect("compile empty");
4345
let mdata = c.module_data().unwrap();
4446
assert!(mdata.heap_spec().is_some());
4547
// clang creates 3 globals:
@@ -74,7 +76,8 @@ mod lucetc_tests {
7476
let m = module_from_c(&["c"], &["c"]).expect("build module for c");
7577
let b = Bindings::empty();
7678
let h = HeapSettings::default();
77-
let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile c");
79+
let c =
80+
Compiler::new(&m, OptLevel::Fast, &b, h, Capabilities::default()).expect("compile c");
7881
let mdata = c.module_data().unwrap();
7982
assert_eq!(mdata.import_functions().len(), 0, "import functions");
8083
assert_eq!(mdata.export_functions().len(), 1, "export functions");
@@ -91,7 +94,8 @@ mod lucetc_tests {
9194
let m = module_from_c(&["d"], &["d"]).expect("build module for d");
9295
let b = d_only_test_bindings();
9396
let h = HeapSettings::default();
94-
let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile d");
97+
let c =
98+
Compiler::new(&m, OptLevel::Fast, &b, h, Capabilities::default()).expect("compile d");
9599
let mdata = c.module_data().unwrap();
96100
assert_eq!(mdata.import_functions().len(), 1, "import functions");
97101
assert_eq!(mdata.export_functions().len(), 1, "export functions");
@@ -107,7 +111,8 @@ mod lucetc_tests {
107111
let m = module_from_c(&["c", "d"], &["c", "d"]).expect("build module for c & d");
108112
let b = Bindings::empty();
109113
let h = HeapSettings::default();
110-
let c = Compiler::new(&m, OptLevel::Fast, &b, h, false).expect("compile c & d");
114+
let c = Compiler::new(&m, OptLevel::Fast, &b, h, Capabilities::default())
115+
.expect("compile c & d");
111116
let mdata = c.module_data().unwrap();
112117
assert_eq!(mdata.import_functions().len(), 0, "import functions");
113118
assert_eq!(mdata.export_functions().len(), 2, "export functions");

lucetc/src/compiler.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use cranelift_native;
1919
use cranelift_wasm::{translate_module, FuncTranslator, WasmError};
2020
use failure::{format_err, Fail, ResultExt};
2121
use lucet_module::bindings::Bindings;
22-
use lucet_module::{FunctionSpec, ModuleData, MODULE_DATA_SYM};
22+
use lucet_module::{Capabilities, FunctionSpec, ModuleData, MODULE_DATA_SYM};
2323

2424
#[derive(Debug, Clone, Copy)]
2525
pub enum OptLevel {
@@ -48,7 +48,7 @@ pub struct Compiler<'a> {
4848
decls: ModuleDecls<'a>,
4949
clif_module: ClifModule<FaerieBackend>,
5050
opt_level: OptLevel,
51-
count_instructions: bool,
51+
capabilities: Capabilities,
5252
}
5353

5454
impl<'a> Compiler<'a> {
@@ -57,7 +57,7 @@ impl<'a> Compiler<'a> {
5757
opt_level: OptLevel,
5858
bindings: &'a Bindings,
5959
heap_settings: HeapSettings,
60-
count_instructions: bool,
60+
capabilities: Capabilities,
6161
) -> Result<Self, LucetcError> {
6262
let isa = Self::target_isa(opt_level);
6363

@@ -108,7 +108,7 @@ impl<'a> Compiler<'a> {
108108
decls,
109109
clif_module,
110110
opt_level,
111-
count_instructions,
111+
capabilities,
112112
})
113113
}
114114

@@ -120,7 +120,8 @@ impl<'a> Compiler<'a> {
120120
let mut func_translator = FuncTranslator::new();
121121

122122
for (ref func, (code, code_offset)) in self.decls.function_bodies() {
123-
let mut func_info = FuncInfo::new(&self.decls, self.count_instructions);
123+
let mut func_info =
124+
FuncInfo::new(&self.decls, self.capabilities.instructions_counted());
124125
let mut clif_context = ClifContext::new();
125126
clif_context.func.name = func.name.as_externalname();
126127
clif_context.func.signature = func.signature.clone();
@@ -175,7 +176,8 @@ impl<'a> Compiler<'a> {
175176
let mut func_translator = FuncTranslator::new();
176177

177178
for (ref func, (code, code_offset)) in self.decls.function_bodies() {
178-
let mut func_info = FuncInfo::new(&self.decls, self.count_instructions);
179+
let mut func_info =
180+
FuncInfo::new(&self.decls, self.capabilities.instructions_counted());
179181
let mut clif_context = ClifContext::new();
180182
clif_context.func.name = func.name.as_externalname();
181183
clif_context.func.signature = func.signature.clone();

lucetc/src/lib.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub use crate::{
3131
};
3232
use failure::{format_err, Error, ResultExt};
3333
pub use lucet_module::bindings::Bindings;
34+
use lucet_module::CapabilitiesBuilder;
3435
use signature::{PublicKey, SecretKey};
3536
use std::env;
3637
use std::path::{Path, PathBuf};
@@ -51,7 +52,7 @@ pub struct Lucetc {
5152
pk: Option<PublicKey>,
5253
sign: bool,
5354
verify: bool,
54-
count_instructions: bool,
55+
capabilities: CapabilitiesBuilder,
5556
}
5657

5758
pub trait AsLucetc {
@@ -207,12 +208,12 @@ impl<T: AsLucetc> LucetcOpts for T {
207208
self
208209
}
209210

210-
fn count_instructions(&mut self, count_instructions: bool) {
211-
self.as_lucetc().count_instructions = count_instructions;
211+
fn count_instructions(&mut self, count: bool) {
212+
self.as_lucetc().capabilities.instructions_counted(count);
212213
}
213214

214-
fn with_count_instructions(mut self, count_instructions: bool) -> Self {
215-
self.count_instructions(count_instructions);
215+
fn with_count_instructions(mut self, count: bool) -> Self {
216+
self.count_instructions(count);
216217
self
217218
}
218219
}
@@ -230,7 +231,7 @@ impl Lucetc {
230231
sk: None,
231232
sign: false,
232233
verify: false,
233-
count_instructions: false,
234+
capabilities: CapabilitiesBuilder::new(),
234235
}
235236
}
236237

@@ -246,7 +247,7 @@ impl Lucetc {
246247
sk: None,
247248
sign: false,
248249
verify: false,
249-
count_instructions: false,
250+
capabilities: CapabilitiesBuilder::new(),
250251
})
251252
}
252253

@@ -286,7 +287,7 @@ impl Lucetc {
286287
self.opt_level,
287288
&bindings,
288289
self.heap.clone(),
289-
self.count_instructions,
290+
self.capabilities.clone().build(),
290291
)?;
291292
let obj = compiler.object_file()?;
292293

@@ -302,7 +303,7 @@ impl Lucetc {
302303
self.opt_level,
303304
&bindings,
304305
self.heap.clone(),
305-
self.count_instructions,
306+
self.capabilities.clone().build(),
306307
)?;
307308

308309
compiler

0 commit comments

Comments
 (0)