Skip to content

Commit f466aa2

Browse files
cfallinfitzgen
andauthored
Skeleton and initial support for proof-carrying code. (#7165)
* WIP veriwasm 2.0 Co-Authored-By: Chris Fallin <cfallin@fastly.com> * PCC: successfully parse some simple facts. Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * PCC: plumb facts through VCode and add framework on LowerBackend to check them. Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * PCC: code is carrying some proofs! Very simple test-case. Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * PCC: add a `safe` flag for checked memory accesses. * PCC: add pretty-printing of facts to CLIF output. * PCC: misc. cleanups. * PCC: lots of cleanup. * Post-rebase fixups and some misc. fixes. * Add serde traits to facts. * PCC: add succeed and fail tests. * Review feedback: rename `safe` memflag to `checked`. * Review feedback. --------- Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com>
1 parent a109d2a commit f466aa2

25 files changed

Lines changed: 919 additions & 18 deletions

File tree

cranelift/codegen/meta/src/shared/settings.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ pub(crate) fn define() -> SettingGroup {
6363
true,
6464
);
6565

66+
settings.add_bool(
67+
"enable_pcc",
68+
"Enable proof-carrying code translation validation.",
69+
r#"
70+
This adds a proof-carrying code mode. TODO ADD MORE
71+
"#,
72+
false,
73+
);
74+
6675
// Note that Cranelift doesn't currently need an is_pie flag, because PIE is
6776
// just PIC where symbols can't be pre-empted, which can be expressed with the
6877
// `colocated` flag on external functions and global values.

cranelift/codegen/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ impl Context {
237237
/// Run the verifier on the function.
238238
///
239239
/// Also check that the dominator tree and control flow graph are consistent with the function.
240+
///
241+
/// TODO: rename to "CLIF validate" or similar.
240242
pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
241243
let mut errors = VerifierErrors::default();
242244
let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);

cranelift/codegen/src/ir/dfg.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::ir;
55
use crate::ir::builder::ReplaceBuilder;
66
use crate::ir::dynamic_type::{DynamicTypeData, DynamicTypes};
77
use crate::ir::instructions::{CallInfo, InstructionData};
8+
use crate::ir::pcc::Fact;
89
use crate::ir::{
910
types, Block, BlockCall, ConstantData, ConstantPool, DynamicType, ExtFuncData, FuncRef,
1011
Immediate, Inst, JumpTables, RelSourceLoc, SigRef, Signature, Type, Value,
@@ -125,6 +126,9 @@ pub struct DataFlowGraph {
125126
/// Primary value table with entries for all values.
126127
values: PrimaryMap<Value, ValueDataPacked>,
127128

129+
/// Facts: proof-carrying-code assertions about values.
130+
pub facts: SecondaryMap<Value, Option<Fact>>,
131+
128132
/// Function signature table. These signatures are referenced by indirect call instructions as
129133
/// well as the external function references.
130134
pub signatures: PrimaryMap<SigRef, Signature>,
@@ -158,6 +162,7 @@ impl DataFlowGraph {
158162
dynamic_types: DynamicTypes::new(),
159163
value_lists: ValueListPool::new(),
160164
values: PrimaryMap::new(),
165+
facts: SecondaryMap::new(),
161166
signatures: PrimaryMap::new(),
162167
old_signatures: SecondaryMap::new(),
163168
ext_funcs: PrimaryMap::new(),

cranelift/codegen/src/ir/memflags.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@ use core::fmt;
66
use serde_derive::{Deserialize, Serialize};
77

88
enum FlagBit {
9+
/// Guaranteed not to trap. This may enable additional
10+
/// optimizations to be performed.
911
Notrap,
12+
/// Guaranteed to use "natural alignment" for the given type. This
13+
/// may enable better instruction selection.
1014
Aligned,
15+
/// A load that reads data in memory that does not change for the
16+
/// duration of the function's execution. This may enable
17+
/// additional optimizations to be performed.
1118
Readonly,
19+
/// Load multi-byte values from memory in a little-endian format.
1220
LittleEndian,
21+
/// Load multi-byte values from memory in a big-endian format.
1322
BigEndian,
1423
/// Accesses only the "heap" part of abstract state. Used for
1524
/// alias analysis. Mutually exclusive with "table" and "vmctx".
@@ -20,10 +29,15 @@ enum FlagBit {
2029
/// Accesses only the "vmctx" part of abstract state. Used for
2130
/// alias analysis. Mutually exclusive with "heap" and "table".
2231
Vmctx,
32+
/// Check this load or store for safety when using the
33+
/// proof-carrying-code framework. The address must have a
34+
/// `PointsTo` fact attached with a sufficiently large valid range
35+
/// for the accessed size.
36+
Checked,
2337
}
2438

25-
const NAMES: [&str; 8] = [
26-
"notrap", "aligned", "readonly", "little", "big", "heap", "table", "vmctx",
39+
const NAMES: [&str; 9] = [
40+
"notrap", "aligned", "readonly", "little", "big", "heap", "table", "vmctx", "checked",
2741
];
2842

2943
/// Endianness of a memory access.
@@ -48,7 +62,7 @@ pub enum Endianness {
4862
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
4963
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
5064
pub struct MemFlags {
51-
bits: u8,
65+
bits: u16,
5266
}
5367

5468
impl MemFlags {
@@ -265,6 +279,32 @@ impl MemFlags {
265279
self.set_vmctx();
266280
self
267281
}
282+
283+
/// Test if the `checked` bit is set.
284+
///
285+
/// Loads and stores with this flag are verified to access
286+
/// pointers only with a validated `PointsTo` fact attached, and
287+
/// with that fact validated, when using the proof-carrying-code
288+
/// framework. If initial facts on program inputs are correct
289+
/// (i.e., correctly denote the shape and types of data structures
290+
/// in memory), and if PCC validates the compiled output, then all
291+
/// `checked`-marked memory accesses are guaranteed (up to the
292+
/// checker's correctness) to access valid memory. This can be
293+
/// used to ensure memory safety and sandboxing.
294+
pub fn checked(self) -> bool {
295+
self.read(FlagBit::Checked)
296+
}
297+
298+
/// Set the `checked` bit.
299+
pub fn set_checked(&mut self) {
300+
self.set(FlagBit::Checked);
301+
}
302+
303+
/// Set the `checked` bit, returning new flags.
304+
pub fn with_checked(mut self) -> Self {
305+
self.set_checked();
306+
self
307+
}
268308
}
269309

270310
impl fmt::Display for MemFlags {

cranelift/codegen/src/ir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub(crate) mod known_symbol;
1818
pub mod layout;
1919
pub(crate) mod libcall;
2020
mod memflags;
21+
pub mod pcc;
2122
mod progpoint;
2223
mod sourceloc;
2324
pub mod stackslot;

0 commit comments

Comments
 (0)