Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

crates/mimir-room/tests/room/boundary.rs

//! The system boundary in the room: a consumed repo whose code reaches std,
//! std reaching libc's `ffi` items, the boundary written once
//! (`mimir_ingest::boundary::ensure`: table, maps, a generated kernel BTF) —
//! and the ring-on room answers who reaches which system call, by class,
//! with the path, down to the kernel function the call enters.
//!
//! ```text
//! own  k files → std fsread → std open_c → libc open64 (ffi)   ⇒ openat (file)
//!      k net   → std connect ──────────────→ libc connect (ffi) ⇒ connect (network)
//!      k pure  → std add                                        ⇒ nothing
//!      std statx (named like the call) → libc syscall (the raw door)
//! ```

use mimir_ingest::boundary::{self, KernelSource, Target};
use mimir_room::{MaskSpec, Room, Scope};
use mimir_schema::{EdgeKind, Origin, kind as nk, moniker};

use super::common::*;

const REPO: &str = "bound";

fn libc_ffi(name: &str) -> mimir_schema::NodeRow {
    let mut n = node(&format!("libc {name}"), nk::FFI, "libc", Origin::Library, true);
    n.link_name = Some(name.to_string());
    n
}

fn libc_syscall_id() -> String {
    // the raw door is recognised by its moniker (`libc … syscall().`)
    "rust-analyzer cargo libc 0.2.0 unix/linux_like/linux/syscall().".to_string()
}

fn steps() -> Vec<Step> {
    use EdgeKind::*;
    let own = vec![
        node("k", "crate", "k", Origin::Local, true),
        k("files", "fn"),
        k("net", "fn"),
        k("pure", "fn"),
        node("std", "crate", "std", Origin::Lang, false),
        node("std fsread", "fn", "std", Origin::Lang, false),
        node("std connect", "fn", "std", Origin::Lang, false),
        node("std add", "fn", "std", Origin::Lang, false),
    ];
    let own_edges = vec![
        edge("k", "std", DependsOn),
        edge("k files", "std fsread", Calls),
        edge("k net", "std connect", Calls),
        edge("k pure", "std add", Calls),
    ];
    let mut raw = node(&libc_syscall_id(), nk::FFI, "libc", Origin::Library, true);
    raw.link_name = Some("syscall".into());
    let std_ring = (
        "std@lang:lib",
        vec![
            node("std", "crate", "std", Origin::Lang, true),
            node("std fsread", "fn", "std", Origin::Lang, true),
            node("std open_c", "fn", "std", Origin::Lang, true),
            node("std connect", "fn", "std", Origin::Lang, true),
            node("std add", "fn", "std", Origin::Lang, true),
            node("std statx", "fn", "std", Origin::Lang, true),
            node("libc", "crate", "libc", Origin::Library, false),
        ],
        vec![
            edge("std", "libc", DependsOn),
            edge("std fsread", "std open_c", Calls),
            edge("std open_c", "libc open64", Calls),
            edge("std connect", "libc connect", Calls),
            edge("std statx", &libc_syscall_id(), Calls),
        ],
    );
    let libc_ring = ("libc@0.2.0:lib", vec![node("libc", "crate", "libc", Origin::Library, true), libc_ffi("open64"), libc_ffi("connect"), libc_ffi("strlen"), raw], vec![]);
    vec![Step { owner: "k@0.1.0:lib", nodes: own, edges: own_edges, binary: None, ring: vec![std_ring, libc_ring] }]
}

fn sc(n: &str) -> String {
    moniker::syscall("x86_64", n)
}

#[tokio::test(flavor = "current_thread")]
async fn the_room_walks_own_code_down_to_the_system_call_and_the_kernel() {
    let _g = serial().await;
    let tmp = tempfile::tempdir().unwrap();
    let log = consume(open_log(tmp.path()).await, tmp.path(), REPO, steps()).await;
    let btf = tmp.path().join("vmlinux.btf");
    std::fs::write(&btf, mimir_ingest::boundary::btf::sample_kernel()).unwrap();
    let kernel = KernelSource { path: btf, release: "6.99.0-test".into(), chosen: "configured" };
    let target = Target::parse("x86_64-unknown-linux-gnu").unwrap();

    let w = log.writer().unwrap();
    let first = boundary::ensure(&w, &target, "nightly-fixture", Some(&kernel)).await.unwrap();
    eprintln!("{}", first.line());
    assert!(first.table_written.is_some());
    assert!(first.kernel.as_ref().is_some_and(|k| k.written && k.entries_linked == 3), "{:?}", first.kernel);
    assert_eq!(first.map.owners_with_edges, 2, "std (statx → the raw door) and libc: {:?}", first.map);
    // ONCE: a second ensure writes nothing
    let again = boundary::ensure(&w, &target, "nightly-fixture", Some(&kernel)).await.unwrap();
    assert!(again.table_written.is_none() && again.maps_written == 0 && !again.kernel.as_ref().unwrap().written, "{}", again.line());
    drop(w);

    let room = Room::at(&log, &Scope::current().with_universe(true)).await.unwrap();
    let o = |id: &str| room.ordinal(id).unwrap_or_else(|| panic!("{id} not in the room"));
    let walk = [EdgeKind::Calls, EdgeKind::Syscalls];

    // file: k files → … → libc open64 ⇒ openat
    let p = room.path(&[o("k files")][..], &[o(&sc("openat"))][..], &walk, None, None).unwrap().value.expect("a path to openat");
    assert_eq!(room.monikers(&p.nodes), vec!["k files", "std fsread", "std open_c", "libc open64", sc("openat").as_str()]);
    assert_eq!(p.kinds.last(), Some(&EdgeKind::Syscalls));
    assert_eq!(room.node(o(&sc("openat"))).ty, Some("file"));

    // network: k net ⇒ connect, and connect enters the kernel at __x64_sys_connect
    let reached = room.reach(&[o("k net")][..], &walk, None, None).unwrap().value.reached;
    let calls: Vec<&str> = reached.iter().filter(|r| room.node(**r).kind == Some(nk::SYSCALL)).map(|r| room.node(*r).name.unwrap()).collect();
    assert_eq!(calls, vec!["connect"]);
    assert_eq!(room.node(o(&sc("connect"))).ty, Some("network"));
    let entry = moniker::kernel_item("6.99.0-test", "func", "__x64_sys_connect", None);
    let into_kernel = room.path(&[o("k net")][..], &[o(&entry)][..], &walk, None, None).unwrap().value.expect("into the kernel");
    assert_eq!(room.moniker(*into_kernel.nodes.last().unwrap()), entry);
    // the kernel's types came with it
    assert!(room.ordinal(&moniker::kernel_item("6.99.0-test", "struct", "task_struct", None)).is_some());

    // pure: reaches no system call
    let pure = room.reach(&[o("k pure")][..], &walk, None, None).unwrap().value.reached;
    assert!(pure.iter().all(|r| room.node(*r).kind != Some(nk::SYSCALL)), "{:?}", room.monikers(&pure));

    // the raw door: std's statx-named fn → statx (uncertain), libc syscall → <indirect>
    assert!(room.path(&[o("std statx")][..], &[o(&sc("statx"))][..], &[EdgeKind::Syscalls], Some(1), None).unwrap().value.is_some());
    assert!(room.path(&[o(&libc_syscall_id())][..], &[o(&sc(boundary::INDIRECT))][..], &[EdgeKind::Syscalls], Some(1), None).unwrap().value.is_some());

    // who reaches the network, walked BACK from every network call
    let net = room.mask(&MaskSpec { node_kinds: vec![nk::SYSCALL.into()], ..Default::default() }).unwrap().value;
    let net: Vec<u64> = net.ordinals().iter().copied().filter(|x| room.node(*x).ty == Some("network")).collect();
    let back = room.dependents_by(&net[..], &walk, None, None).unwrap().value.reached;
    let own: Vec<&str> = back.iter().filter(|r| room.node(**r).origin == Some(Origin::Local)).map(|r| room.moniker(*r)).collect();
    assert_eq!(own, vec!["k net"]);

    // ring off: the boundary is not in the room of the own code
    let off = Room::at(&log, &Scope::current()).await.unwrap();
    assert!(off.ordinal(&sc("openat")).is_none());
}

/// What a reader of the ring room needs to carry an answer across a room
/// advance: the universe's identity (`universe_key`, equal while the ring
/// rows are), the nodes local edge rows leave (`local_out`: the only out-edges
/// a consume moves), and the out-edges of a FEW nodes without listing the
/// whole kind (`edges` with a sparse `from` = the row filter of the full list).
#[tokio::test(flavor = "current_thread")]
async fn the_ring_room_names_its_universe_and_its_local_edge_sources() {
    let _g = serial().await;
    let tmp = tempfile::tempdir().unwrap();
    let log = consume(open_log(tmp.path()).await, tmp.path(), REPO, steps()).await;
    let target = Target::parse("x86_64-unknown-linux-gnu").unwrap();
    let w = log.writer().unwrap();
    boundary::ensure(&w, &target, "nightly-fixture", None).await.unwrap();
    drop(w);
    let room = Room::at(&log, &Scope::current().with_universe(true)).await.unwrap();
    let o = |id: &str| room.ordinal(id).unwrap_or_else(|| panic!("{id} not in the room"));
    let key = room.universe_key().expect("ring on: the universe has a key");
    let off = Room::at(&log, &Scope::current()).await.unwrap();
    assert_eq!(off.universe_key(), None, "ring off: no universe");
    let local: Vec<&str> = room.local_out().iter().map(|x| room.moniker(*x)).collect();
    for m in ["k", "k files", "k net", "k pure"] {
        assert!(local.contains(&m), "{m} leaves a local edge row: {local:?}");
    }
    for m in ["std fsread", "std open_c", "std connect"] {
        assert!(!local.contains(&m), "{m}'s edges are the ring's: {local:?}");
    }
    // a sparse `from` takes the rows only — the same edges as the filter
    let all = room.edges(&mimir_room::EdgeSel::kinds(&[EdgeKind::Calls])).unwrap().value.edges;
    for seeds in [vec![o("k files")], vec![o("k net"), o("std open_c")], vec![]] {
        let m = room.mask_of(&seeds);
        let some = room.edges(&mimir_room::EdgeSel { from: Some(&m), ..mimir_room::EdgeSel::kinds(&[EdgeKind::Calls]) }).unwrap().value.edges;
        let want: Vec<_> = all.iter().copied().filter(|e| seeds.contains(&e.from)).collect();
        assert_eq!(some, want, "{seeds:?}");
        let pairs = room.out_pairs(EdgeKind::Calls, &m.ordinals().to_vec()).unwrap();
        assert_eq!(pairs, want.iter().map(|e| (e.from, e.to)).collect::<Vec<_>>());
    }
    assert!(all.len() * 8 > 0 && room.len() > 8 * 2, "the room is large enough for the row path");
    // the same lake state, opened again: the same universe
    let again = Room::at(&log, &Scope::current().with_universe(true)).await.unwrap();
    assert_eq!(again.universe_key(), Some(key));
    // a ring write (the kernel's rows) moves the manifest: another universe
    let btf = tmp.path().join("vmlinux.btf");
    std::fs::write(&btf, mimir_ingest::boundary::btf::sample_kernel()).unwrap();
    let kernel = KernelSource { path: btf, release: "6.99.0-test".into(), chosen: "configured" };
    let w = log.writer().unwrap();
    boundary::ensure(&w, &target, "nightly-fixture", Some(&kernel)).await.unwrap();
    drop(w);
    Room::clear_cache();
    let moved = Room::at(&log, &Scope::current().with_universe(true)).await.unwrap();
    assert_ne!(moved.universe_key(), Some(key), "the ring rows moved: the universe key moves with them");
}