mirror of
https://github.com/domcyrus/rustnet.git
synced 2026-05-13 15:29:27 -05:00
Pin CI actions to commit SHAs, add Npcap checksum verification (#210)
- Pin all GitHub Actions to full commit SHAs across workflows - Add SHA256 verification for Windows Npcap SDK download in build.rs - Add supply chain security and sandboxing documentation to SECURITY.md - Add sha2 build-dependency for Windows
This commit is contained in:
@@ -15,7 +15,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
|
||||
- name: Checkout repository
|
||||
if: matrix.arch != 'aarch64'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ inputs.version }}
|
||||
|
||||
|
||||
@@ -68,14 +68,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Setup Linux dependencies
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
uses: ./.github/actions/setup-linux-deps
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@stable # unpinned: maintained branch by Rust team member
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
components: rustfmt
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
# For test builds: upload raw binary
|
||||
- name: Upload binary artifact
|
||||
if: ${{ !inputs.create-archives }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: rustnet-${{ matrix.build }}
|
||||
path: target/${{ matrix.target }}/release/rustnet${{ contains(matrix.os, 'windows') && '.exe' || '' }}
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
|
||||
- name: Upload release archive
|
||||
if: ${{ inputs.create-archives }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: build-${{ matrix.target }}
|
||||
path: ${{ env.ASSET }}
|
||||
@@ -179,7 +179,7 @@ jobs:
|
||||
# x86_64: use standard checkout action
|
||||
- name: Checkout repository
|
||||
if: matrix.arch == 'x86_64' || matrix.arch == 'x86_64-android' || matrix.arch == 'armv7-android' || matrix.arch == 'x86-android'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
# aarch64: JS actions don't work in Alpine containers on ARM runners
|
||||
- name: Checkout repository (ARM workaround)
|
||||
@@ -312,7 +312,7 @@ jobs:
|
||||
- name: Upload binary artifact
|
||||
if: ${{ !inputs.create-archives }}
|
||||
continue-on-error: ${{ matrix.arch != 'x86_64' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: rustnet-linux-static-${{ matrix.arch }}
|
||||
path: ${{ (matrix.arch == 'armv7-android' && 'target/armv7-unknown-linux-musleabihf/release/rustnet') || (matrix.arch == 'x86-android' && 'target/i686-unknown-linux-musl/release/rustnet') || 'target/release/rustnet' }}
|
||||
@@ -339,7 +339,7 @@ jobs:
|
||||
# JS actions don't work in Alpine containers on ARM runners;
|
||||
# release.yml has dedicated upload-arm-static/upload-android-static jobs as fallback
|
||||
continue-on-error: ${{ contains(matrix.arch, 'aarch64') }}
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: build-${{ matrix.target }}
|
||||
path: rustnet-${{ inputs.version }}-${{ matrix.target }}.tar.gz
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -18,14 +18,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
||||
|
||||
- name: Log in to Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
- name: Generate artifact attestation
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/attest-build-provenance@v4
|
||||
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
pkg-config
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@stable # unpinned: maintained branch by Rust team member
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
@@ -185,7 +185,7 @@ jobs:
|
||||
dput ${{ env.PPA }} ${CHANGES_FILE}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: ppa-source-${{ matrix.ubuntu_release }}
|
||||
path: |
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
sudo apt-get install -y libpcap-dev libelf-dev zlib1g-dev clang llvm pkg-config
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@stable # unpinned: maintained branch by Rust team member
|
||||
|
||||
- name: Publish to crates.io
|
||||
env:
|
||||
|
||||
@@ -50,10 +50,10 @@ jobs:
|
||||
needs: build
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
@@ -210,7 +210,7 @@ jobs:
|
||||
|
||||
- name: Checkout repository
|
||||
if: matrix.arch != 'aarch64'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Install common dependencies
|
||||
run: |
|
||||
@@ -439,10 +439,10 @@ jobs:
|
||||
needs: create-release
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
@@ -450,7 +450,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-linux-deps
|
||||
|
||||
- name: Install Rust and tools
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@stable # unpinned: maintained branch by Rust team member
|
||||
with:
|
||||
targets: x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf
|
||||
components: rustfmt
|
||||
@@ -537,7 +537,7 @@ jobs:
|
||||
target: aarch64-apple-darwin
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Install packaging tools
|
||||
run: |
|
||||
@@ -546,7 +546,7 @@ jobs:
|
||||
brew install create-dmg
|
||||
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: build-${{ matrix.target }}
|
||||
path: artifacts
|
||||
@@ -652,7 +652,7 @@ jobs:
|
||||
target: x86_64-pc-windows-msvc
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Install dependencies
|
||||
shell: powershell
|
||||
@@ -672,7 +672,7 @@ jobs:
|
||||
Write-Host "::endgroup::"
|
||||
|
||||
- name: Install Rust and tools
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@stable # unpinned: maintained branch by Rust team member
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
@@ -683,7 +683,7 @@ jobs:
|
||||
cargo wix --version
|
||||
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: build-${{ matrix.target }}
|
||||
path: artifacts
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libpcap-dev libelf-dev zlib1g-dev clang llvm pkg-config
|
||||
- name: Check formatting
|
||||
@@ -56,11 +56,11 @@ jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
||||
- name: Build Docker image
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
update-oui:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Download latest IEEE OUI database
|
||||
run: |
|
||||
|
||||
Generated
+1
@@ -2365,6 +2365,7 @@ dependencies = [
|
||||
"ring",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"simplelog",
|
||||
"windows",
|
||||
"zip",
|
||||
|
||||
@@ -75,6 +75,7 @@ clap_mangen = "0.2"
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
http_req = "0.14"
|
||||
zip = "8.3"
|
||||
sha2 = "0.10"
|
||||
windows = { version = "0.62", features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_NetworkManagement_IpHelper",
|
||||
|
||||
+30
@@ -12,6 +12,7 @@ RustNet processes untrusted network data, making defense-in-depth security criti
|
||||
- [Log File Privacy](#log-file-privacy)
|
||||
- [eBPF Security](#ebpf-security)
|
||||
- [Threat Model](#threat-model)
|
||||
- [Supply Chain Security](#supply-chain-security)
|
||||
- [Audit and Compliance](#audit-and-compliance)
|
||||
- [Reporting Security Issues](#reporting-security-issues)
|
||||
|
||||
@@ -201,6 +202,35 @@ When using eBPF for enhanced process detection (default on Linux):
|
||||
- Physical access to the machine enables packet capture
|
||||
- Network-level attacks (RustNet is a monitoring tool, not a security appliance)
|
||||
|
||||
### Sandboxing as Root
|
||||
|
||||
Both Landlock (Linux) and Seatbelt (macOS) enforce restrictions even when RustNet runs as root (UID 0). Once applied, the sandbox cannot be reversed from within the process — Landlock sets `PR_SET_NO_NEW_PRIVS` which is irreversible per-process.
|
||||
|
||||
However, sandboxing does **not** protect against supply chain attacks. A compromised binary would simply not apply the sandbox. Root can also:
|
||||
- Pass `--no-sandbox` to skip sandboxing entirely
|
||||
- Unload the Landlock LSM kernel module
|
||||
- Disable SIP on macOS (which controls sandbox enforcement)
|
||||
- Use `ptrace` to modify a running process
|
||||
|
||||
For this reason, running with fine-grained capabilities (`setcap cap_net_raw=eip`) is strongly preferred over running as root.
|
||||
|
||||
## Supply Chain Security
|
||||
|
||||
RustNet takes the following measures to protect against supply chain attacks:
|
||||
|
||||
- **Dependency lockfile**: `Cargo.lock` is committed to the repository, pinning all transitive dependency versions and recording source checksums. This prevents silent version upgrades.
|
||||
- **Security audit**: `cargo audit` runs in CI on every push and pull request, checking dependencies against the RustSec Advisory Database.
|
||||
- **CI action pinning**: All GitHub Actions are pinned by commit SHA (not tags), preventing tag-rewriting attacks on upstream actions.
|
||||
- **Conservative dependency policy**: New dependencies require justification and are reviewed for maintenance status and security track record (see `CONTRIBUTING.md`).
|
||||
- **Build-time integrity**: The Windows Npcap SDK download in `build.rs` is verified against a hardcoded SHA256 checksum.
|
||||
- **Code signing**: macOS releases are signed with an Apple Developer certificate and notarized.
|
||||
- **Checksum verification**: All packaging workflows (Homebrew, Chocolatey, AUR) calculate and double-verify SHA256 checksums before publishing.
|
||||
|
||||
### Limitations
|
||||
|
||||
- `cargo install rustnet` fetches the latest compatible versions from crates.io and does **not** use `Cargo.lock`. Users building from source should verify the source tarball checksum.
|
||||
- Build scripts (`build.rs`) and proc-macros execute arbitrary code at compile time. While all current dependencies are well-established crates, this is an inherent risk of the Rust build model.
|
||||
|
||||
## Audit and Compliance
|
||||
|
||||
For production environments:
|
||||
|
||||
@@ -80,6 +80,7 @@ fn generate_assets() -> Result<()> {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn download_windows_npcap_sdk() -> Result<()> {
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{
|
||||
fs,
|
||||
io::{self, Write},
|
||||
@@ -89,15 +90,18 @@ fn download_windows_npcap_sdk() -> Result<()> {
|
||||
|
||||
// get npcap SDK
|
||||
const NPCAP_SDK: &str = "npcap-sdk-1.15.zip";
|
||||
const NPCAP_SDK_SHA256: &str =
|
||||
"52c7b9fb4abee3ad9fe739bb545c3efe77b731c8e127122bdf328eafdae3ed4f";
|
||||
|
||||
let npcap_sdk_download_url = format!("https://npcap.com/dist/{NPCAP_SDK}");
|
||||
let cache_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?).join("target");
|
||||
let npcap_sdk_cache_path = cache_dir.join(NPCAP_SDK);
|
||||
|
||||
let npcap_zip = match fs::read(&npcap_sdk_cache_path) {
|
||||
// use cached
|
||||
// use cached (verify checksum)
|
||||
Ok(zip_data) => {
|
||||
eprintln!("Found cached npcap SDK");
|
||||
verify_npcap_checksum(&zip_data)?;
|
||||
zip_data
|
||||
}
|
||||
// download SDK
|
||||
@@ -108,6 +112,9 @@ fn download_windows_npcap_sdk() -> Result<()> {
|
||||
let mut zip_data = vec![];
|
||||
let _res = http_req::request::get(npcap_sdk_download_url, &mut zip_data)?;
|
||||
|
||||
// verify checksum before caching
|
||||
verify_npcap_checksum(&zip_data)?;
|
||||
|
||||
// write cache
|
||||
fs::create_dir_all(cache_dir)?;
|
||||
let mut cache = fs::File::create(npcap_sdk_cache_path)?;
|
||||
@@ -117,6 +124,21 @@ fn download_windows_npcap_sdk() -> Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
fn verify_npcap_checksum(data: &[u8]) -> Result<()> {
|
||||
let hash = Sha256::digest(data);
|
||||
let actual = hash.iter().map(|b| format!("{b:02x}")).collect::<String>();
|
||||
if actual != NPCAP_SDK_SHA256 {
|
||||
anyhow::bail!(
|
||||
"Npcap SDK checksum mismatch!\n Expected: {}\n Actual: {}\n\
|
||||
The downloaded file may be corrupted or tampered with.",
|
||||
NPCAP_SDK_SHA256,
|
||||
actual
|
||||
);
|
||||
}
|
||||
eprintln!("Npcap SDK checksum verified: {actual}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// extract libraries based on target architecture
|
||||
let target = env::var("TARGET").unwrap_or_else(|_| "unknown".to_string());
|
||||
let (packet_lib_path, wpcap_lib_path) = if target.contains("aarch64") {
|
||||
|
||||
Reference in New Issue
Block a user