seccompy 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.
- seccompy-0.1.0/.github/CODEOWNERS +3 -0
- seccompy-0.1.0/.github/dependabot.yml +16 -0
- seccompy-0.1.0/.github/workflows/ci.yml +59 -0
- seccompy-0.1.0/.github/workflows/codeql.yml +35 -0
- seccompy-0.1.0/.github/workflows/dependency-review.yml +22 -0
- seccompy-0.1.0/.github/workflows/release.yml +63 -0
- seccompy-0.1.0/.github/workflows/scorecard.yml +42 -0
- seccompy-0.1.0/.github/workflows/zizmor.yml +28 -0
- seccompy-0.1.0/.gitignore +11 -0
- seccompy-0.1.0/CHANGELOG.md +24 -0
- seccompy-0.1.0/CONTRIBUTING.md +19 -0
- seccompy-0.1.0/LICENSE +12 -0
- seccompy-0.1.0/Makefile +16 -0
- seccompy-0.1.0/PKG-INFO +78 -0
- seccompy-0.1.0/README.md +57 -0
- seccompy-0.1.0/SECURITY.md +6 -0
- seccompy-0.1.0/pyproject.toml +107 -0
- seccompy-0.1.0/src/seccompy/__init__.py +87 -0
- seccompy-0.1.0/src/seccompy/_syscall.py +124 -0
- seccompy-0.1.0/src/seccompy/bpf.py +248 -0
- seccompy-0.1.0/src/seccompy/errors.py +10 -0
- seccompy-0.1.0/src/seccompy/filter.py +275 -0
- seccompy-0.1.0/src/seccompy/py.typed +0 -0
- seccompy-0.1.0/src/seccompy/syscalls.py +825 -0
- seccompy-0.1.0/src/seccompy/testing.py +63 -0
- seccompy-0.1.0/tests/__init__.py +1 -0
- seccompy-0.1.0/tests/_sandbox.py +175 -0
- seccompy-0.1.0/tests/conftest.py +46 -0
- seccompy-0.1.0/tests/test_bpf.py +212 -0
- seccompy-0.1.0/tests/test_enforced.py +81 -0
- seccompy-0.1.0/tests/test_filter.py +195 -0
- seccompy-0.1.0/tests/test_seccompy.py +119 -0
- seccompy-0.1.0/tests/test_syscalls.py +63 -0
- seccompy-0.1.0/uv.lock +863 -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,59 @@
|
|
|
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
|
+
- run: uvx ty check src tests
|
|
36
|
+
|
|
37
|
+
test:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
strategy:
|
|
40
|
+
fail-fast: false
|
|
41
|
+
matrix:
|
|
42
|
+
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
43
|
+
steps:
|
|
44
|
+
- uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
|
45
|
+
with:
|
|
46
|
+
egress-policy: audit
|
|
47
|
+
|
|
48
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
49
|
+
with:
|
|
50
|
+
persist-credentials: false
|
|
51
|
+
|
|
52
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
53
|
+
with:
|
|
54
|
+
version: "0.11.32"
|
|
55
|
+
enable-cache: true
|
|
56
|
+
|
|
57
|
+
- run: uv python install ${{ matrix.python }}
|
|
58
|
+
- run: uv sync --locked --python ${{ matrix.python }}
|
|
59
|
+
- run: uv run pytest --cov --cov-fail-under=80
|
|
@@ -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/seccompy
|
|
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 seccompy; print(seccompy.__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@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
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,42 @@
|
|
|
1
|
+
name: OpenSSF Scorecard
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
branch_protection_rule:
|
|
5
|
+
push:
|
|
6
|
+
branches: [master]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "42 5 * * 6"
|
|
10
|
+
|
|
11
|
+
permissions: read-all
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
analysis:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
security-events: write
|
|
18
|
+
id-token: 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: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
|
|
29
|
+
with:
|
|
30
|
+
results_file: results.sarif
|
|
31
|
+
results_format: sarif
|
|
32
|
+
publish_results: true
|
|
33
|
+
|
|
34
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
name: SARIF file
|
|
37
|
+
path: results.sarif
|
|
38
|
+
retention-days: 5
|
|
39
|
+
|
|
40
|
+
- uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
|
|
41
|
+
with:
|
|
42
|
+
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,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-09-22
|
|
6
|
+
|
|
7
|
+
Initial release.
|
|
8
|
+
|
|
9
|
+
- Pure-Python classic BPF assembler for struct sock_filter programs,
|
|
10
|
+
with symbolic labels, forward-jump resolution and automatic JA
|
|
11
|
+
trampolines for conditional jumps beyond the 8-bit offset limit.
|
|
12
|
+
- Filter API with a default action plus per-syscall rules: allow(),
|
|
13
|
+
kill() (KILL_PROCESS), kill_thread(), trap(), errno(), trace() and
|
|
14
|
+
log(), each optionally gated on equality of 64-bit syscall arguments.
|
|
15
|
+
- Compiled programs always verify seccomp_data.arch against the native
|
|
16
|
+
AUDIT_ARCH_* value and kill foreign-ABI syscalls.
|
|
17
|
+
- Raw ctypes bindings for seccomp(2) and prctl(PR_SET_NO_NEW_PRIVS),
|
|
18
|
+
with real kernel errnos preserved on SeccompError/UnsupportedError.
|
|
19
|
+
- Kernel feature probes: supported(), action_supported() via
|
|
20
|
+
SECCOMP_GET_ACTION_AVAIL and flag_supported() via NULL-program flag
|
|
21
|
+
validation.
|
|
22
|
+
- Full x86_64 and aarch64 syscall name/number tables generated from the
|
|
23
|
+
kernel UAPI headers, with syscall_nr() and syscall_name() helpers.
|
|
24
|
+
- testing.probe() to run a callable under a filter in a forked child.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Report bugs through GitHub issues. Security reports go to
|
|
4
|
+
security@quad4.io (see SECURITY.md).
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
uv sync
|
|
9
|
+
make check
|
|
10
|
+
|
|
11
|
+
`make check` runs the full local gate: ruff lint and format, bandit,
|
|
12
|
+
mypy strict, ty, and pytest with coverage.
|
|
13
|
+
|
|
14
|
+
## Conventions
|
|
15
|
+
|
|
16
|
+
- No runtime dependencies unless the project genuinely needs one.
|
|
17
|
+
- Source files start with the SPDX license identifier.
|
|
18
|
+
- Public API changes need tests.
|
|
19
|
+
- Commit messages: short, imperative, formal.
|
seccompy-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.
|
seccompy-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.PHONY: check lint test build
|
|
2
|
+
|
|
3
|
+
check: lint test
|
|
4
|
+
|
|
5
|
+
lint:
|
|
6
|
+
uv run ruff check .
|
|
7
|
+
uv run ruff format --check .
|
|
8
|
+
uv run bandit -r src/
|
|
9
|
+
uv run mypy
|
|
10
|
+
uvx ty check src tests
|
|
11
|
+
|
|
12
|
+
test:
|
|
13
|
+
uv run pytest --cov --cov-report=term-missing
|
|
14
|
+
|
|
15
|
+
build:
|
|
16
|
+
uv build
|
seccompy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: seccompy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python bindings for Linux seccomp-BPF syscall filtering
|
|
5
|
+
Project-URL: Homepage, https://quad4.io
|
|
6
|
+
Project-URL: Repository, https://github.com/Quad4-Software/seccompy
|
|
7
|
+
Project-URL: Issues, https://github.com/Quad4-Software/seccompy/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/Quad4-Software/seccompy/blob/master/CHANGELOG.md
|
|
9
|
+
Author: Quad4
|
|
10
|
+
License-Expression: 0BSD
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: bpf,linux,sandbox,seccomp,security
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# seccompy
|
|
23
|
+
|
|
24
|
+
[](https://github.com/Quad4-Software/seccompy/actions/workflows/ci.yml)
|
|
25
|
+
[](https://github.com/Quad4-Software/seccompy/actions/workflows/codeql.yml)
|
|
26
|
+
[](https://securityscorecards.dev/viewer/?uri=github.com/Quad4-Software/seccompy)
|
|
27
|
+
[](https://pypi.org/project/seccompy/)
|
|
28
|
+
[](LICENSE)
|
|
29
|
+
|
|
30
|
+
Dependency-free Python bindings for Linux seccomp-BPF syscall filtering.
|
|
31
|
+
Filters are assembled in pure Python from symbolic instructions, checked
|
|
32
|
+
against the native architecture to block ABI confusion, and installed
|
|
33
|
+
through seccomp(2) with prctl(PR_SET_NO_NEW_PRIVS), so no compiler,
|
|
34
|
+
libbpf or privileges are needed.
|
|
35
|
+
|
|
36
|
+
Requires Python 3.10+ and Linux 3.17+ on x86_64 or aarch64.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
pip install seccompy
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import errno
|
|
46
|
+
|
|
47
|
+
from seccompy import Action, Filter
|
|
48
|
+
|
|
49
|
+
filt = Filter(default=Action.ALLOW)
|
|
50
|
+
filt.errno("openat", errno.EACCES)
|
|
51
|
+
filt.kill("ptrace")
|
|
52
|
+
filt.log("mount")
|
|
53
|
+
filt.load()
|
|
54
|
+
|
|
55
|
+
# openat now fails with EACCES for this thread and its children,
|
|
56
|
+
# ptrace kills the process, mount is allowed but logged
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Rules can also match on 64-bit syscall arguments:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
filt.errno("write", errno.EIO, args={0: 1}) # deny write() on fd 1 only
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`seccompy.supported()` reports whether the running kernel can install
|
|
66
|
+
filters, `seccompy.action_supported(Action.X)` probes a return action
|
|
67
|
+
and `seccompy.flag_supported(FilterFlag.X)` probes a load flag. The
|
|
68
|
+
compiled BPF program is available as `filt.program` for inspection, and
|
|
69
|
+
`seccompy.testing.probe()` runs a callable under a filter in a forked
|
|
70
|
+
child to preview enforcement.
|
|
71
|
+
|
|
72
|
+
## Documentation
|
|
73
|
+
|
|
74
|
+
- API: docstrings in `src/seccompy/`, mostly `filter.py`
|
|
75
|
+
- seccomp reference: https://docs.kernel.org/userspace-api/seccomp_filter.html
|
|
76
|
+
- seccomp(2) man page: https://man7.org/linux/man-pages/man2/seccomp.2.html
|
|
77
|
+
|
|
78
|
+
License: 0BSD.
|
seccompy-0.1.0/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# seccompy
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Quad4-Software/seccompy/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/Quad4-Software/seccompy/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://securityscorecards.dev/viewer/?uri=github.com/Quad4-Software/seccompy)
|
|
6
|
+
[](https://pypi.org/project/seccompy/)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
Dependency-free Python bindings for Linux seccomp-BPF syscall filtering.
|
|
10
|
+
Filters are assembled in pure Python from symbolic instructions, checked
|
|
11
|
+
against the native architecture to block ABI confusion, and installed
|
|
12
|
+
through seccomp(2) with prctl(PR_SET_NO_NEW_PRIVS), so no compiler,
|
|
13
|
+
libbpf or privileges are needed.
|
|
14
|
+
|
|
15
|
+
Requires Python 3.10+ and Linux 3.17+ on x86_64 or aarch64.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
pip install seccompy
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import errno
|
|
25
|
+
|
|
26
|
+
from seccompy import Action, Filter
|
|
27
|
+
|
|
28
|
+
filt = Filter(default=Action.ALLOW)
|
|
29
|
+
filt.errno("openat", errno.EACCES)
|
|
30
|
+
filt.kill("ptrace")
|
|
31
|
+
filt.log("mount")
|
|
32
|
+
filt.load()
|
|
33
|
+
|
|
34
|
+
# openat now fails with EACCES for this thread and its children,
|
|
35
|
+
# ptrace kills the process, mount is allowed but logged
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Rules can also match on 64-bit syscall arguments:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
filt.errno("write", errno.EIO, args={0: 1}) # deny write() on fd 1 only
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`seccompy.supported()` reports whether the running kernel can install
|
|
45
|
+
filters, `seccompy.action_supported(Action.X)` probes a return action
|
|
46
|
+
and `seccompy.flag_supported(FilterFlag.X)` probes a load flag. The
|
|
47
|
+
compiled BPF program is available as `filt.program` for inspection, and
|
|
48
|
+
`seccompy.testing.probe()` runs a callable under a filter in a forked
|
|
49
|
+
child to preview enforcement.
|
|
50
|
+
|
|
51
|
+
## Documentation
|
|
52
|
+
|
|
53
|
+
- API: docstrings in `src/seccompy/`, mostly `filter.py`
|
|
54
|
+
- seccomp reference: https://docs.kernel.org/userspace-api/seccomp_filter.html
|
|
55
|
+
- seccomp(2) man page: https://man7.org/linux/man-pages/man2/seccomp.2.html
|
|
56
|
+
|
|
57
|
+
License: 0BSD.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "seccompy"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Python bindings for Linux seccomp-BPF syscall filtering"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "0BSD"
|
|
12
|
+
authors = [{ name = "Quad4" }]
|
|
13
|
+
keywords = ["seccomp", "bpf", "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
|
+
"Typing :: Typed",
|
|
21
|
+
]
|
|
22
|
+
dependencies = []
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://quad4.io"
|
|
26
|
+
Repository = "https://github.com/Quad4-Software/seccompy"
|
|
27
|
+
Issues = "https://github.com/Quad4-Software/seccompy/issues"
|
|
28
|
+
Changelog = "https://github.com/Quad4-Software/seccompy/blob/master/CHANGELOG.md"
|
|
29
|
+
|
|
30
|
+
[tool.hatch.version]
|
|
31
|
+
path = "src/seccompy/__init__.py"
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=9.1.1",
|
|
36
|
+
"pytest-cov>=7.1.0",
|
|
37
|
+
"hypothesis>=6.140",
|
|
38
|
+
"ruff>=0.16.8",
|
|
39
|
+
"bandit>=1.9.4",
|
|
40
|
+
"mypy>=2.3.1",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[tool.ruff]
|
|
44
|
+
target-version = "py310"
|
|
45
|
+
src = ["src", "tests"]
|
|
46
|
+
|
|
47
|
+
[tool.ruff.lint]
|
|
48
|
+
select = [
|
|
49
|
+
"E", "W", # pycodestyle
|
|
50
|
+
"F", # pyflakes
|
|
51
|
+
"I", # isort
|
|
52
|
+
"N", # pep8-naming
|
|
53
|
+
"UP", # pyupgrade
|
|
54
|
+
"YTT", # sys.version misuse
|
|
55
|
+
"FA", # future annotations
|
|
56
|
+
"A", # builtins shadowing
|
|
57
|
+
"B", # flake8-bugbear
|
|
58
|
+
"BLE", # blind except
|
|
59
|
+
"C4", # comprehensions
|
|
60
|
+
"C90", # mccabe complexity
|
|
61
|
+
"DTZ", # timezone-aware datetimes
|
|
62
|
+
"ERA", # commented-out code
|
|
63
|
+
"FURB", # refurb
|
|
64
|
+
"G", # logging format
|
|
65
|
+
"ICN", # import conventions
|
|
66
|
+
"ISC", # implicit string concat
|
|
67
|
+
"LOG", # logging
|
|
68
|
+
"PERF", # perflint
|
|
69
|
+
"PGH", # pygrep hooks
|
|
70
|
+
"PIE", # misc lints
|
|
71
|
+
"PT", # pytest style
|
|
72
|
+
"PTH", # pathlib
|
|
73
|
+
"RET", # return
|
|
74
|
+
"RSE", # raise/return
|
|
75
|
+
"S", # bandit rules
|
|
76
|
+
"SIM", # simplify
|
|
77
|
+
"SLOT", # __slots__
|
|
78
|
+
"T20", # print
|
|
79
|
+
"TRY", # exception handling
|
|
80
|
+
"RUF", # ruff-specific
|
|
81
|
+
]
|
|
82
|
+
ignore = [
|
|
83
|
+
"ISC001", # single-line implicit concat conflicts with the formatter
|
|
84
|
+
"TRY003", # long messages in raise calls are fine
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint.per-file-ignores]
|
|
88
|
+
"tests/*" = ["S101", "S603"]
|
|
89
|
+
|
|
90
|
+
[tool.mypy]
|
|
91
|
+
strict = true
|
|
92
|
+
files = ["src", "tests"]
|
|
93
|
+
|
|
94
|
+
[tool.bandit]
|
|
95
|
+
exclude_dirs = ["tests"]
|
|
96
|
+
|
|
97
|
+
[tool.coverage.run]
|
|
98
|
+
branch = true
|
|
99
|
+
source = ["src/seccompy"]
|
|
100
|
+
|
|
101
|
+
[tool.coverage.report]
|
|
102
|
+
show_missing = true
|
|
103
|
+
|
|
104
|
+
[tool.pytest.ini_options]
|
|
105
|
+
testpaths = ["tests"]
|
|
106
|
+
xfail_strict = true
|
|
107
|
+
filterwarnings = ["error"]
|