shadow-hdk-linux-sandbox 0.33.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shadow_hdk_linux_sandbox-0.33.0/Cargo.lock +284 -0
- shadow_hdk_linux_sandbox-0.33.0/Cargo.toml +33 -0
- shadow_hdk_linux_sandbox-0.33.0/PKG-INFO +75 -0
- shadow_hdk_linux_sandbox-0.33.0/README.md +58 -0
- shadow_hdk_linux_sandbox-0.33.0/pyproject.toml +32 -0
- shadow_hdk_linux_sandbox-0.33.0/src/args.rs +236 -0
- shadow_hdk_linux_sandbox-0.33.0/src/linux.rs +212 -0
- shadow_hdk_linux_sandbox-0.33.0/src/main.rs +111 -0
- shadow_hdk_linux_sandbox-0.33.0/tests/confines.rs +349 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "bitflags"
|
|
7
|
+
version = "2.13.2"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "cfg-if"
|
|
13
|
+
version = "1.0.5"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "enumflags2"
|
|
19
|
+
version = "0.7.12"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"enumflags2_derive",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "enumflags2_derive"
|
|
28
|
+
version = "0.7.12"
|
|
29
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
30
|
+
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
|
31
|
+
dependencies = [
|
|
32
|
+
"proc-macro2",
|
|
33
|
+
"quote",
|
|
34
|
+
"syn 2.0.119",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[[package]]
|
|
38
|
+
name = "errno"
|
|
39
|
+
version = "0.3.14"
|
|
40
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
41
|
+
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
|
42
|
+
dependencies = [
|
|
43
|
+
"libc",
|
|
44
|
+
"windows-sys",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[[package]]
|
|
48
|
+
name = "fastrand"
|
|
49
|
+
version = "2.5.0"
|
|
50
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
51
|
+
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
|
52
|
+
|
|
53
|
+
[[package]]
|
|
54
|
+
name = "getrandom"
|
|
55
|
+
version = "0.4.3"
|
|
56
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
57
|
+
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
|
58
|
+
dependencies = [
|
|
59
|
+
"cfg-if",
|
|
60
|
+
"libc",
|
|
61
|
+
"r-efi",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[[package]]
|
|
65
|
+
name = "itoa"
|
|
66
|
+
version = "1.0.18"
|
|
67
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
68
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
69
|
+
|
|
70
|
+
[[package]]
|
|
71
|
+
name = "landlock"
|
|
72
|
+
version = "0.4.7"
|
|
73
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
74
|
+
checksum = "4cca98e95f35b29d469dade6724c6f96cec9236640f745a0e99b0334ec320ab1"
|
|
75
|
+
dependencies = [
|
|
76
|
+
"enumflags2",
|
|
77
|
+
"libc",
|
|
78
|
+
"thiserror",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[[package]]
|
|
82
|
+
name = "libc"
|
|
83
|
+
version = "0.2.189"
|
|
84
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
85
|
+
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
|
86
|
+
|
|
87
|
+
[[package]]
|
|
88
|
+
name = "linux-raw-sys"
|
|
89
|
+
version = "0.12.1"
|
|
90
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
91
|
+
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
|
92
|
+
|
|
93
|
+
[[package]]
|
|
94
|
+
name = "memchr"
|
|
95
|
+
version = "2.8.3"
|
|
96
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
97
|
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
98
|
+
|
|
99
|
+
[[package]]
|
|
100
|
+
name = "once_cell"
|
|
101
|
+
version = "1.21.4"
|
|
102
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
103
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
104
|
+
|
|
105
|
+
[[package]]
|
|
106
|
+
name = "proc-macro2"
|
|
107
|
+
version = "1.0.107"
|
|
108
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
109
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
110
|
+
dependencies = [
|
|
111
|
+
"unicode-ident",
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
[[package]]
|
|
115
|
+
name = "quote"
|
|
116
|
+
version = "1.0.47"
|
|
117
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
118
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
119
|
+
dependencies = [
|
|
120
|
+
"proc-macro2",
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
[[package]]
|
|
124
|
+
name = "r-efi"
|
|
125
|
+
version = "6.0.0"
|
|
126
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
127
|
+
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
|
128
|
+
|
|
129
|
+
[[package]]
|
|
130
|
+
name = "rustix"
|
|
131
|
+
version = "1.1.5"
|
|
132
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
133
|
+
checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
|
|
134
|
+
dependencies = [
|
|
135
|
+
"bitflags",
|
|
136
|
+
"errno",
|
|
137
|
+
"libc",
|
|
138
|
+
"linux-raw-sys",
|
|
139
|
+
"windows-sys",
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
[[package]]
|
|
143
|
+
name = "seccompiler"
|
|
144
|
+
version = "0.5.0"
|
|
145
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
146
|
+
checksum = "a4ae55de56877481d112a559bbc12667635fdaf5e005712fd4e2b2fa50ffc884"
|
|
147
|
+
dependencies = [
|
|
148
|
+
"libc",
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
[[package]]
|
|
152
|
+
name = "serde"
|
|
153
|
+
version = "1.0.229"
|
|
154
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
155
|
+
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
|
156
|
+
dependencies = [
|
|
157
|
+
"serde_core",
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
[[package]]
|
|
161
|
+
name = "serde_core"
|
|
162
|
+
version = "1.0.229"
|
|
163
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
164
|
+
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
|
165
|
+
dependencies = [
|
|
166
|
+
"serde_derive",
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
[[package]]
|
|
170
|
+
name = "serde_derive"
|
|
171
|
+
version = "1.0.229"
|
|
172
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
173
|
+
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
174
|
+
dependencies = [
|
|
175
|
+
"proc-macro2",
|
|
176
|
+
"quote",
|
|
177
|
+
"syn 3.0.6",
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
[[package]]
|
|
181
|
+
name = "serde_json"
|
|
182
|
+
version = "1.0.151"
|
|
183
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
184
|
+
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
|
185
|
+
dependencies = [
|
|
186
|
+
"itoa",
|
|
187
|
+
"memchr",
|
|
188
|
+
"serde",
|
|
189
|
+
"serde_core",
|
|
190
|
+
"zmij",
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
[[package]]
|
|
194
|
+
name = "shadow-hdk-sandbox"
|
|
195
|
+
version = "0.33.0"
|
|
196
|
+
dependencies = [
|
|
197
|
+
"landlock",
|
|
198
|
+
"libc",
|
|
199
|
+
"seccompiler",
|
|
200
|
+
"serde_json",
|
|
201
|
+
"tempfile",
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
[[package]]
|
|
205
|
+
name = "syn"
|
|
206
|
+
version = "2.0.119"
|
|
207
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
208
|
+
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
|
209
|
+
dependencies = [
|
|
210
|
+
"proc-macro2",
|
|
211
|
+
"quote",
|
|
212
|
+
"unicode-ident",
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
[[package]]
|
|
216
|
+
name = "syn"
|
|
217
|
+
version = "3.0.6"
|
|
218
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
219
|
+
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
|
220
|
+
dependencies = [
|
|
221
|
+
"proc-macro2",
|
|
222
|
+
"quote",
|
|
223
|
+
"unicode-ident",
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
[[package]]
|
|
227
|
+
name = "tempfile"
|
|
228
|
+
version = "3.27.0"
|
|
229
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
230
|
+
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
|
231
|
+
dependencies = [
|
|
232
|
+
"fastrand",
|
|
233
|
+
"getrandom",
|
|
234
|
+
"once_cell",
|
|
235
|
+
"rustix",
|
|
236
|
+
"windows-sys",
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
[[package]]
|
|
240
|
+
name = "thiserror"
|
|
241
|
+
version = "2.0.20"
|
|
242
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
243
|
+
checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
|
|
244
|
+
dependencies = [
|
|
245
|
+
"thiserror-impl",
|
|
246
|
+
]
|
|
247
|
+
|
|
248
|
+
[[package]]
|
|
249
|
+
name = "thiserror-impl"
|
|
250
|
+
version = "2.0.20"
|
|
251
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
252
|
+
checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
|
|
253
|
+
dependencies = [
|
|
254
|
+
"proc-macro2",
|
|
255
|
+
"quote",
|
|
256
|
+
"syn 3.0.6",
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
[[package]]
|
|
260
|
+
name = "unicode-ident"
|
|
261
|
+
version = "1.0.26"
|
|
262
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
263
|
+
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
|
264
|
+
|
|
265
|
+
[[package]]
|
|
266
|
+
name = "windows-link"
|
|
267
|
+
version = "0.2.1"
|
|
268
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
269
|
+
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
|
270
|
+
|
|
271
|
+
[[package]]
|
|
272
|
+
name = "windows-sys"
|
|
273
|
+
version = "0.61.2"
|
|
274
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
275
|
+
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
|
276
|
+
dependencies = [
|
|
277
|
+
"windows-link",
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
[[package]]
|
|
281
|
+
name = "zmij"
|
|
282
|
+
version = "1.0.23"
|
|
283
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
284
|
+
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# The OS layer's native parts (Epic 0010, D123): one crate, one small static helper per operating
|
|
2
|
+
# system that needs one, invoked by the Python leash exactly as `sandbox-exec` is on macOS. The
|
|
3
|
+
# policy — which mode allows what — the detection and the D36 proof stay in Python; this crate is
|
|
4
|
+
# the syscalls a child has to make on itself before `exec`.
|
|
5
|
+
[package]
|
|
6
|
+
name = "shadow-hdk-sandbox"
|
|
7
|
+
version = "0.33.0"
|
|
8
|
+
edition = "2024"
|
|
9
|
+
rust-version = "1.85"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
description = "Shadow HDK's OS-layer helpers: the Linux sandbox (Landlock + seccomp, applied before exec)"
|
|
12
|
+
repository = "https://github.com/avinash-singh-io/shadow-hdk"
|
|
13
|
+
publish = false
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
|
|
16
|
+
[[bin]]
|
|
17
|
+
name = "shadow-hdk-linux-sandbox"
|
|
18
|
+
path = "src/main.rs"
|
|
19
|
+
|
|
20
|
+
[target.'cfg(target_os = "linux")'.dependencies]
|
|
21
|
+
landlock = "0.4"
|
|
22
|
+
seccompiler = "0.5"
|
|
23
|
+
libc = "0.2"
|
|
24
|
+
|
|
25
|
+
[dev-dependencies]
|
|
26
|
+
serde_json = "1"
|
|
27
|
+
tempfile = "3"
|
|
28
|
+
|
|
29
|
+
[profile.release]
|
|
30
|
+
strip = true
|
|
31
|
+
lto = true
|
|
32
|
+
codegen-units = 1
|
|
33
|
+
panic = "abort"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shadow-hdk-linux-sandbox
|
|
3
|
+
Version: 0.33.0
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
7
|
+
Classifier: Programming Language :: Rust
|
|
8
|
+
Classifier: Topic :: Security
|
|
9
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
10
|
+
Summary: Shadow HDK's Linux confinement helper: Landlock and seccomp applied before exec, invoked by the kit's local environment.
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
Requires-Python: >=3.12
|
|
13
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
14
|
+
Project-URL: Homepage, https://github.com/avinash-singh-io/shadow-hdk
|
|
15
|
+
Project-URL: Repository, https://github.com/avinash-singh-io/shadow-hdk
|
|
16
|
+
|
|
17
|
+
# shadow-hdk-linux-sandbox
|
|
18
|
+
|
|
19
|
+
Shadow HDK's Linux confinement helper — the first executable of the kit's OS layer (Epic 0010,
|
|
20
|
+
D123). `LocalEnvironment` invokes it exactly as it invokes `sandbox-exec` on macOS: the helper
|
|
21
|
+
confines *itself* and `exec`s the command, so there is one process, in the leash's process group,
|
|
22
|
+
exiting with the command's own code.
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
shadow-hdk-linux-sandbox --mode read-only|workspace-write [--root <dir>]... -- <argv>...
|
|
26
|
+
shadow-hdk-linux-sandbox --probe
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## What it applies
|
|
30
|
+
|
|
31
|
+
- **Landlock** (a kernel LSM any unprivileged process may apply to itself; Linux 5.13+, ABI 4 on
|
|
32
|
+
Ubuntu 24.04's 6.8): reads everywhere — the interpreter has to read its own installation;
|
|
33
|
+
writes beneath each `--root` for `workspace-write` and nowhere for `read-only`; the null, zero,
|
|
34
|
+
full, random, urandom, tty, ptmx and pts devices writable in both modes, because devices are not
|
|
35
|
+
files (`git` opens `/dev/null` read-write at startup); TCP `bind` and `connect` handled and
|
|
36
|
+
denied where the kernel has it (ABI 4+).
|
|
37
|
+
- **seccomp**: `socket()` with any domain but `AF_UNIX` fails with `EPERM`, and so does
|
|
38
|
+
`io_uring_setup` — io_uring can open and connect sockets without a `socket` syscall, so a filter
|
|
39
|
+
that stopped at `socket` would stop nothing. Every other syscall is allowed; the filesystem is
|
|
40
|
+
Landlock's.
|
|
41
|
+
|
|
42
|
+
No namespaces, no root, no daemon — which is what survives Ubuntu 24.04's default AppArmor policy,
|
|
43
|
+
where bubblewrap's unprivileged user namespace does not. Bubblewrap stays behind it as the
|
|
44
|
+
fallback on a kernel without Landlock; the kit's D36 proof decides which is in force by watching
|
|
45
|
+
a write outside denied, a socket refused and a write inside land, before any confined mode opens.
|
|
46
|
+
Nothing here is trusted for having run.
|
|
47
|
+
|
|
48
|
+
## Exit codes
|
|
49
|
+
|
|
50
|
+
| code | meaning |
|
|
51
|
+
|---|---|
|
|
52
|
+
| the command's | after `exec`, the helper *is* the command |
|
|
53
|
+
| **120** | cannot confine — no Landlock (absent or `lsm=` without it), a ruleset the kernel did not enforce, seccomp refused; stderr says why |
|
|
54
|
+
| **121** | usage — the arguments above are the contract; `full` never reaches the helper |
|
|
55
|
+
| **126** / **127** | the command could not be executed / was not found |
|
|
56
|
+
|
|
57
|
+
`--probe` prints one JSON line — `{"version": "…", "landlock_abi": N, "supported": true|false}` —
|
|
58
|
+
and exits 0 or 120.
|
|
59
|
+
|
|
60
|
+
## Building
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
cargo build --release
|
|
64
|
+
cargo test # the argument tests everywhere; the confinement tests on a Linux kernel
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Packaged for PyPI by maturin (`bindings = "bin"`): one `py3-none-<platform>` wheel per OS × arch,
|
|
68
|
+
no Python-version coupling. `shadow-hdk` depends on it where `sys_platform == 'linux'`. Off Linux
|
|
69
|
+
the binary builds and refuses with 120 — so the crate lints, unit-tests and packages on any
|
|
70
|
+
developer machine.
|
|
71
|
+
|
|
72
|
+
Environment variables the *kit* reads (not the helper): `SHADOW_HDK_LINUX_SANDBOX` names the
|
|
73
|
+
helper's path when it is not beside the interpreter or on `PATH`; `SHADOW_HDK_SANDBOX` narrows the
|
|
74
|
+
kit's candidates to one mechanism (`landlock`, `bubblewrap`, `seatbelt`).
|
|
75
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# shadow-hdk-linux-sandbox
|
|
2
|
+
|
|
3
|
+
Shadow HDK's Linux confinement helper — the first executable of the kit's OS layer (Epic 0010,
|
|
4
|
+
D123). `LocalEnvironment` invokes it exactly as it invokes `sandbox-exec` on macOS: the helper
|
|
5
|
+
confines *itself* and `exec`s the command, so there is one process, in the leash's process group,
|
|
6
|
+
exiting with the command's own code.
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
shadow-hdk-linux-sandbox --mode read-only|workspace-write [--root <dir>]... -- <argv>...
|
|
10
|
+
shadow-hdk-linux-sandbox --probe
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## What it applies
|
|
14
|
+
|
|
15
|
+
- **Landlock** (a kernel LSM any unprivileged process may apply to itself; Linux 5.13+, ABI 4 on
|
|
16
|
+
Ubuntu 24.04's 6.8): reads everywhere — the interpreter has to read its own installation;
|
|
17
|
+
writes beneath each `--root` for `workspace-write` and nowhere for `read-only`; the null, zero,
|
|
18
|
+
full, random, urandom, tty, ptmx and pts devices writable in both modes, because devices are not
|
|
19
|
+
files (`git` opens `/dev/null` read-write at startup); TCP `bind` and `connect` handled and
|
|
20
|
+
denied where the kernel has it (ABI 4+).
|
|
21
|
+
- **seccomp**: `socket()` with any domain but `AF_UNIX` fails with `EPERM`, and so does
|
|
22
|
+
`io_uring_setup` — io_uring can open and connect sockets without a `socket` syscall, so a filter
|
|
23
|
+
that stopped at `socket` would stop nothing. Every other syscall is allowed; the filesystem is
|
|
24
|
+
Landlock's.
|
|
25
|
+
|
|
26
|
+
No namespaces, no root, no daemon — which is what survives Ubuntu 24.04's default AppArmor policy,
|
|
27
|
+
where bubblewrap's unprivileged user namespace does not. Bubblewrap stays behind it as the
|
|
28
|
+
fallback on a kernel without Landlock; the kit's D36 proof decides which is in force by watching
|
|
29
|
+
a write outside denied, a socket refused and a write inside land, before any confined mode opens.
|
|
30
|
+
Nothing here is trusted for having run.
|
|
31
|
+
|
|
32
|
+
## Exit codes
|
|
33
|
+
|
|
34
|
+
| code | meaning |
|
|
35
|
+
|---|---|
|
|
36
|
+
| the command's | after `exec`, the helper *is* the command |
|
|
37
|
+
| **120** | cannot confine — no Landlock (absent or `lsm=` without it), a ruleset the kernel did not enforce, seccomp refused; stderr says why |
|
|
38
|
+
| **121** | usage — the arguments above are the contract; `full` never reaches the helper |
|
|
39
|
+
| **126** / **127** | the command could not be executed / was not found |
|
|
40
|
+
|
|
41
|
+
`--probe` prints one JSON line — `{"version": "…", "landlock_abi": N, "supported": true|false}` —
|
|
42
|
+
and exits 0 or 120.
|
|
43
|
+
|
|
44
|
+
## Building
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
cargo build --release
|
|
48
|
+
cargo test # the argument tests everywhere; the confinement tests on a Linux kernel
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Packaged for PyPI by maturin (`bindings = "bin"`): one `py3-none-<platform>` wheel per OS × arch,
|
|
52
|
+
no Python-version coupling. `shadow-hdk` depends on it where `sys_platform == 'linux'`. Off Linux
|
|
53
|
+
the binary builds and refuses with 120 — so the crate lints, unit-tests and packages on any
|
|
54
|
+
developer machine.
|
|
55
|
+
|
|
56
|
+
Environment variables the *kit* reads (not the helper): `SHADOW_HDK_LINUX_SANDBOX` names the
|
|
57
|
+
helper's path when it is not beside the interpreter or on `PATH`; `SHADOW_HDK_SANDBOX` narrows the
|
|
58
|
+
kit's candidates to one mechanism (`landlock`, `bubblewrap`, `seatbelt`).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# The Linux helper as a distribution (Epic 0010, D123 as amended 2026-09-19): maturin packages the
|
|
2
|
+
# `shadow-hdk-linux-sandbox` binary alone — `bindings = "bin"`, no Python module, no Python ABI —
|
|
3
|
+
# so there is one `py3-none-<platform>` wheel per OS × arch and never one per Python version.
|
|
4
|
+
# `shadow-hdk` depends on it under a Linux marker; the version moves with the kit's
|
|
5
|
+
# (`tests/test_versions.py`).
|
|
6
|
+
[build-system]
|
|
7
|
+
requires = ["maturin>=1.7,<2"]
|
|
8
|
+
build-backend = "maturin"
|
|
9
|
+
|
|
10
|
+
[project]
|
|
11
|
+
name = "shadow-hdk-linux-sandbox"
|
|
12
|
+
version = "0.33.0"
|
|
13
|
+
description = "Shadow HDK's Linux confinement helper: Landlock and seccomp applied before exec, invoked by the kit's local environment."
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
requires-python = ">=3.12"
|
|
16
|
+
license = "MIT"
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
"Programming Language :: Rust",
|
|
22
|
+
"Topic :: Security",
|
|
23
|
+
"Topic :: Software Development :: Libraries",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/avinash-singh-io/shadow-hdk"
|
|
28
|
+
Repository = "https://github.com/avinash-singh-io/shadow-hdk"
|
|
29
|
+
|
|
30
|
+
[tool.maturin]
|
|
31
|
+
bindings = "bin"
|
|
32
|
+
strip = true
|