{"id":22865486,"url":"https://github.com/taoky/greenhook","last_synced_at":"2025-05-05T15:18:49.443Z","repository":{"id":169997466,"uuid":"646102593","full_name":"taoky/greenhook","owner":"taoky","description":"A seccomp-unotify-based syscall hook library for Linux","archived":false,"fork":false,"pushed_at":"2023-11-04T04:15:26.000Z","size":1112,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-01T02:12:16.487Z","etag":null,"topics":["hook","seccomp","syscalls"],"latest_commit_sha":null,"homepage":"http://www.taoky.moe/greenhook/greenhook/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/taoky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-05-27T09:43:54.000Z","updated_at":"2024-09-27T02:14:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"205fe612-0908-4450-9545-11d522030f04","html_url":"https://github.com/taoky/greenhook","commit_stats":null,"previous_names":["taoky/greenhook"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoky%2Fgreenhook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoky%2Fgreenhook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoky%2Fgreenhook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoky%2Fgreenhook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taoky","download_url":"https://codeload.github.com/taoky/greenhook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229538515,"owners_count":18088895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hook","seccomp","syscalls"],"created_at":"2024-12-13T11:37:23.466Z","updated_at":"2024-12-13T11:37:24.261Z","avatar_url":"https://github.com/taoky.png","language":"Rust","readme":"# greenhook\n\nhttps://crates.io/crates/greenhook\n\nGreenhook is a seccomp-unotify-based syscall hook library. It is adapted from \u003chttps://github.com/pdlan/binder\u003e.\n\nYou could have it a try if you want to find alternatives other than `LD_PRELOAD` and `ptrace`. However, please note that seccomp unotify **IS NOT** a full replacement of these techniques, and take some time reading [`seccomp_unotify(2)`](https://man7.org/linux/man-pages/man2/seccomp_unotify.2.html) before you start.\n\nTo fully utilize this library, you need to have a kernel version \u003e= 5.9.0. And also you need [a special seccomp policy file](./assets/seccomp.json) if you want to run this in Docker or other containers (to allow `process_vm_readv()` and `pidfd_getfd()` to run without capabilities), with this:\n\n```console\n# docker run --security-opt seccomp=assets/seccomp.json ...\n```\n\nAlso, it is necessary to install libseccomp header and library:\n\n```\n$ sudo apt install libseccomp-dev\n```\n\n## Example\n\nYou can find some examples inside test code. Here is a simple one that makes programs like `whoami(1)` considering you are root (even if you are not), by hooking `geteuid(2)`:\n\n```rust\nuse std::process::Command;\n\nuse greenhook::{Supervisor, UNotifyEventRequest};\nuse libseccomp::ScmpSyscall;\n\nfn geteuid_handler(req: \u0026UNotifyEventRequest) -\u003e libseccomp::ScmpNotifResp {\n    req.return_syscall(0)\n}\n\nfn main() {\n    env_logger::init();\n    // Get argv[1]\n    let program = std::env::args().nth(1).unwrap();\n    let mut supervisor = Supervisor::new(2).unwrap();\n    supervisor.insert_handler(ScmpSyscall::new(\"geteuid\"), geteuid_handler);\n    let mut cmd = Command::new(program);\n    let (mut child, thread_handle, pool) = supervisor.exec(\u0026mut cmd).unwrap();\n    let _ = Supervisor::wait(\u0026mut child, thread_handle, pool).unwrap();\n}\n```\n\nRun this with:\n\n```console\n\u003e cargo run --example geteuid -- whoami\nroot\n\u003e whoami\nuser\n```\n\nA more complicated one, that replaces `/etc/passwd` to `/etc/resolv.conf` by hooking `openat(2)`:\n\n```rust\nuse std::{process::Command, ffi::CStr, fs::File, os::fd::AsRawFd};\n\nuse greenhook::{Supervisor, UNotifyEventRequest, RemoteProcess};\nuse libseccomp::ScmpSyscall;\nuse log::info;\nuse nix::{unistd::Pid, libc};\n\nfn openat_handler(req: \u0026UNotifyEventRequest) -\u003e libseccomp::ScmpNotifResp {\n    let path = req.get_request().data.args[1];\n    let remote = RemoteProcess::new(Pid::from_raw(req.get_request().pid as i32)).unwrap();\n    let mut buf = [0u8; 256];\n    remote.read_mem(\u0026mut buf, path as usize).unwrap();\n    // debug!(\"open (read from remote): {:?}\", buf);\n    let path = CStr::from_bytes_until_nul(\u0026buf).unwrap();\n    if !req.is_valid() {\n        return req.fail_syscall(libc::EACCES);\n    }\n    info!(\"open (path CStr): {:?}\", path);\n    if path.to_str().unwrap() == \"/etc/passwd\" {\n        // open /etc/resolv.conf instead\n        let file = File::open(\"/etc/resolv.conf\").unwrap();\n        let fd = file.as_raw_fd();\n        let remote_fd = req.add_fd(fd).unwrap();\n        req.return_syscall(remote_fd as i64)\n    } else {\n        unsafe { req.continue_syscall() }\n    }\n}\n\nfn main() {\n    env_logger::init();\n    // Get argv[1..]\n    let args = std::env::args().skip(1).collect::\u003cVec\u003c_\u003e\u003e();\n    if args.len() == 0 {\n        panic!(\"Usage: {} \u003cprogram\u003e [args...]\", std::env::args().nth(0).unwrap());\n    }\n    let mut supervisor = Supervisor::new(2).unwrap();\n    supervisor.insert_handler(ScmpSyscall::new(\"openat\"), openat_handler);\n    let mut cmd = Command::new(args[0].clone());\n    let cmd = cmd.args(\u0026args[1..]);\n    let (mut child, thread_handle, pool) = supervisor.exec(cmd).unwrap();\n    let _ = Supervisor::wait(\u0026mut child, thread_handle, pool).unwrap();\n}\n```\n\nRun this with:\n\n```console\n\u003e RUST_LOG=info cargo run --example openat -- cat /etc/passwd\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/Projects/greenhook/target/debug/deps/glibc-hwcaps/x86-64-v3/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/Projects/greenhook/target/debug/deps/glibc-hwcaps/x86-64-v2/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/Projects/greenhook/target/debug/deps/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/Projects/greenhook/target/debug/glibc-hwcaps/x86-64-v3/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/Projects/greenhook/target/debug/glibc-hwcaps/x86-64-v2/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/Projects/greenhook/target/debug/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/glibc-hwcaps/x86-64-v3/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/glibc-hwcaps/x86-64-v2/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/glibc-hwcaps/x86-64-v3/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/glibc-hwcaps/x86-64-v2/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/home/taoky/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/etc/ld.so.cache\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/usr/lib/libc.so.6\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/usr/lib/locale/locale-archive\"\n[2023-05-27T14:39:57Z INFO  openat] open (path CStr): \"/etc/passwd\"\n# Generated by NetworkManager\n...\n```\n\nSee [`examples/binder.rs`](examples/binder.rs) for a more complicated example. It resembles the logic of \u003chttps://github.com/pdlan/binder\u003e in Rust.\n\n## Limitation\n\n1. Your hook functions are executed by supervisor process (thread), not supervised one! This means that you may find difficulties when you need to do something on behalf of supervised process.\n2. Be careful of TOCTOU attack! Seccomp unotify will NOT stop whole process when handling syscalls, so it is possible that the supervised process may change the syscall arguments after supervisor has checked them, and `continue_syscall` can be dangerous (thus it is marked as `unsafe` here). [Curious about how to exploit this? Check here（简体中文）!](https://github.com/USTC-Hackergame/hackergame2023-writeups/blob/master/official/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%89%93%E5%BC%80%20flag%20%F0%9F%98%A1/README.md)\n3. Handling signals could be troublesome. It is possible that signals can interrupt syscalls or restart them, but supervisor has no knowledge of this. Try to check request validity in your functions to alleviate this problem. For more information please read `seccomp_unotify(2)`.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaoky%2Fgreenhook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaoky%2Fgreenhook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaoky%2Fgreenhook/lists"}