From ecb8492bfa6679cd5ffa1d5e289c2be9095a2671 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sun, 23 Nov 2025 23:05:51 -0600 Subject: [PATCH] checkpoint --- foo.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 foo.c diff --git a/foo.c b/foo.c new file mode 100644 index 00000000..7e0cbd7a --- /dev/null +++ b/foo.c @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Direct syscall wrappers since we're not using libcap +static int capset(cap_user_header_t header, const cap_user_data_t data) { + return syscall(SYS_capset, header, data); +} + +static int capget(cap_user_header_t header, cap_user_data_t data) { + return syscall(SYS_capget, header, data); +} + +void print_capabilities(const char *label) { + struct __user_cap_header_struct header; + struct __user_cap_data_struct data[2]; + + header.version = _LINUX_CAPABILITY_VERSION_3; + header.pid = 0; + + if (capget(&header, data) < 0) { + perror("capget"); + return; + } + + printf("%s:\n", label); + printf(" Permitted: 0x%08x%08x\n", data[1].permitted, data[0].permitted); + printf(" Effective: 0x%08x%08x\n", data[1].effective, data[0].effective); + printf(" Inheritable: 0x%08x%08x\n", data[1].inheritable, data[0].inheritable); + + // Check if CAP_DAC_READ_SEARCH is set + int cap_bit = CAP_DAC_READ_SEARCH; + int word = cap_bit / 32; + int bit = cap_bit % 32; + + if (data[word].effective & (1 << bit)) { + printf(" CAP_DAC_READ_SEARCH is EFFECTIVE\n"); + } else { + printf(" CAP_DAC_READ_SEARCH is NOT effective\n"); + } +} + +void print_ids(const char *label) { + printf("%s: uid=%d euid=%d gid=%d egid=%d\n", + label, getuid(), geteuid(), getgid(), getegid()); +} + +int setup_capabilities() { + struct __user_cap_header_struct header; + struct __user_cap_data_struct data[2]; + + printf("\n=== Setting up capabilities ===\n"); + + // Initialize header + header.version = _LINUX_CAPABILITY_VERSION_3; + header.pid = 0; + + // Get current capabilities + if (capget(&header, data) < 0) { + perror("capget"); + return -1; + } + + print_capabilities("Before setup"); + + // Calculate bit position for CAP_DAC_READ_SEARCH + int cap_bit = CAP_DAC_READ_SEARCH; + int word = cap_bit / 32; // Which 32-bit word (0 or 1) + int bit = cap_bit % 32; // Which bit in that word + + // Set CAP_DAC_READ_SEARCH in permitted, effective, and inheritable + data[word].permitted |= (1 << bit); + data[word].effective |= (1 << bit); + data[word].inheritable |= (1 << bit); + + // Apply the capability set + if (capset(&header, data) < 0) { + perror("capset"); + return -1; + } + + print_capabilities("After capset"); + + // Enable ambient capabilities (survives UID changes) + // PR_CAP_AMBIENT = 47, PR_CAP_AMBIENT_RAISE = 2 + if (prctl(47, 2, CAP_DAC_READ_SEARCH, 0, 0) < 0) { + perror("prctl PR_CAP_AMBIENT_RAISE"); + printf("Warning: Ambient capabilities not supported (kernel < 4.3?)\n"); + } else { + printf("Ambient capabilities set successfully\n"); + } + + // Keep capabilities across setuid + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { + perror("prctl PR_SET_KEEPCAPS"); + return -1; + } + + printf("PR_SET_KEEPCAPS enabled\n"); + + return 0; +} + +int drop_privileges(uid_t target_uid, gid_t target_gid) { + struct __user_cap_header_struct header; + struct __user_cap_data_struct data[2]; + + printf("\n=== Dropping privileges ===\n"); + print_ids("Before drop"); + + // Set GID first (must be done while still root) + if (setgid(target_gid) < 0) { + perror("setgid"); + return -1; + } + + // Drop supplementary groups + if (setgroups(0, NULL) < 0) { + perror("setgroups"); + return -1; + } + + // Set UID + if (setuid(target_uid) < 0) { + perror("setuid"); + return -1; + } + + print_ids("After drop"); + print_capabilities("After UID change (before re-apply)"); + + // Re-apply capabilities after UID change + header.version = _LINUX_CAPABILITY_VERSION_3; + header.pid = 0; + + // Get current capabilities + if (capget(&header, data) < 0) { + perror("capget after setuid"); + return -1; + } + + // Re-enable CAP_DAC_READ_SEARCH in effective set + int cap_bit = CAP_DAC_READ_SEARCH; + int word = cap_bit / 32; + int bit = cap_bit % 32; + + data[word].effective |= (1 << bit); + + if (capset(&header, data) < 0) { + perror("capset after setuid"); + return -1; + } + + print_capabilities("Final capabilities"); + + return 0; +} + +void test_file_access(const char *path) { + printf("\n=== Testing access to: %s ===\n", path); + + struct stat st; + if (stat(path, &st) < 0) { + printf("stat() failed: %s\n", strerror(errno)); + } else { + printf("stat() succeeded! Mode: %o, Owner: %d:%d\n", + st.st_mode & 0777, st.st_uid, st.st_gid); + } + + int fd = open(path, O_RDONLY); + if (fd < 0) { + printf("open() failed: %s\n", strerror(errno)); + } else { + printf("open() succeeded! fd=%d\n", fd); + + char buf[128]; + ssize_t n = read(fd, buf, sizeof(buf) - 1); + if (n > 0) { + buf[n] = '\0'; + printf("Read %zd bytes: %.50s%s\n", n, buf, n > 50 ? "..." : ""); + } + close(fd); + } +} + +int main(int argc, char *argv[]) { + uid_t target_uid = 1000; + gid_t target_gid = 1000; + + if (argc > 1) { + target_uid = atoi(argv[1]); + } + if (argc > 2) { + target_gid = atoi(argv[2]); + } + + printf("CAP_DAC_READ_SEARCH Test Program (without libcap)\n"); + printf("=================================================\n"); + + if (geteuid() != 0) { + fprintf(stderr, "Error: This program must be run as root\n"); + fprintf(stderr, "Usage: sudo %s [target_uid] [target_gid]\n", argv[0]); + return 1; + } + + print_ids("Initial state"); + print_capabilities("Initial capabilities"); + + if (setup_capabilities() != 0) { + fprintf(stderr, "Failed to setup capabilities\n"); + return 1; + } + + if (drop_privileges(target_uid, target_gid) != 0) { + fprintf(stderr, "Failed to drop privileges\n"); + return 1; + } + + printf("\n=== Testing File Access ===\n"); + printf("Now running as uid=%d with CAP_DAC_READ_SEARCH\n", getuid()); + + // Test accessing a root-owned file + printf("\nTrying to access /etc/shadow (normally requires root):\n"); + test_file_access("/etc/shadow"); + + // Test accessing /root (usually 0700) + printf("\nTrying to access /root directory:\n"); + test_file_access("/root"); + + // Provide instructions for custom test + printf("\n=== Custom Test Instructions ===\n"); + printf("To test with your own restricted directory:\n"); + printf("1. Create a test: sudo mkdir -p /tmp/test_restricted\n"); + printf("2. Restrict it: sudo chmod 700 /tmp/test_restricted\n"); + printf("3. Add a file: sudo sh -c 'echo test > /tmp/test_restricted/file.txt'\n"); + printf("4. The program should be able to read it despite permissions\n"); + + if (argc > 3) { + printf("\nTesting custom path: %s\n", argv[3]); + test_file_access(argv[3]); + } + + return 0; +} + +/* + * Compilation (no libcap needed): + * gcc -o cap_test cap_test.c + * + * Usage: + * sudo ./cap_test [target_uid] [target_gid] [optional_test_path] + * + * Example: + * sudo ./cap_test 1000 1000 + * sudo ./cap_test 1000 1000 /tmp/test_restricted/file.txt + */