Skip to content

Commit

Permalink
Merge pull request #11 from onekey-sec/landlock
Browse files Browse the repository at this point in the history
Expose landlock API
  • Loading branch information
qkaiser authored Feb 21, 2024
2 parents 371aa58 + e2763ef commit 95bfa0f
Show file tree
Hide file tree
Showing 14 changed files with 351 additions and 20 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
key: pytest-${{ matrix.os }}
- name: Install dependencies
run: |
pdm sync -d
pdm sync -v -d
- name: Run Tests
run: |
pdm pytest
Expand All @@ -109,7 +109,7 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Install dependencies
run: |
pdm sync -d
pdm sync -v -d
- name: Type-Check
run: |
pdm pyright
Expand Down Expand Up @@ -156,7 +156,7 @@ jobs:
with:
target: ${{ matrix.target }}
container: ${{ env.CONTAINER }}
args: --release --out dist
args: --verbose --release --out dist
sccache: ${{ matrix.target == 'musllinux_1_1' }}
manylinux: auto
docker-options: -e CARGO_NET_GIT_FETCH_WITH_CLI=true
Expand All @@ -171,7 +171,7 @@ jobs:
cd /usr/src
curl -sSL https://raw.githubusercontent.com/pdm-project/pdm/main/install-pdm.py | python3.10 -
export PATH=/root/.local/bin:$PATH
pdm sync -d --no-self -G test
pdm sync -v -d --no-self -G test
pdm run python -m ensurepip
pdm run python -m pip install dist/*.whl
pdm pytest
Expand All @@ -196,7 +196,7 @@ jobs:
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist
args: --verbose --release --out dist
sccache: "true"
- name: Upload wheels
uses: actions/upload-artifact@v3
Expand All @@ -208,7 +208,7 @@ jobs:
- name: Test wheels
if: ${{ matrix.target == 'x86_64' }}
run: |
pdm sync -d --no-self -G test
pdm sync -v -d --no-self -G test
pdm run python -m ensurepip
pdm run python -m pip install dist/*.whl
pdm pytest
Expand Down
71 changes: 71 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ crate-type = [
]

[dependencies]
log = "0.4.18"
pyo3 = "0.18.3"
pyo3-log = "0.8.1"

[target.'cfg(target_os = "linux")'.dependencies]
landlock = "0.2.0"

[dev-dependencies]
approx = "0.5.0"
Expand Down
2 changes: 1 addition & 1 deletion benches/benches_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn shannon_entropy(c: &mut Criterion) {
BenchmarkId::from_parameter(sample_size),
&sample_size,
|b, &size| {
b.iter(|| unblob_native::math::shannon_entropy(&sample[0..size]));
b.iter(|| unblob_native::math_tools::shannon_entropy(&sample[0..size]));
},
);
}
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ ignore = [
"D203", # one-blank-line-before-class: D211 (no-blank-line-before-class) is used instead
"D213", # multi-line-summary-second-line: D212 (multi-line-summary-first-line) is used instead
"E501", # line-too-long: Let black handle line length violations
"UP007", # non-pep604-annotation: Python 3.8 support needs legacy annotations
]

[tool.ruff.per-file-ignores]
Expand Down
3 changes: 0 additions & 3 deletions python/unblob_native/_native/__init__.pyi

This file was deleted.

File renamed without changes.
20 changes: 20 additions & 0 deletions python/unblob_native/sandbox.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import os
import typing

import typing_extensions

_Path: typing_extensions.TypeAlias = typing.Union[os.PathLike, str]

class AccessFS:
@staticmethod
def read(access_dir: _Path) -> AccessFS: ...
@staticmethod
def read_write(access_dir: _Path) -> AccessFS: ...
@staticmethod
def make_reg(access_dir: _Path) -> AccessFS: ...
@staticmethod
def make_dir(access_dir: _Path) -> AccessFS: ...

def restrict_access(*args: AccessFS) -> None: ...

class SandboxError(Exception): ...
16 changes: 6 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
pub mod math;
pub mod math_tools;
pub mod sandbox;

use pyo3::prelude::*;

/// Calculates Shannon entropy of data
#[pyfunction(text_signature = "(data)")]
pub fn shannon_entropy(py: Python, data: &[u8]) -> PyResult<f64> {
py.allow_threads(|| Ok(math::shannon_entropy(data)))
}

/// Performance-critical functionality
#[pymodule]
fn _native(py: Python, m: &PyModule) -> PyResult<()> {
let math_module = PyModule::new(py, "math_tools")?;
math_module.add_function(wrap_pyfunction!(shannon_entropy, math_module)?)?;
math_tools::init_module(py, m)?;
sandbox::init_module(py, m)?;

pyo3_log::init();

m.add_submodule(math_module)?;
Ok(())
}
20 changes: 20 additions & 0 deletions src/math.rs → src/math_tools.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use pyo3::prelude::*;

pub fn shannon_entropy(data: &[u8]) -> f64 {
let mut entropy = 0.0;
let mut counts = [0; 256];
Expand All @@ -17,6 +19,24 @@ pub fn shannon_entropy(data: &[u8]) -> f64 {

entropy
}
/// Calculates Shannon entropy of data
#[pyfunction(name = "shannon_entropy")]
pub fn py_shannon_entropy(py: Python, data: &[u8]) -> PyResult<f64> {
py.allow_threads(|| Ok(shannon_entropy(data)))
}

pub fn init_module(py: Python, root_module: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "math_tools")?;
module.add_function(wrap_pyfunction!(py_shannon_entropy, module)?)?;

root_module.add_submodule(module)?;

py.import("sys")?
.getattr("modules")?
.set_item("unblob_native.math", module)?;

Ok(())
}

#[cfg(test)]
mod tests {
Expand Down
74 changes: 74 additions & 0 deletions src/sandbox/linux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use landlock::{
path_beneath_rules, Access, AccessFs, Ruleset, RulesetAttr, RulesetCreatedAttr, ABI,
};
use log;

use std::path::Path;

use crate::sandbox::AccessFS;

impl AccessFS {
fn read(&self) -> Option<&Path> {
if let Self::Read(path) = self {
Some(path)
} else {
None
}
}

fn read_write(&self) -> Option<&Path> {
if let Self::ReadWrite(path) = self {
Some(path)
} else {
None
}
}

fn make_reg(&self) -> Option<&Path> {
if let Self::MakeReg(path) = self {
Some(path)
} else {
None
}
}

fn make_dir(&self) -> Option<&Path> {
if let Self::MakeDir(path) = self {
Some(path)
} else {
None
}
}
}

pub fn restrict_access(access_rules: &[AccessFS]) -> Result<(), Box<dyn std::error::Error>> {
let abi = ABI::V2;

let read_only: Vec<&Path> = access_rules.iter().filter_map(AccessFS::read).collect();

let read_write: Vec<&Path> = access_rules
.iter()
.filter_map(AccessFS::read_write)
.collect();

let create_file: Vec<&Path> = access_rules.iter().filter_map(AccessFS::make_reg).collect();

let create_directory: Vec<&Path> = access_rules.iter().filter_map(AccessFS::make_dir).collect();

let status = Ruleset::new()
.handle_access(AccessFs::from_all(abi))?
.create()?
.add_rules(path_beneath_rules(read_write, AccessFs::from_all(abi)))?
.add_rules(path_beneath_rules(create_file, AccessFs::MakeReg))?
.add_rules(path_beneath_rules(create_directory, AccessFs::MakeDir))?
.add_rules(path_beneath_rules(read_only, AccessFs::from_read(abi)))?
.restrict_self()?;

log::info!(
"Activated FS access restrictions; rules={:?}, status={:?}",
access_rules,
status.ruleset
);

Ok(())
}
Loading

0 comments on commit 95bfa0f

Please sign in to comment.