Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skeleton and initial support for proof-carrying code. #7165

Merged
merged 13 commits into from
Oct 6, 2023
9 changes: 9 additions & 0 deletions cranelift/codegen/meta/src/shared/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ pub(crate) fn define() -> SettingGroup {
true,
);

settings.add_bool(
"enable_pcc",
"Enable proof-carrying code translation validation.",
r#"
This adds a proof-carrying code mode. TODO ADD MORE
"#,
false,
);

// Note that Cranelift doesn't currently need an is_pie flag, because PIE is
// just PIC where symbols can't be pre-empted, which can be expressed with the
// `colocated` flag on external functions and global values.
Expand Down
2 changes: 2 additions & 0 deletions cranelift/codegen/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ impl Context {
/// Run the verifier on the function.
///
/// Also check that the dominator tree and control flow graph are consistent with the function.
///
/// TODO: rename to "CLIF validate" or similar.
pub fn verify<'a, FOI: Into<FlagsOrIsa<'a>>>(&self, fisa: FOI) -> VerifierResult<()> {
let mut errors = VerifierErrors::default();
let _ = verify_context(&self.func, &self.cfg, &self.domtree, fisa, &mut errors);
Expand Down
5 changes: 5 additions & 0 deletions cranelift/codegen/src/ir/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::ir;
use crate::ir::builder::ReplaceBuilder;
use crate::ir::dynamic_type::{DynamicTypeData, DynamicTypes};
use crate::ir::instructions::{CallInfo, InstructionData};
use crate::ir::pcc::Fact;
use crate::ir::{
types, Block, BlockCall, ConstantData, ConstantPool, DynamicType, ExtFuncData, FuncRef,
Immediate, Inst, JumpTables, RelSourceLoc, SigRef, Signature, Type, Value,
Expand Down Expand Up @@ -125,6 +126,9 @@ pub struct DataFlowGraph {
/// Primary value table with entries for all values.
values: PrimaryMap<Value, ValueDataPacked>,

/// Facts: proof-carrying-code assertions about values.
pub facts: SecondaryMap<Value, Option<Fact>>,

/// Function signature table. These signatures are referenced by indirect call instructions as
/// well as the external function references.
pub signatures: PrimaryMap<SigRef, Signature>,
Expand Down Expand Up @@ -158,6 +162,7 @@ impl DataFlowGraph {
dynamic_types: DynamicTypes::new(),
value_lists: ValueListPool::new(),
values: PrimaryMap::new(),
facts: SecondaryMap::new(),
signatures: PrimaryMap::new(),
old_signatures: SecondaryMap::new(),
ext_funcs: PrimaryMap::new(),
Expand Down
46 changes: 43 additions & 3 deletions cranelift/codegen/src/ir/memflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ use core::fmt;
use serde_derive::{Deserialize, Serialize};

enum FlagBit {
/// Guaranteed not to trap. This may enable additional
/// optimizations to be performed.
Notrap,
/// Guaranteed to use "natural alignment" for the given type. This
/// may enable better instruction selection.
Aligned,
/// A load that reads data in memory that does not change for the
/// duration of the function's execution. This may enable
/// additional optimizations to be performed.
Readonly,
/// Load multi-byte values from memory in a little-endian format.
LittleEndian,
/// Load multi-byte values from memory in a big-endian format.
BigEndian,
/// Accesses only the "heap" part of abstract state. Used for
/// alias analysis. Mutually exclusive with "table" and "vmctx".
Expand All @@ -20,10 +29,15 @@ enum FlagBit {
/// Accesses only the "vmctx" part of abstract state. Used for
/// alias analysis. Mutually exclusive with "heap" and "table".
Vmctx,
/// Check this load or store for safety when using the
/// proof-carrying-code framework. The address must have a
/// `PointsTo` fact attached with a sufficiently large valid range
/// for the accessed size.
Safe,
cfallin marked this conversation as resolved.
Show resolved Hide resolved
}

const NAMES: [&str; 8] = [
"notrap", "aligned", "readonly", "little", "big", "heap", "table", "vmctx",
const NAMES: [&str; 9] = [
"notrap", "aligned", "readonly", "little", "big", "heap", "table", "vmctx", "safe",
];

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

impl MemFlags {
Expand Down Expand Up @@ -265,6 +279,32 @@ impl MemFlags {
self.set_vmctx();
self
}

/// Test if the `safe` bit is set.
///
/// Loads and stores with this flag are verified to access
/// pointers only with a validated `PointsTo` fact attached, and
/// with that fact validated, when using the proof-carrying-code
/// framework. If initial facts on program inputs are correct
/// (i.e., correctly denote the shape and types of data structures
/// in memory), and if PCC validates the compiled output, then all
/// `safe`-marked memory accesses are guaranteed (up to the
/// checker's correctness) to access valid memory. This can be
/// used to ensure memory safety and sandboxing.
pub fn safe(self) -> bool {
self.read(FlagBit::Safe)
}

/// Set the `safe` bit.
pub fn set_safe(&mut self) {
self.set(FlagBit::Safe);
}

/// Set the `safe` bit, returning new flags.
pub fn with_safe(mut self) -> Self {
self.set_safe();
self
}
}

impl fmt::Display for MemFlags {
Expand Down
1 change: 1 addition & 0 deletions cranelift/codegen/src/ir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub(crate) mod known_symbol;
pub mod layout;
pub(crate) mod libcall;
mod memflags;
pub mod pcc;
mod progpoint;
mod sourceloc;
pub mod stackslot;
Expand Down
Loading