DF-0783 / ucred_helper.c
/* * DF-0783 setuid-root helper (extended): discover calling process's ucred * address AND dump the full 192-byte ucred to stdout/file. * * Output format: * UCRED_ADDR 0x<addr> * <192 bytes of raw ucred content> * * Build: cc -o ucred_helper ucred_helper.c -lkvm * Install (root): install -o root -m 4511 ucred_helper /usr/local/sbin/ucred_helper */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/sysctl.h> #include <sys/kinfo.h> #include <kvm.h> #define P_UCREDOFF 16 #define UCREDSIZE 192 int main(int argc, char **argv) { kvm_t *kd; struct kinfo_proc *kp; int nprocs; char errbuf[LINE_MAX]; pid_t target; unsigned long proc_addr, ucred_addr; unsigned char buf[UCREDSIZE]; int fd = -1; target = getppid(); if (argc >= 2) target = atoi(argv[1]); if (argc >= 3) { fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); return 1; } } kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); if (kd == NULL) { fprintf(stderr, "ucred_helper: kvm_openfiles: %s\n", errbuf); return 1; } kp = kvm_getprocs(kd, KERN_PROC_PID, target, &nprocs); if (kp == NULL || nprocs < 1 || kp[0].kp_paddr == 0) { fprintf(stderr, "ucred_helper: kvm_getprocs pid=%d failed\n", target); kvm_close(kd); return 1; } proc_addr = (unsigned long)kp[0].kp_paddr; if (kvm_read(kd, proc_addr + P_UCREDOFF, &ucred_addr, sizeof(ucred_addr)) != sizeof(ucred_addr)) { fprintf(stderr, "ucred_helper: kvm_read p_ucred: %s\n", kvm_geterr(kd)); kvm_close(kd); return 1; } if (kvm_read(kd, ucred_addr, buf, UCREDSIZE) != UCREDSIZE) { fprintf(stderr, "ucred_helper: kvm_read ucred: %s\n", kvm_geterr(kd)); kvm_close(kd); return 1; } /* Determine slab zone owning CPU. ZoneSize is 32KB on this guest. * zone_header = ucred & ~(32KB-1). z_Cpu is at offset 4 of SLZone. */ unsigned long zone_hdr = ucred_addr & ~0x7FFFUL; /* 32KB mask */ int z_cpu = -1; if (kvm_read(kd, zone_hdr + 4, &z_cpu, sizeof(z_cpu)) != sizeof(z_cpu)) { /* ignore error */ } fprintf(stderr, "UCRED_ADDR 0x%lx UID %u NGROUPS %u ZONE_CPU %d\n", ucred_addr, (unsigned)*(unsigned *)(buf + 64), (unsigned)*(unsigned short *)(buf + 68), z_cpu); fprintf(stderr, "PROC_ADDR 0x%lx\n", proc_addr); if (fd >= 0) { /* File format: 8-byte ucred addr + 192-byte ucred content */ write(fd, &ucred_addr, sizeof(ucred_addr)); write(fd, buf, UCREDSIZE); close(fd); } else { /* Stdout: addr line + raw bytes */ printf("UCRED_ADDR 0x%lx\n", ucred_addr); fwrite(buf, 1, UCREDSIZE, stdout); } kvm_close(kd); return 0; } |