first commit

This commit is contained in:
guochao 2023-11-01 16:17:51 +08:00
commit 1a5d0ebbb7
15 changed files with 1779 additions and 0 deletions

3
.cargo/config Normal file
View File

@ -0,0 +1,3 @@
[build]
target = "x86_64-unknown-linux-musl"

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.direnv
/target
/result

49
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,49 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'x2t-sandbox'",
"cargo": {
"args": [
"build",
"--bin=x2t-sandbox",
"--package=x2t-sandbox",
"--target=x86_64-unknown-linux-gnu"
],
"filter": {
"name": "x2t-sandbox",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}",
"env": {
"RUST_LOG": "DEBUG"
}
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in executable 'x2t-sandbox'",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=x2t-sandbox",
"--package=x2t-sandbox"
],
"filter": {
"name": "x2t-sandbox",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

336
Cargo.lock generated Normal file
View File

@ -0,0 +1,336 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "env_logger"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
"humantime",
"is-terminal",
"log",
"regex",
"termcolor",
]
[[package]]
name = "errno"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "hermit-abi"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys",
]
[[package]]
name = "libc"
version = "0.2.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
[[package]]
name = "libseccomp"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21c57fd8981a80019807b7b68118618d29a87177c63d704fc96e6ecd003ae5b3"
dependencies = [
"bitflags 1.3.2",
"libc",
"libseccomp-sys",
"pkg-config",
]
[[package]]
name = "libseccomp-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a7cbbd4ad467251987c6e5b47d53b11a5a05add08f2447a9e2d70aef1e0d138"
[[package]]
name = "linux-raw-sys"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
"libc",
]
[[package]]
name = "pkg-config"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustix"
version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
dependencies = [
"winapi-util",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "x2t-sandbox"
version = "0.1.0"
dependencies = [
"anyhow",
"env_logger",
"libseccomp",
"log",
"nix",
"pkg-config",
"x2t-sandbox-rulegen",
]
[[package]]
name = "x2t-sandbox-rulegen"
version = "0.1.0"
dependencies = [
"nix",
"proc-macro2",
"quote",
"regex",
]

23
Cargo.toml Normal file
View File

@ -0,0 +1,23 @@
[package]
name = "x2t-sandbox"
version = "0.1.0"
edition = "2021"
[workspace]
members = [
"x2t-sandbox-rulegen"
]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.75"
env_logger = "0.10.0"
libseccomp = "0.3.0"
log = "0.4.20"
nix = { version = "0.27.1", features = [ "process" ] }
x2t-sandbox-rulegen = { path = "./x2t-sandbox-rulegen" }
[build-dependencies]
anyhow = "1.0.75"
pkg-config = "0.3.27"

34
README.md Normal file
View File

@ -0,0 +1,34 @@
# x2t 沙箱
为了避免 x2t 解析文档时,被通过内存溢出而执行未信任代码,对 x2t 做一层沙箱,限制 syscall 调用
## Quick start
### Setup
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
### Build
```
cargo build
```
### Run
```
cargo run
```
## 项目结构
- [项目](/)
- [x2t-syscalls.txt](/x2t-syscalls.txt): x2t 用到的 syscall
- [build.rs](/build.rs): 解决少数构建平台无法找到 libseccomp 的问题
- [x2t-sandbox-rulegen](/x2t-sandbox-rulegen/): 通过 macro 直接从 syscall 列表生成代码不用内嵌syscall名字文本了不容易被修改
- Cargo.toml/Cargo.lock/rust-toolchain.toml: 已经被配置为默认构建静态链接的二进制
- optional: flake.nix/flake.lock: nix 搭建的、完全统一的统一开发环境,配置为默认构建静态链接的二进制
- .envrc: 如果不适用nix注释掉或者 direnv block 一下不加载就行
- .gitignore

5
build.rs Normal file
View File

@ -0,0 +1,5 @@
fn main() -> anyhow::Result<()> {
pkg_config::probe_library("libseccomp")?;
Ok(())
}

65
flake.lock generated Normal file
View File

@ -0,0 +1,65 @@
{
"nodes": {
"fenix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1698733307,
"narHash": "sha256-1DngQANpymPDqFpdeb5CjE7g4+J6E169MqD9KEHOltY=",
"owner": "nix-community",
"repo": "fenix",
"rev": "3755012ba41d5d7f27d6d3d37a82cf30605dcab6",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1698611440,
"narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable",
"type": "indirect"
}
},
"root": {
"inputs": {
"fenix": "fenix",
"nixpkgs": "nixpkgs"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1698691756,
"narHash": "sha256-O250hhxQJhDyGKvVMjrdjuCB90Lz3VgIR5WxQAoCeeM=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "a2e2881676b52f6d8bd4e4b38cd169e57790013f",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

93
flake.nix Normal file
View File

@ -0,0 +1,93 @@
{
inputs = {
fenix = {
url = "github:nix-community/fenix";
inputs.nixpkgs.follows = "nixpkgs";
};
nixpkgs.url = "nixpkgs/nixos-unstable";
};
outputs = { nixpkgs, fenix, ... }:
let
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
foreachSystem = nixpkgs.lib.genAttrs systems;
buildTools = pkgs: with pkgs; [
pkg-config
# TODO: cargo-lipo
];
developmentTools = pkgs: with pkgs; [
# bpf-linker
# cargo-espflash
cargo-expand
# cargo-generate
# cargo-make
# cargo-mobile2
# cargo-tauri
# cargo-watch
# TODO: cargo-xcode
# TODO: create-tauri-app
# cargo-espflash
# TODO: kopium
# TODO: ldproxy
# TODO: paperclip
# sea-orm-cli
# perseus-cli
# trunk
# wasm-bindgen-cli
];
libraries = pkgs: with pkgs; [
libseccomp
];
buildRustPlatform = pkgs: with fenix.packages."${pkgs.stdenv.system}"; let toolchain = combine [ complete.toolchain targets."x86_64-unknown-linux-musl".latest.rust-std ]; in pkgs.makeRustPlatform {
cargo = toolchain;
rustc = toolchain;
};
buildWithPackages = pkgs: pkgsStatic: (buildRustPlatform pkgsStatic).buildRustPackage rec {
pname = "hello";
version = "1.0.0";
nativeBuildInputs = buildTools pkgs;
buildInputs = libraries pkgsStatic;
src = ./.;
cargoLock = {
lockFile = ./Cargo.lock;
};
meta = with nixpkgs.lib; {
description = "rust project scaffold";
homepage = "https://git.jeffthecoder.xyz/public/os-flakes";
license = licenses.unlicense;
maintainers = [ ];
};
}
;
in
rec {
packages = foreachSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in
rec {
hello = buildWithPackages pkgs pkgs.pkgsStatic;
default = hello;
});
devShells = foreachSystem
(system:
let
pkgs = import nixpkgs { inherit system; };
in
with pkgs; rec {
default = packages."${system}".default.overrideAttrs (prevAttrs: {
nativeBuildInputs = prevAttrs.nativeBuildInputs ++ (with fenix.packages."${system}".combine; with fenix.packages."${system}"; with pkgs; [
complete.rust-analyzer
complete.rust-src
]) ++ (developmentTools pkgs);
});
});
};
}

3
rust-toolchain.toml Normal file
View File

@ -0,0 +1,3 @@
[toolchain]
channel = "stable"
targets = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"]

40
src/main.rs Normal file
View File

@ -0,0 +1,40 @@
use std::{ffi::CString, ptr::null};
use libseccomp::*;
use nix::libc::EPERM;
fn main() -> anyhow::Result<()> {
env_logger::init();
log::info!("restrict myself by set_no_new_privs...");
nix::sys::prctl::set_no_new_privs()?;
log::info!("create filter context...");
let mut filter = ScmpFilterContext::new_filter(ScmpAction::Errno(EPERM))?;
log::info!("add architecture to filter context...");
filter.add_arch(ScmpArch::X8664)?;
x2t_sandbox_rulegen::generate! {
log::info!("accepting {}", syscall_name);
};
log::info!("load filter into kernel...");
if let Err(err) = filter.load() {
log::error!("failed to load filter into kernel: {err}");
return Err(err.into());
}
let args: Vec<_> = std::env::args().map(|s| CString::new(s).unwrap()).collect();
let command = std::env::args().next().unwrap();
let command = CString::new(command).unwrap();
let env: Vec<CString> = Vec::new();
log::info!("executing {:?}", args);
if let Err(err) = nix::unistd::execve(&command, args.as_slice(), env.as_slice()) {
panic!("failed to execve for {err}");
}
panic!("unreachable");
}

View File

@ -0,0 +1,16 @@
[package]
name = "x2t-sandbox-rulegen"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1"
quote = "1"
nix = "0.27.1"
regex = "1.10.2"

View File

@ -0,0 +1,63 @@
use std::{collections::HashSet, str::FromStr};
use proc_macro::*;
use quote::{quote, format_ident, TokenStreamExt};
#[proc_macro]
pub fn generate(input: TokenStream) -> TokenStream {
let wd = std::path::PathBuf::from_str(&std::env::var("CARGO_MANIFEST_DIR").unwrap()).unwrap();
let syscall_filepath =
wd.join(std::env::var("X2T_SYSCALLS_FILE").unwrap_or("x2t-syscalls.txt".to_string()));
if let Some(syscalls) = option_env!("X2T_SYSCALLS") {
generate_from(input.clone(), syscalls.to_lowercase(), ":").into()
} else if let Ok(syscalls) = std::fs::read_to_string(&syscall_filepath) {
generate_from(input.clone(), syscalls, "\n").into()
} else {
panic!("either specify a X2T_SYSCALLS environment variable with values seperated by colon or write the allowed syscalls line by line into {}", syscall_filepath.to_string_lossy());
}
}
fn generate_from(input: proc_macro::TokenStream, buf: String, sep: &str) -> proc_macro2::TokenStream {
// TODO: improve generate rules to restrict arguments
let mut tokens = Vec::new();
let mut syscalls = HashSet::new();
let raw_syscall_pattern = regex::Regex::new("^\\s*([a-z_][a-z0-9_]*)").unwrap();
let strace_pattern = regex::Regex::new("^\\d+ ([a-z_][a-z0-9_]*)").unwrap();
for s in buf.split(sep) {
// s can be a
// - a name matched by [[:space:]]*(?P<syscall>[a-z_][a-z0-9_]*)
// - strace line matched by [[:digit:]] (?P<syscall>[a-z_][a-z0-9_]*)
for pattern in [&raw_syscall_pattern, &strace_pattern] {
if let Some(capture) = pattern.captures(s) {
let (_, [syscall_name]) = capture.extract();
syscalls.insert(syscall_name.to_string());
break;
}
}
}
let mut syscalls: Vec<String> = syscalls.iter().map(|s| s.to_owned()).collect();
syscalls.sort();
let hook: proc_macro2::TokenStream = input.into();
for syscall_name in syscalls {
let libc_name = format_ident!("SYS_{}", syscall_name);
tokens.push(
quote! {
{
let syscall_nr = nix::libc::#libc_name;
let syscall_name = #syscall_name;
filter.add_rule_conditional(ScmpAction::Allow, syscall_nr as i32, &[])?;
#hook
}
}
);
}
quote! {
#(#tokens);*
}
}

1045
x2t-syscalls.txt Normal file

File diff suppressed because it is too large Load Diff