landlockpy 0.1.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.
- landlockpy-0.1.0/.github/dependabot.yml +16 -0
- landlockpy-0.1.0/.github/workflows/ci.yml +58 -0
- landlockpy-0.1.0/.github/workflows/codeql.yml +35 -0
- landlockpy-0.1.0/.github/workflows/dependency-review.yml +22 -0
- landlockpy-0.1.0/.github/workflows/release.yml +63 -0
- landlockpy-0.1.0/.github/workflows/scorecard.yml +41 -0
- landlockpy-0.1.0/.github/workflows/zizmor.yml +28 -0
- landlockpy-0.1.0/.gitignore +9 -0
- landlockpy-0.1.0/CHANGELOG.md +15 -0
- landlockpy-0.1.0/LICENSE +12 -0
- landlockpy-0.1.0/Makefile +15 -0
- landlockpy-0.1.0/PKG-INFO +65 -0
- landlockpy-0.1.0/README.md +43 -0
- landlockpy-0.1.0/SECURITY.md +6 -0
- landlockpy-0.1.0/pyproject.toml +64 -0
- landlockpy-0.1.0/src/landlockpy/__init__.py +81 -0
- landlockpy-0.1.0/src/landlockpy/_syscall.py +124 -0
- landlockpy-0.1.0/src/landlockpy/errors.py +10 -0
- landlockpy-0.1.0/src/landlockpy/flags.py +168 -0
- landlockpy-0.1.0/src/landlockpy/py.typed +0 -0
- landlockpy-0.1.0/src/landlockpy/ruleset.py +265 -0
- landlockpy-0.1.0/tests/__init__.py +0 -0
- landlockpy-0.1.0/tests/_sandbox.py +155 -0
- landlockpy-0.1.0/tests/conftest.py +37 -0
- landlockpy-0.1.0/tests/test_api.py +56 -0
- landlockpy-0.1.0/tests/test_enforced.py +60 -0
- landlockpy-0.1.0/tests/test_flags.py +119 -0
- landlockpy-0.1.0/tests/test_ruleset.py +214 -0
- landlockpy-0.1.0/tests/test_structs.py +41 -0
- landlockpy-0.1.0/uv.lock +611 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: github-actions
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
cooldown:
|
|
8
|
+
default-days: 7
|
|
9
|
+
open-pull-requests-limit: 5
|
|
10
|
+
- package-ecosystem: uv
|
|
11
|
+
directory: /
|
|
12
|
+
schedule:
|
|
13
|
+
interval: weekly
|
|
14
|
+
cooldown:
|
|
15
|
+
default-days: 7
|
|
16
|
+
open-pull-requests-limit: 5
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "9 7 * * 1"
|
|
9
|
+
|
|
10
|
+
permissions: {}
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
17
|
+
with:
|
|
18
|
+
egress-policy: audit
|
|
19
|
+
|
|
20
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
|
|
24
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
25
|
+
with:
|
|
26
|
+
version: "0.11.32"
|
|
27
|
+
enable-cache: true
|
|
28
|
+
|
|
29
|
+
- run: uv sync --locked
|
|
30
|
+
|
|
31
|
+
- run: uv run ruff check .
|
|
32
|
+
- run: uv run ruff format --check .
|
|
33
|
+
- run: uv run bandit -r src/
|
|
34
|
+
- run: uv run mypy
|
|
35
|
+
|
|
36
|
+
test:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
strategy:
|
|
39
|
+
fail-fast: false
|
|
40
|
+
matrix:
|
|
41
|
+
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
42
|
+
steps:
|
|
43
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
44
|
+
with:
|
|
45
|
+
egress-policy: audit
|
|
46
|
+
|
|
47
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
48
|
+
with:
|
|
49
|
+
persist-credentials: false
|
|
50
|
+
|
|
51
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
52
|
+
with:
|
|
53
|
+
version: "0.11.32"
|
|
54
|
+
enable-cache: true
|
|
55
|
+
|
|
56
|
+
- run: uv python install ${{ matrix.python }}
|
|
57
|
+
- run: uv sync --locked --python ${{ matrix.python }}
|
|
58
|
+
- run: uv run pytest
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "17 3 * * 4"
|
|
9
|
+
|
|
10
|
+
permissions: {}
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
analyze:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
actions: read
|
|
17
|
+
contents: read
|
|
18
|
+
security-events: write
|
|
19
|
+
steps:
|
|
20
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
21
|
+
with:
|
|
22
|
+
egress-policy: audit
|
|
23
|
+
|
|
24
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
25
|
+
with:
|
|
26
|
+
persist-credentials: false
|
|
27
|
+
|
|
28
|
+
- uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
|
29
|
+
with:
|
|
30
|
+
languages: python
|
|
31
|
+
queries: security-and-quality
|
|
32
|
+
|
|
33
|
+
- uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
|
34
|
+
with:
|
|
35
|
+
category: "/language:python"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Dependency Review
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
|
|
6
|
+
permissions: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
dependency-review:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
steps:
|
|
14
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
15
|
+
with:
|
|
16
|
+
egress-policy: audit
|
|
17
|
+
|
|
18
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
19
|
+
with:
|
|
20
|
+
persist-credentials: false
|
|
21
|
+
|
|
22
|
+
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions: {}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
release:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment:
|
|
13
|
+
name: pypi
|
|
14
|
+
url: https://pypi.org/p/landlockpy
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
id-token: write
|
|
18
|
+
attestations: write
|
|
19
|
+
steps:
|
|
20
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
21
|
+
with:
|
|
22
|
+
egress-policy: audit
|
|
23
|
+
|
|
24
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
25
|
+
with:
|
|
26
|
+
persist-credentials: false
|
|
27
|
+
|
|
28
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
29
|
+
with:
|
|
30
|
+
version: "0.11.32"
|
|
31
|
+
|
|
32
|
+
- run: uv sync --locked
|
|
33
|
+
|
|
34
|
+
- name: Verify tag matches package version
|
|
35
|
+
run: |
|
|
36
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
37
|
+
version="$(uv run python -c 'import landlockpy; print(landlockpy.__version__)')"
|
|
38
|
+
if [ "$tag" != "$version" ]; then
|
|
39
|
+
echo "tag $tag does not match package version $version" >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
- run: uv build
|
|
44
|
+
|
|
45
|
+
- name: Attest build provenance
|
|
46
|
+
uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0
|
|
47
|
+
with:
|
|
48
|
+
subject-path: dist/*
|
|
49
|
+
|
|
50
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
51
|
+
with:
|
|
52
|
+
attestations: true
|
|
53
|
+
|
|
54
|
+
- name: Create GitHub release
|
|
55
|
+
env:
|
|
56
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
57
|
+
run: |
|
|
58
|
+
gh release create "${GITHUB_REF_NAME}" \
|
|
59
|
+
--repo "${GITHUB_REPOSITORY}" \
|
|
60
|
+
--verify-tag \
|
|
61
|
+
--title "${GITHUB_REF_NAME}" \
|
|
62
|
+
--generate-notes \
|
|
63
|
+
dist/*
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: OpenSSF Scorecard
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
branch_protection_rule:
|
|
5
|
+
push:
|
|
6
|
+
branches: [master]
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "42 5 * * 6"
|
|
9
|
+
|
|
10
|
+
permissions: read-all
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
analysis:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
security-events: write
|
|
17
|
+
id-token: write
|
|
18
|
+
steps:
|
|
19
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
20
|
+
with:
|
|
21
|
+
egress-policy: audit
|
|
22
|
+
|
|
23
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
|
|
27
|
+
- uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
|
|
28
|
+
with:
|
|
29
|
+
results_file: results.sarif
|
|
30
|
+
results_format: sarif
|
|
31
|
+
publish_results: true
|
|
32
|
+
|
|
33
|
+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
34
|
+
with:
|
|
35
|
+
name: SARIF file
|
|
36
|
+
path: results.sarif
|
|
37
|
+
retention-days: 5
|
|
38
|
+
|
|
39
|
+
- uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
|
40
|
+
with:
|
|
41
|
+
sarif_file: results.sarif
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: zizmor
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
paths: [.github/**]
|
|
7
|
+
pull_request:
|
|
8
|
+
paths: [.github/**]
|
|
9
|
+
|
|
10
|
+
permissions: {}
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
zizmor:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
security-events: write
|
|
17
|
+
steps:
|
|
18
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
19
|
+
with:
|
|
20
|
+
egress-policy: audit
|
|
21
|
+
|
|
22
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
23
|
+
with:
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
|
|
26
|
+
- uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
|
|
27
|
+
with:
|
|
28
|
+
advanced-security: false
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-09-22
|
|
4
|
+
|
|
5
|
+
Initial release.
|
|
6
|
+
|
|
7
|
+
- Ruleset construction with handled filesystem, network and scope rights.
|
|
8
|
+
- Path-hierarchy rules and TCP/UDP port rules, including quiet rules (ABI 10).
|
|
9
|
+
- Scoped domains for abstract UNIX sockets and signals (ABI 6).
|
|
10
|
+
- Restrict flags covering audit logging, TSYNC and atomic no_new_privs
|
|
11
|
+
(ABI 11, prctl fallback on older kernels).
|
|
12
|
+
- Best-effort masking to the running kernel, strict mode via
|
|
13
|
+
best_effort=False.
|
|
14
|
+
- Kernel probes: abi_version(), errata(), supported(), and the for_abi
|
|
15
|
+
helpers for computing which rights a given ABI supports.
|
landlockpy-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Copyright (c) 2026 Quad4
|
|
2
|
+
|
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
4
|
+
with or without fee is hereby granted.
|
|
5
|
+
|
|
6
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
7
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
8
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
9
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
10
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
11
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
12
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: landlockpy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python bindings for the Landlock Linux security module
|
|
5
|
+
Project-URL: Homepage, https://quad4.io
|
|
6
|
+
Project-URL: Repository, https://github.com/Quad4-Software/landlockpy
|
|
7
|
+
Project-URL: Documentation, https://docs.kernel.org/userspace-api/landlock.html
|
|
8
|
+
Author: Quad4
|
|
9
|
+
License-Expression: 0BSD
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: landlock,linux,lsm,sandbox,security
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Security
|
|
18
|
+
Classifier: Topic :: System :: Operating System Kernels :: Linux
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# landlockpy
|
|
24
|
+
|
|
25
|
+
[](https://github.com/Quad4-Software/landlockpy/actions/workflows/ci.yml)
|
|
26
|
+
[](https://github.com/Quad4-Software/landlockpy/actions/workflows/codeql.yml)
|
|
27
|
+
[](https://securityscorecards.dev/viewer/?uri=github.com/Quad4-Software/landlockpy)
|
|
28
|
+
[](LICENSE)
|
|
29
|
+
|
|
30
|
+
Dependency-free Python bindings for the Landlock Linux security module.
|
|
31
|
+
Landlock lets unprivileged processes sandbox themselves with filesystem,
|
|
32
|
+
network and IPC restrictions enforced by the kernel. Supports ABI versions
|
|
33
|
+
1 through 11 with best-effort degradation on older kernels.
|
|
34
|
+
|
|
35
|
+
Requires Python 3.10+ and Linux 5.13+ with Landlock enabled in the LSM list.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
pip install landlockpy
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from landlockpy import AccessFS, AccessNet, Ruleset
|
|
45
|
+
|
|
46
|
+
with Ruleset() as ruleset:
|
|
47
|
+
ruleset.allow_path(
|
|
48
|
+
"/usr", AccessFS.READ_FILE | AccessFS.READ_DIR | AccessFS.EXECUTE
|
|
49
|
+
)
|
|
50
|
+
ruleset.allow_port(443, AccessNet.CONNECT_TCP)
|
|
51
|
+
ruleset.restrict()
|
|
52
|
+
|
|
53
|
+
# everything not granted above is now denied for this thread and its children
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`landlockpy.supported()` reports whether the running kernel has Landlock,
|
|
57
|
+
and `landlockpy.abi_version()` returns its ABI version.
|
|
58
|
+
|
|
59
|
+
## Documentation
|
|
60
|
+
|
|
61
|
+
- API: docstrings in `src/landlockpy/`, mostly `ruleset.py`
|
|
62
|
+
- Landlock API reference: https://docs.kernel.org/userspace-api/landlock.html
|
|
63
|
+
- Project site: https://landlock.io/
|
|
64
|
+
|
|
65
|
+
License: 0BSD.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# landlockpy
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Quad4-Software/landlockpy/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/Quad4-Software/landlockpy/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://securityscorecards.dev/viewer/?uri=github.com/Quad4-Software/landlockpy)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Dependency-free Python bindings for the Landlock Linux security module.
|
|
9
|
+
Landlock lets unprivileged processes sandbox themselves with filesystem,
|
|
10
|
+
network and IPC restrictions enforced by the kernel. Supports ABI versions
|
|
11
|
+
1 through 11 with best-effort degradation on older kernels.
|
|
12
|
+
|
|
13
|
+
Requires Python 3.10+ and Linux 5.13+ with Landlock enabled in the LSM list.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
pip install landlockpy
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from landlockpy import AccessFS, AccessNet, Ruleset
|
|
23
|
+
|
|
24
|
+
with Ruleset() as ruleset:
|
|
25
|
+
ruleset.allow_path(
|
|
26
|
+
"/usr", AccessFS.READ_FILE | AccessFS.READ_DIR | AccessFS.EXECUTE
|
|
27
|
+
)
|
|
28
|
+
ruleset.allow_port(443, AccessNet.CONNECT_TCP)
|
|
29
|
+
ruleset.restrict()
|
|
30
|
+
|
|
31
|
+
# everything not granted above is now denied for this thread and its children
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`landlockpy.supported()` reports whether the running kernel has Landlock,
|
|
35
|
+
and `landlockpy.abi_version()` returns its ABI version.
|
|
36
|
+
|
|
37
|
+
## Documentation
|
|
38
|
+
|
|
39
|
+
- API: docstrings in `src/landlockpy/`, mostly `ruleset.py`
|
|
40
|
+
- Landlock API reference: https://docs.kernel.org/userspace-api/landlock.html
|
|
41
|
+
- Project site: https://landlock.io/
|
|
42
|
+
|
|
43
|
+
License: 0BSD.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "landlockpy"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Python bindings for the Landlock Linux security module"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "0BSD"
|
|
12
|
+
authors = [{ name = "Quad4" }]
|
|
13
|
+
keywords = ["landlock", "lsm", "sandbox", "security", "linux"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: BSD License",
|
|
18
|
+
"Operating System :: POSIX :: Linux",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Topic :: Security",
|
|
21
|
+
"Topic :: System :: Operating System Kernels :: Linux",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = []
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://quad4.io"
|
|
28
|
+
Repository = "https://github.com/Quad4-Software/landlockpy"
|
|
29
|
+
Documentation = "https://docs.kernel.org/userspace-api/landlock.html"
|
|
30
|
+
|
|
31
|
+
[tool.hatch.version]
|
|
32
|
+
path = "src/landlockpy/__init__.py"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"pytest>=9.1.1",
|
|
37
|
+
"ruff>=0.16.8",
|
|
38
|
+
"bandit>=1.9.4",
|
|
39
|
+
"mypy>=2.3.1",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.ruff]
|
|
43
|
+
target-version = "py310"
|
|
44
|
+
src = ["src", "tests"]
|
|
45
|
+
|
|
46
|
+
[tool.ruff.lint]
|
|
47
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "S", "PTH", "C90", "RUF", "TRY"]
|
|
48
|
+
ignore = ["TRY003"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint.per-file-ignores]
|
|
51
|
+
"tests/*" = ["S101", "S603"]
|
|
52
|
+
|
|
53
|
+
[tool.mypy]
|
|
54
|
+
strict = true
|
|
55
|
+
files = ["src", "tests"]
|
|
56
|
+
|
|
57
|
+
[tool.bandit]
|
|
58
|
+
exclude_dirs = ["tests"]
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
testpaths = ["tests"]
|
|
62
|
+
markers = [
|
|
63
|
+
"enforced: tests that apply a Landlock ruleset in a child process",
|
|
64
|
+
]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# SPDX-License-Identifier: 0BSD
|
|
2
|
+
"""Python bindings for the Landlock Linux security module.
|
|
3
|
+
|
|
4
|
+
Landlock lets unprivileged processes sandbox themselves with filesystem,
|
|
5
|
+
network and IPC restrictions enforced by the kernel. Rulesets are scoped to
|
|
6
|
+
what the running kernel supports, so applications get best-effort protection
|
|
7
|
+
across kernel versions.
|
|
8
|
+
|
|
9
|
+
Kernel reference: https://docs.kernel.org/userspace-api/landlock.html
|
|
10
|
+
Project site: https://landlock.io/
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import errno
|
|
14
|
+
|
|
15
|
+
from . import _syscall
|
|
16
|
+
from .errors import LandlockError, UnsupportedError
|
|
17
|
+
from .flags import (
|
|
18
|
+
AccessFS,
|
|
19
|
+
AccessNet,
|
|
20
|
+
RestrictFlag,
|
|
21
|
+
Scope,
|
|
22
|
+
fs_for_abi,
|
|
23
|
+
net_for_abi,
|
|
24
|
+
restrict_for_abi,
|
|
25
|
+
scope_for_abi,
|
|
26
|
+
)
|
|
27
|
+
from .ruleset import Ruleset
|
|
28
|
+
|
|
29
|
+
__version__ = "0.1.0"
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"AccessFS",
|
|
33
|
+
"AccessNet",
|
|
34
|
+
"LandlockError",
|
|
35
|
+
"RestrictFlag",
|
|
36
|
+
"Ruleset",
|
|
37
|
+
"Scope",
|
|
38
|
+
"UnsupportedError",
|
|
39
|
+
"__version__",
|
|
40
|
+
"abi_version",
|
|
41
|
+
"errata",
|
|
42
|
+
"fs_for_abi",
|
|
43
|
+
"net_for_abi",
|
|
44
|
+
"restrict_for_abi",
|
|
45
|
+
"scope_for_abi",
|
|
46
|
+
"supported",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def abi_version() -> int:
|
|
51
|
+
"""Return the Landlock ABI version of the running kernel, or 0.
|
|
52
|
+
|
|
53
|
+
A return value of 0 means the kernel is too old (ENOSYS) or Landlock is
|
|
54
|
+
disabled at boot time (EOPNOTSUPP).
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
return _syscall.abi_version()
|
|
58
|
+
except LandlockError as exc:
|
|
59
|
+
if exc.errno in (errno.ENOSYS, errno.EOPNOTSUPP):
|
|
60
|
+
return 0
|
|
61
|
+
raise
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def errata() -> int:
|
|
65
|
+
"""Return the errata bitmask for the current ABI version, or 0.
|
|
66
|
+
|
|
67
|
+
Bit N set means erratum N is fixed in the running kernel. Older kernels
|
|
68
|
+
without the errata mechanism report 0. Most applications should not
|
|
69
|
+
check errata; best-effort enforcement is the safer default.
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
return _syscall.errata()
|
|
73
|
+
except LandlockError as exc:
|
|
74
|
+
if exc.errno in (errno.ENOSYS, errno.EOPNOTSUPP, errno.EINVAL):
|
|
75
|
+
return 0
|
|
76
|
+
raise
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def supported() -> bool:
|
|
80
|
+
"""Return whether the running kernel supports Landlock."""
|
|
81
|
+
return abi_version() >= 1
|