feat: initial impl of NSA

This commit is contained in:
sevki 2024-03-17 17:47:21 +00:00 committed by Sevki
parent 9ec5b14306
commit 8103309419
14 changed files with 140 additions and 100 deletions

View file

@ -1,60 +0,0 @@
# Sample workflow for building and deploying a mdBook site to GitHub Pages
#
# To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html
#
name: Deploy mdBook site to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
env:
MDBOOK_VERSION: 0.4.36
steps:
- uses: actions/checkout@v4
- name: Install mdBook
run: |
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
rustup update
cargo install --version ${MDBOOK_VERSION} mdbook
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
- name: Build with mdBook
run: mdbook build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./book
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

2
.gitignore vendored
View file

@ -1 +1,3 @@
docs/book
target
openat

11
Cargo.lock generated
View file

@ -3,5 +3,14 @@
version = 3
[[package]]
name = "okrust"
name = "libc"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "nosey_syscall_auditor"
version = "0.1.0"
dependencies = [
"libc",
]

View file

@ -1,8 +1,11 @@
[package]
name = "okrust"
name = "nosey_syscall_auditor"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "nsa"
crate-type = ["cdylib"]
[dependencies]
libc = "0.2.153"

8
Makefile Normal file
View file

@ -0,0 +1,8 @@
all: test_openat
test_openat: test_openat.c
$(CC) $(CFLAGS) -o openat test_openat.c
clean veryclean:
$(RM) Hello

View file

@ -1,10 +1,13 @@
<img src="docs/src/okRust.png" width="200" height="200" alt="okRust logo">
<img src="nsa.png" width="200" height="200" alt="Nosey Syscall Auditor">
# okRust
# Nosey Syscall Auditor
okrust is the template for new rust projects within oknotok.computer.
NSA, a tortured backronym for Nosey Syscall Auditor, is a simple tool to audit system calls made by a process.
It has some opinionated defaults, like using:
- mdBook for documentation
- release please for releases
- github actions for CI/CD
I'm sorry. I couldn't resist.
## Usage
```bash
LD_PRELOAD=./nsa.so make all
```

View file

@ -1,5 +0,0 @@
[book]
authors = ["sevki"]
language = "en"
multilingual = false
src = "docs/src"

View file

@ -1,3 +0,0 @@
# Summary
- [Intro](intro.md)

View file

@ -1,10 +0,0 @@
# okRust
<img src="okRust.png" width="200" height="200" align="right" alt="okRust logo">
okrust is the template for new rust projects within oknotok.computer.
It has some opinionated defaults, like using:
- mdBook for documentation
- release please for releases
- github actions for CI/CD

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

BIN
nsa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 KiB

3
rust-toolchain Normal file
View file

@ -0,0 +1,3 @@
[toolchain]
channel = "1.76"
components = [ "rustfmt", "rust-src", "cargo", "clippy" ]

View file

@ -1,14 +1,91 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
//! ![NSA](https://raw.githubusercontent.com/sevki/nsa/master/nsa.png)
//!
//! # NSA: Nosey Syscall Abstractions
//!
//! NSA is a library that allows you to intercept and log system calls.
//! It uses the `dlsym` function to get the address of the original function and then calls it. This is a simple way to intercept and log system calls.
//!
//! ## Usage
//!
//! ```shell
//! cargo build --release
//! LD_PRELOAD=./target/release/nsa.so make
//! ```
// set docs rs logo and favicon
#![doc(html_logo_url = "https://raw.githubusercontent.com/sevki/nsa/master/nsa.png")]
#![doc(html_favicon_url = "https://raw.githubusercontent.com/sevki/nsa/master/nsa.png")]
use libc::c_char;
use std::ffi::CStr;
macro_rules! wrap_syscall {
($func_name:ident, $($arg_name:ident: $arg_type:ty),*) => {
/// # Safety
///
/// These functinos are inherently unsafe as they are calling system calls.
///
#[no_mangle]
pub unsafe extern "C" fn $func_name($($arg_name: $arg_type),*) -> i32 {
let orig_func: unsafe extern "C" fn($($arg_type),*) -> i32 =
unsafe { std::mem::transmute(libc::dlsym(libc::RTLD_NEXT, concat!(stringify!($func_name), "\0").as_ptr() as *const i8)) };
println!("Intercepted {}", stringify!($func_name));
println!("Arguments: ");
$(
println!(" {} {}: {}", stringify!($func_name), stringify!($arg_name), {
// check argtype is *const c_char
if stringify!($arg_type) == "*const c_char" {
if let Some(s) = unsafe { ($arg_name as *const c_char).as_ref() } {
let string = unsafe { CStr::from_ptr(s).to_string_lossy() };
format!("{:?}", string)
} else {
format!("{:?}", $arg_name)
}
} else {
format!("{:?}", $arg_name)
}
});
)*
let result = orig_func($($arg_name),*);
println!("Original {} returned {}", stringify!($func_name), result);
result
}
};
($func_name:ident) => {
#[no_mangle]
pub unsafe extern "C" fn $func_name() -> i32 {
let orig_func: unsafe extern "C" fn() -> i32 =
unsafe { std::mem::transmute(libc::dlsym(libc::RTLD_NEXT, concat!(stringify!($func_name), "\0").as_ptr() as *const i8)) };
println!("Intercepted {}", stringify!($func_name));
let result = orig_func();
println!("Original {} returned {}", stringify!($func_name), result);
result
}
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
// open
wrap_syscall!(open, path: *const c_char, flags: i32, mode: i32);
// openat
wrap_syscall!(openat, dirfd: i32, path: *const c_char, flags: i32, mode: i32);
// execve
wrap_syscall!(execve, path: *const c_char, argv: *const *const c_char, envp: *const *const c_char);
// access
wrap_syscall!(access, pathname: *const c_char, mode: i32);
// uname
wrap_syscall!(uname, buf: *mut libc::utsname);
// getuid
wrap_syscall!(getuid);
// getpid
wrap_syscall!(getpid);
// getppid
wrap_syscall!(getppid);
// fork
wrap_syscall!(fork);

13
test_openat.c Normal file
View file

@ -0,0 +1,13 @@
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int fd = openat(AT_FDCWD, "Cargo.toml", O_RDONLY);
if (fd == -1) {
perror("openat");
return 1;
}
close(fd);
return 0;
}