1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Userspace handle to the in-kernel `INODE_MARKS`
//! (`BPF_MAP_TYPE_INODE_STORAGE`) map.
//!
//! The eBPF `file_open` hook writes the `OriginRecord` into `INODE_MARKS`
//! with `creator_path_hash == 0` — it can't cheaply resolve the creator's
//! exe path in-kernel. Userspace later resolves that hash (from
//! `/proc/$pid/exe`) and writes it into the xattr, but historically *not*
//! back into the in-kernel record.
//!
//! That gap matters for two paths:
//! * **direct exec** — `bprm_check_security` falls back to the (more
//! expensive) xattr kfunc whenever the inode-storage record has a zero
//! `creator_path_hash`;
//! * **taint propagation** — a process that reads a marked file inherits
//! the source's record *from `INODE_MARKS`* (same-boot), so a zero
//! creator hash would propagate to every derived file.
//!
//! So after augmenting a record, userspace back-fills it here. Inode storage
//! is keyed from userspace by an **open file descriptor** whose inode the
//! kernel resolves, which is exactly what aya's typed [`InodeStorage`] map
//! exposes.
use AsRawFd;
use ;
use ;
use OriginRecord;
/// Newtype so we can `impl aya::Pod` for the map value without tripping the
/// orphan rule (`OriginRecord` lives in `linprov-common`, which can't see
/// aya). `repr(transparent)` keeps the layout identical to `OriginRecord`,
/// so the kernel value size still matches.
;
unsafe
/// Owns the userspace view of `INODE_MARKS` and back-fills augmented records.