API reference
Rulesets
landlockpy.Ruleset
A Landlock ruleset under construction.
A ruleset declares which access rights it handles. Handled rights are denied by default once the ruleset is enforced. The allow_path() and allow_port() methods grant back specific rights for specific objects:
with Ruleset() as ruleset:
ruleset.allow_path("/usr", AccessFS.READ_FILE | AccessFS.READ_DIR)
ruleset.allow_port(443, AccessNet.CONNECT_TCP)
ruleset.restrict()
Rights the running kernel does not support are dropped in best-effort mode (the default), or rejected with UnsupportedError when best_effort is False.
The ruleset owns a kernel file descriptor. Use it as a context manager or call close() to release it.
Kernel reference: https://docs.kernel.org/userspace-api/landlock.html
Source code in src/landlockpy/ruleset.py
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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | |
abi_version
property
Landlock ABI version of the running kernel.
handled_fs
property
Filesystem rights this ruleset denies by default.
handled_net
property
Network rights this ruleset denies by default.
scoped
property
Scope isolation flags applied to the domain.
enforced
property
Whether restrict() has been called successfully.
closed
property
Whether the ruleset file descriptor has been closed.
fileno()
Return the underlying ruleset file descriptor.
Source code in src/landlockpy/ruleset.py
178 179 180 181 182 | |
allow_path(path, access, *, quiet=False)
Grant filesystem access rights on a file hierarchy.
The path can point to a file or a directory. A directory rule covers its whole hierarchy. Access is masked against the handled filesystem rights. Returns the rights actually granted, which is empty if none of the requested rights are handled and no rule was added.
quiet marks the rule with LANDLOCK_ADD_RULE_QUIET, suppressing audit logs for accesses the ruleset declared quiet. Quiet requires ABI 10. On older kernels it is dropped in best-effort mode or rejected with UnsupportedError in strict mode. See "Extending a ruleset" in the kernel documentation.
Source code in src/landlockpy/ruleset.py
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | |
allow_port(port, access, *, quiet=False)
Grant network access rights on a TCP or UDP port.
Port 0 covers the ephemeral port range used by auto-bound sockets. Access is masked against the handled network rights. Returns the rights actually granted, which is empty if none of the requested rights are handled and no rule was added.
A LandlockError with errno EAFNOSUPPORT means the kernel lacks TCP/IP support. The operation is impossible anyway and the error can safely be ignored. See "Extending a ruleset" in the kernel documentation.
Source code in src/landlockpy/ruleset.py
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | |
restrict(flags=RestrictFlag.NONE, *, no_new_privs=True)
Enforce the ruleset on the calling thread and its future children.
Flags unsupported by the running kernel are dropped in best-effort mode, or rejected with UnsupportedError when best_effort is False. With no_new_privs, the thread is also prevented from gaining privileges through suid or file-capability binaries. On ABI 11 and newer this is set atomically with enforcement. On older kernels a prctl(PR_SET_NO_NEW_PRIVS) call is made first.
Enforcement is irreversible and per-thread. Without the TSYNC flag (ABI 8), only the calling thread and its future children are restricted. Sibling threads keep their own policy. See "Enforcing a ruleset" in the kernel documentation.
Source code in src/landlockpy/ruleset.py
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
close()
Close the ruleset file descriptor. Safe to call twice.
Source code in src/landlockpy/ruleset.py
284 285 286 287 288 | |
landlockpy.mute_subdomain_logs(*, all_threads=False, no_new_privs=True)
Suppress audit logging for Landlock domains nested under this one.
Calls landlock_restrict_self with a ruleset file descriptor of -1, which updates the logging configuration without creating a new domain. Denied accesses originating from nested domains created afterwards by the caller or its descendants are not logged. Requires ABI 7.
With all_threads, the configuration is propagated to every thread of the current process, which requires ABI 8.
Like restrict(), the kernel requires the calling thread to already run with no_new_privs or hold CAP_SYS_ADMIN. With no_new_privs=True the attribute is set via prctl(PR_SET_NO_NEW_PRIVS) first. The LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS flag cannot be combined with a ruleset file descriptor of -1, so prctl is used on every ABI. See "Logging" and "Enforcing a ruleset" in the kernel documentation.
Source code in src/landlockpy/ruleset.py
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | |
Access rights and flags
landlockpy.AccessFS
Bases: IntFlag
Filesystem access rights, mirroring LANDLOCK_ACCESS_FS_*.
Used in the handled_access_fs field of a ruleset and in the allowed_access field of path rules. See "Filesystem flags" in the kernel documentation.
Source code in src/landlockpy/flags.py
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 | |
landlockpy.AccessNet
Bases: IntFlag
Network access rights, mirroring LANDLOCK_ACCESS_NET_*.
Used in the handled_access_net field of a ruleset and in the allowed_access field of port rules. See "Network flags" in the kernel documentation.
Source code in src/landlockpy/flags.py
58 59 60 61 62 63 64 65 66 67 68 69 70 | |
landlockpy.Scope
Bases: IntFlag
Scope flags, mirroring LANDLOCK_SCOPE_*.
Set on a ruleset to isolate the domain from resources outside it, such as abstract UNIX sockets or signals. See "Scope flags" in the kernel documentation.
Source code in src/landlockpy/flags.py
73 74 75 76 77 78 79 80 81 82 83 | |
landlockpy.RestrictFlag
Bases: IntFlag
Flags accepted by landlock_restrict_self, mirroring LANDLOCK_RESTRICT_SELF_*. See "Enforcing a ruleset" in the kernel documentation.
Source code in src/landlockpy/flags.py
86 87 88 89 90 91 92 93 94 95 96 97 | |
Kernel probes
landlockpy.supported()
Return whether the running kernel supports Landlock.
Source code in src/landlockpy/__init__.py
82 83 84 | |
landlockpy.abi_version()
Return the Landlock ABI version of the running kernel, or 0.
A return value of 0 means Landlock is unavailable: the platform is not Linux, the kernel is too old (ENOSYS), or Landlock is disabled at boot time (EOPNOTSUPP).
Source code in src/landlockpy/__init__.py
52 53 54 55 56 57 58 59 60 61 62 63 64 | |
landlockpy.errata()
Return the errata bitmask for the current ABI version, or 0.
Bit N set means erratum N is fixed in the running kernel. Older kernels without the errata mechanism report 0. Most applications should not check errata. Best-effort enforcement is the safer default.
Source code in src/landlockpy/__init__.py
67 68 69 70 71 72 73 74 75 76 77 78 79 | |
ABI helpers
landlockpy.fs_for_abi(abi)
Return the filesystem rights supported by the given ABI version.
Source code in src/landlockpy/flags.py
151 152 153 | |
landlockpy.net_for_abi(abi)
Return the network rights supported by the given ABI version.
Source code in src/landlockpy/flags.py
156 157 158 | |
landlockpy.scope_for_abi(abi)
Return the scope flags supported by the given ABI version.
Source code in src/landlockpy/flags.py
161 162 163 | |
landlockpy.restrict_for_abi(abi)
Return the restrict flags supported by the given ABI version.
Source code in src/landlockpy/flags.py
166 167 168 | |
Errors
landlockpy.LandlockError
Bases: OSError
A Landlock syscall failed.
Source code in src/landlockpy/errors.py
5 6 | |
landlockpy.UnsupportedError
Bases: LandlockError
The running kernel does not support Landlock or the requested feature.
Source code in src/landlockpy/errors.py
9 10 | |
Testing helpers
landlockpy.testing.probe(ruleset, fn)
Run fn in a forked child process restricted by ruleset.
The ruleset must be unenforced. It is enforced in the child only, so the caller's copy stays usable. The return value of fn is discarded. The child exits with os._exit, so atexit handlers, buffered I/O and threads do not run there.
Source code in src/landlockpy/testing.py
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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
landlockpy.testing.probe_path(ruleset, path)
Probe whether the ruleset allows reading the file at path.
Convenience wrapper around probe() for the common case of checking whether a path remains readable under a policy.
Source code in src/landlockpy/testing.py
104 105 106 107 108 109 110 | |
landlockpy.testing.ProbeResult
dataclass
Outcome of a probe() run.
ok is True when fn completed under the ruleset. When fn or the enforcement raised an OSError, errno holds its errno value such as EACCES or EPERM. For failures that are not OSError, errno is 0 and exception holds a "ClassName: message" string from the child. signal is nonzero if the child was killed by a signal instead of exiting normally.
Source code in src/landlockpy/testing.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |