DF-0037 / leak_xsess.c
/* * DF-0037 PoC - sharper cross-session demonstration. * * Parent (session A) forks a child; the child calls setsid() to create a * brand-new session (session B). The parent then calls getpgid()/getsid() * on the child. POSIX says the parent MUST get EPERM (target is in a * different session). The buggy kernel returns the value. * * Build: cc -o leak_xsess leak_xsess.c * Run: ./leak_xsess (as an unprivileged user) */ #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> int main(void) { pid_t parent_pid = getpid(); pid_t parent_sid = getsid(0); pid_t parent_pgid = getpgid(0); pid_t child; printf("[parent] pid=%d pgid=%d sid=%d uid=%d\n", (int)parent_pid, (int)parent_pgid, (int)parent_sid, (int)getuid()); child = fork(); if (child < 0) { perror("fork"); return 1; } if (child == 0) { /* Child: create a new session, becoming its own session leader. */ if (setsid() < 0) { perror("setsid"); _exit(2); } printf("[child ] pid=%d pgid=%d sid=%d (new session, different uid-parent session)\n", (int)getpid(), (int)getpgid(0), (int)getsid(0)); /* Stay alive so parent can probe us. */ sleep(3); _exit(0); } /* Parent: probe child which is in a DIFFERENT session. */ sleep(1); errno = 0; pid_t c_pgid = getpgid(child); int e_pgid = errno; errno = 0; pid_t c_sid = getsid(child); int e_sid = errno; printf("\n[parent] probing child pid=%d (DIFFERENT session):\n", (int)child); printf(" getpgid(%d) = %d errno=%d (%s)\n", (int)child, (int)c_pgid, e_pgid, strerror(e_pgid)); printf(" getsid(%d) = %d errno=%d (%s)\n", (int)child, (int)c_sid, e_sid, strerror(e_sid)); printf("\n"); if (e_pgid == 0 || e_sid == 0) { printf("BUG DF-0037 REPRODUCED: parent (sid=%d) leaked child's pgid/sid " "from a DIFFERENT session with no EPERM.\n", (int)parent_sid); printf(" POSIX violation: getpgid/getsid on a process in another " "session MUST return EPERM.\n"); } else if (e_pgid == EPERM && e_sid == EPERM) { printf("FIXED: getpgid/getsid returned EPERM for cross-session target.\n"); } else { printf("UNEXPECTED: getpgid errno=%d getsid errno=%d\n", e_pgid, e_sid); } waitpid(child, NULL, 0); return (e_pgid == EPERM && e_sid == EPERM) ? 1 : 0; } |