|
|
|
| |||||||||
![]() |
|
|
«
Previous Thread
|
Next Thread
»
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
#1
|
||||
|
||||
|
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();}"
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.
__________________
FreeBSD Admin Tips Tricks and Scripts |
|
#2
|
||||
|
||||
|
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. |
|
#3
|
|||
|
|||
|
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 |
|
#4
|
||||
|
||||
|
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 |
|
#5
|
|||
|
|||
|
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. |
|
#6
|
||||
|
||||
|
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 |
|
#7
|
|||
|
|||
|
>> 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. |
|
#8
|
||||
|
||||
|
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 |
![]() |
| Viewing: Dev Shed Forums > Operating Systems > BSD Help > Reducing impact of fork bombs on FreeBSD |
| Thread Tools | Search this Thread |
| Display Modes | Rate This Thread |
|
|
|
|