Re: Linux kernels DoSable by file-max limit

From: elvat_private
Date: Mon Jul 08 2002 - 16:06:01 PDT

  • Next message: Matt Moore: "wp-02-0001: GoAhead Web Server Directory Traversal + Cross Site Scripting"

    
     ('binary' encoding is not supported, stored as-is)
    In-Reply-To: <3D28AA94.8030105at_private>
    
    >Hi,
    >
    >the recently mentioned problem in BSD kernels 
    concerning the global 
    >limit of open files seems to be present in the Linux-
    kernel too. However 
    >as mentioned in the advisory about the BSD specific 
    problem the Linux 
    >kernel keeps some additional file slots reserved for 
    >the root user.
    [...]
    >Greping the source code (2.4.18) reveals that the 
    limit is pretty low:
    >
    >./include/linux/fs.h:#define NR_RESERVED_FILES 10 /* 
    reserved for root */
    >
    >
    >The problem is obviously the checking for superuser 
    privilege in the [*] 
    >line since every user can usually run some setuid 
    binaries like passwd 
    >or su.
    
    hi all,
    
    the obvious solution to this problem is a proper use 
    of setrlimit() (ulimit):
    
    >fddos output:
    
    preforked child 0
    
    
    errno 24 pid 896 got 29 files
    errno 24 pid 897 got 29 files
    errno 24 pid 898 got 29 files
    errno 24 pid 899 got 29 files
    errno 24 pid 900 got 29 files
    errno 24 pid 901 got 29 files
    errno 24 pid 902 got 29 files
    errno 24 pid 903 got 29 files
    errno 24 pid 904 got 29 files
    errno 24 pid 905 got 29 files
    errno 24 pid 906 got 29 files
    errno 24 pid 907 got 29 files
    
    >strace output:
    
    [...]
    
    preforked child 0rt_sigprocmask(SIG_BLOCK, [CHLD], 
    [], 8) = 0
    rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0
    rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
    nanosleep({1, 0}, {1, 0})               = 0
    write(1, "\n\n\n", 3)                   = 3
    fork()                                  = 913
    errno 24 pid 913 got 29 files
    [...]
    fork()                                  = -1 EAGAIN 
    (Resource temporarily unavailable)
    nanosleep({0, 100000000}, NULL)         = 0
    nanosleep({0, 100000000}, NULL)         = 0
    [...]
    
    elvinho ~ $ ulimit -Ha
    core file size        (blocks, -c) 0
    data seg size         (kbytes, -d) 6144
    file size             (blocks, -f) 32768
    max locked memory     (kbytes, -l) unlimited
    max memory size       (kbytes, -m) 1024
    open files                    (-n) 32
    pipe size          (512 bytes, -p) 8
    stack size            (kbytes, -s) 4096
    cpu time             (seconds, -t) 300
    max user processes            (-u) 16
    virtual memory        (kbytes, -v) unlimited
    elvinho ~ $
    
    you can set an ulimit mask in /etc/login.defs
    
    
    in this manner the problem is solved but the kernel
    bug still remains, so two little pieces of code:
    
    --- /usr/src/linux/fs/file_table.c	Mon Sep 17 
    20:16:30 2001
    +++ /usr/src/linux/fs/file_table.c	Mon Jul  8 
    23:42:01 2002
    @@ -51,9 +51,12 @@
     		return f;
     	}
     	/*
    -	 * Use a reserved one if we're the superuser
    +	 * Use one of the first 16 reserved fds if we 
    have euid == 0 
    +	 * and one of the second 16 reserved fds if 
    we're the superuser
     	 */
    -	if (files_stat.nr_free_files && !current-
    >euid)
    +	if (files_stat.nr_free_files > 
    (NR_RESERVED_FILES/2) && !current->euid)
    +		goto used_one;
    +	else if (files_stat.nr_free_files <= 
    (NR_RESERVED_FILES/2) && !current->uid)
     		goto used_one;
     	/*
     	 * Allocate a new one if we're below the 
    limit.
    
    --- /usr/src/linux/include/linux/fs.h	Mon Jul  1 
    14:48:44 2002
    +++ /usr/src/linux/include/linux/fs.h	Tue Jul  9 
    00:07:06 2002
    @@ -65,7 +65,7 @@
     extern int leases_enable, dir_notify_enable, 
    lease_break_time;
     
     #define NR_FILE  8192	/* this can well be larger on 
    a larger system */
    -#define NR_RESERVED_FILES 10 /* reserved for root */
    +#define NR_RESERVED_FILES 32 /* first 16 for euid == 
    0 processes and second 16 only for root */
     #define NR_SUPER 256
     
     #define MAY_EXEC 1
    
    we check if uid == 0 because suid bit cause the 
    kernel to set the egid to the uid/gid of the binary 
    owner:
    
    [...]
                    /* Set-uid? */
                    if (mode & S_ISUID)
                            bprm->e_uid = inode->i_uid;
    [...]
    /usr/src/linux/fs/exec.c line 631 of 1071 (58%)
    
    
    if someone can try to post these patches to the linux 
    kernel ml it would be a good thing.
    
    cheers, elv
    



    This archive was generated by hypermail 2b30 : Wed Jul 10 2002 - 09:35:36 PDT