#1
  1. funky munky
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jul 2001
    Location
    UK
    Posts
    1,446
    Rep Power
    15

    Reducing impact of fork bombs on FreeBSD


    I have recently been stretching my bsd system to see what sort of abuse it can put up with and with help from a friend managed to kill the box in spectacular fashion on one occasion.

    The issue now is this - how to stop a user from forking multiple processes in rapid succession or abusing the stack by overflowing it on a FreeBSD 4.4 system with such code as:
    Code:
    perl -e "while(1){fork();}"
    in perl or
    Code:
    #include <stdlib.h>
    
    void evil(long bleh, long bleh2, long bleh4, long bleh3){
            fork();
            evil(bleh, bleh2, bleh3, bleh4);
    }
    
    void main(void){
            evil(1, 2, 3, 4);
    }
    or
    Code:
    void main(void){
            __asm__("bleh:");
            __asm__("push %eax");
            __asm__("jmp bleh");
    }
    in C.

    I have attempted to define specific login class restrictions on both stack size and max process limits, but to no avail. The machine still balks very nastily when such a limit is imposed:
    Code:
    # /etc/login.conf
    default:\
            :passwd_format=md5:\
            :copyright=/etc/COPYRIGHT:\
            :welcome=/etc/motd:\
            :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,FTP_PASSIVE_MODE=YES:\
            :path=/sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin /usr/X11R6/bin ~/bin:\
            :nologin=/var/run/nologin:\
            :stacksize=1m:
            :maxproc=64:
    When the above perl forkbomb is executed, the above maxproc param seemingly has no effect and similarly when the stack overflow is run the stacksize limit seems to have no effect.

    Is this the best way to minimise the impact of fork bombs and such like, or is a kernel rebuild in order?

    Many thanks in advance,
    Jez

    PS My system specs viz-a-viz mem are minimal as well, 32mb ram, plus my /proc assignment is only 4k - although looking at a freebsd 5 system I have access to I found the same /proc size.
  2. #2
  3. funky munky
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jul 2001
    Location
    UK
    Posts
    1,446
    Rep Power
    15
    Apologies - have just noticed the typo in the second to last line of the login.conf file (missing '\' continuation char).
    Login class restrictions work as expected in restricting stack and proc limits.
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2001
    Posts
    4
    Rep Power
    0
    You shouldn't alter the default class just to stop someone from using up your limit.
    Have a look at this -> http://www.freebsd-howto.com/HOWTO/Login-Class-HOWTO
  6. #4
  7. funky munky
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jul 2001
    Location
    UK
    Posts
    1,446
    Rep Power
    15
    Hi freebsd, hope you're well...

    Thanks for the post - I'm paying for this online time right now so will keep it brief.

    At the time I posted I was baffled as to why it wasn't working and quite amazed at the ease with which a malicious user could kill the system outright (certainly on my machine anyway with only 32mb ram and v. little vmem) - as such I was just modifying the default login class to see what would work. I was a bit miffed that I hadn't noticed that typo within 5 minutes - such is life, live and learn, debug, debug, debug.

    As you correctly mention changing the default class is not good - not least because the entry for root's login class is like this at the moment:
    Code:
    root:\
            :ignorenologin:\
            :idletime=infinity:
            :tc=default:
    and as such root / uid 0 accnts will be limited in ways which are not perhaps desirable.

    I'll setup a separate login class for 'site' users (ie users logging in via sshd) and organize things that way.

    Many thanks for the link also - I will download that and peruse offline.

    Best Regards,
    Jez
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2001
    Posts
    4
    Rep Power
    0
    You should have a look at LINT as there are many adjustable values in limit.
    Also avoid running inetd if at all possible. A good replacement is tcpserver, where you can adjust the limit for individual daemon running via tcpserver. Here is an example of sshd run script:
    Code:
    #!/bin/sh
    PATH=/usr/local/bin:/usr/bin:/bin 
    export PATH
    exec softlimit -m 409600 \
    tcpserver -vRpl0 -x root/ssh.cdb \
    -c5 -u0 -g0 0 22 /usr/sbin/sshd -eiD4 2>&1
    -c is to control number of connection
    -m controls the data segment, stack segment, physical pages, and all other segments.
  10. #6
  11. funky munky
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jul 2001
    Location
    UK
    Posts
    1,446
    Rep Power
    15
    Code:
    #!/bin/sh
    PATH=/usr/local/bin:/usr/bin:/bin 
    export PATH
    exec softlimit -m 409600 \
    tcpserver -vRpl0 -x root/ssh.cdb \
    -c5 -u0 -g0 0 22 /usr/sbin/sshd -eiD4 2>&1
    Ah this is a good idea - so essentially by this method anyone logging in via sshd would be limited to a mem limit of 409600 bytes? Good heads up.

    I installed djb's UCSPI suite a while ago, although I must admit I still have to configure swat, sshd and ftpd to run via tcpserver instead of via inetd (still to install qmail/djbdns!). I'm still unsure about exactly how I run these correctly via tcpserver - for sshd, would I simply place the above script you mentioned in /usr/local/etc/rc.d/ and run it as a sys init service similarly to apache/mysql/samba etc?

    Thanks in advance,
    Jez
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2001
    Posts
    4
    Rep Power
    0
    >> anyone logging in via sshd would be limited to a mem limit

    Yes. softlimit is actually a program to assign hard limit on the program (sshd, not tcpserver).

    >> would I simply place the above script you mentioned in /usr/local/etc/rc.d/

    No. In addition to tcpserver you also need to install daemontools and use its supervise program. djb recommended mkdir a /service directory and symlink the dir where you need it to be monitored by supervise. LWQ uses a non-standard dir of /var/qmail/supervise, so it doesn't make sense to mkdir /var/qmail/supervise/sshd when sshd has nothing to do with qmail. What I usually do is to mkdir a /var/djb directory as the base directory and mkdir other directories like ftp, ssh, socks5, dnscache, or so under /var/djb.
    Here is the ls -Al of /var/djb:
    Code:
    drwxr-xr-t  5 root  wheel  512 Jan 17 19:29 ssh
    And /var/djb/ssh:
    Code:
    drwxr-sr-x  4 root  wheel  512 Jan 17 01:11 log
    drwxr-sr-x  2 root  wheel  512 Mar 10 14:31 root
    -rwxr-xr-x  1 root  wheel  145 Feb 16 11:33 run
    /var/djb/ssh/log:
    Code:
    drwxr-sr-x  2 sshlog  sshlog  512 Feb 23 16:01 main
    -rwxr-xr-x  1 root    wheel   139 Jan 17 03:58 run
    /var/djb/ssh/root:
    Code:
    -rw-r--r--  1 root  wheel  1312 Mar 10 14:30 ssh
    -rw-r--r--  1 root  wheel  4826 Mar 10 14:30 ssh.cdb
    When you are ready to launch sshd under supervise, just:
    1) cd /service
    2) ln -sf /var/djb/ssh ssh
    3) it will be started in 5 seconds

    To have supervise starting automatically on bootup you need to write a script (not the run script) and place it to /usr/local/etc/rc.d/. Here is an example of /usr/local/etc/rc.d/svscan.sh:
    Code:
    #!/bin/sh
    
    case "$1" in
            start)  if [ -f /var/run/svscan.pid ]; then
                            echo 'svscan already running'
                    else
                            cd /service
                            env - PATH="/service:/usr/local/bin:/usr/bin:/bin" \
                            /usr/local/bin/svscan &
                            echo $! > /var/run/svscan.pid
                            echo -n ' svscan'
                    fi
                    ;;
            stop)   if [ -f /var/run/svscan.pid ]; then
                            kill `cat /var/run/svscan.pid`
                            /usr/local/bin/svc -dx /service/* /service/*/log
                            rm -f /var/run/svscan.pid
                            echo -n ' svscan'
                    else
                            touch /var/run/svscan.pid
                            /usr/local/bin/svc -dx /service/* /service/*/log
                            rm -f /var/run/svscan.pid
                            echo -n ' svscan'
                    fi
                    ;;
            stat)           /usr/local/bin/svstat /service/* /service/*/log
                    ;;
      hup|reload)  if [ -f /var/run/svscan.pid ]; then
                            /usr/local/bin/svc -d /service/* /service/*/log
                            /usr/local/bin/svc -u /service/* /service/*/log
                            echo 'svscan restarted'
                    else
                            $0 start
                    fi
                    ;;
      hup-ssh)  if [ -f /var/run/svscan.pid ]; then
                            /usr/local/bin/svc -d /service/ssh /service/ssh/log
                            /usr/local/bin/svc -u /service/ssh /service/ssh/log
                            echo 'ssh restarted'
                    else
                            $0 start
                    fi
                    ;;
         ssh-log)  if [ -f /var/run/svscan.pid ]; then
                            /usr/local/bin/svc -d /service/ssh/log
                            /usr/local/bin/svc -u /service/ssh/log
                            echo "ssh-log restarted"
                    else
                            $0 start
                    fi
                    ;;
            ssh)   if [ -f /var/run/svscan.pid ]; then
                            cd /service/ssh/root
                            tcprules ssh.cdb ssh.tmp < ssh
                            echo 'ssh.cdb rebuilt'
                            rsync -e ssh -az . root@192.168.0.2:/service/ssh/root
                            rsync -e ssh -az . root@192.168.0.3:/service/ssh/root
                            rsync -e ssh -az . root@192.168.0.4:/service/ssh/root
                    else
                            /usr/local/bin/svscan /service &
                            echo $! > /var/run/svscan.pid
                            sleep 6
                            $0 ssh
                    fi
                    ;;
            *)
                    echo "Usage: $0 option
    option:
            start | stop | stat | hup | reload | ssh | hup-ssh | ssh-log |"
            exit 1
    esac
    exit 0
    You only need start|stop for your svscan.sh script. But I symlink'ed svscan.sh to /usr/local/sbin/djb script so I can run djb hup-ssh plus many other hup-ftp, hup-smtp or so that I have removed in the script as shown above.

    What's that ssh-log for?
    That's to restart just /service/ssh/log when /service/ssh/log/run script has been modified and I want the changes to take affect immediately without restarting sshd globally.
    That djb ssh is to rebuild that ssh.cdb database and rsync it to my 3 other boxes in one go.

    The log file of sshd resides at /var/djb/ssh/log/main/current. To make reading the latest ssh log easier, you can create a symlink of that current file to /var/log/ssh_log so you don't have to cd to 5 dir level deep.
  14. #8
  15. funky munky
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jul 2001
    Location
    UK
    Posts
    1,446
    Rep Power
    15
    Fantastic - excellent reply. I couldn't find a lot of info at djb's site, http://cr.yp.to about the UCSPI tcp suite - at least not through the links - ie running daemons using the supervise daemontool. However I just mirrored parts of the site and found references to the daemontools plus a lot of excellent info on various other issues.

    I'm currently cvsupping my ports tree to make sure I grab the latest daemontools, so once I've installed them I'll set about configuring the daemontools to supervise and log for sshd.

    Many thanks again,
    Jez

IMN logo majestic logo threadwatch logo seochat tools logo