Late 1970s. Two interns are reading system call manuals; we're on a v6 Unix system, running on a PDP-11/45.
Like many bad ideas, it starts with an innocent question: "What happens if we recursively fork?"
Five minutes and a couple of C compiles later, we're sitting at the DEC printing console watching the system panic. The sysadmin comes running in a minute later.
"What did you THINK would happen?"
We explained that we didn't know, and we wanted to find out. He rebooted the system, fixed up a couple of busted inodes with ncheck and clri and so forth (this, children, was in the days before fsck...) and went back to his meeting, grumbling "... (inaudible) interns..."
And that's when I got seriously interested in how kernels worked.
Not exactly the same, but my dad told me the story that when he was in computer-lab in college, it was the first class in his school to have brand new Apple II computers. They drummed into the students' heads "these are not all connected to the central mainframe; if you ever break something, just reboot the computer and everything will be cleared and it'll be fine".
Well, I guess my dad took that as a challenge, and doing something using some weird recursive assembly and trying to reclaim some extra RAM by using the ROM chip (not 100% sure what he was trying to do), he managed to completely brick the machine, permanently breaking it.
Apparently they were pretty pissed at him, but he rebutted with "Well, you guys told me that I couldn't break it just by coding!" I guess they begrudgingly agreed and never tried to make him pay for it or anything like that, but they did announce to the class the next day that apparently you can break the machines, and to not do anything too clever without a professor looking at it.
When I was taking an operating systems class I wrote a fork bomb to play with:
~ $ gcc fork-bomb.c
~ $ ./a.out
I saw that it did indeed crash my lab machine, and when it rebooted I went on with my life.
Our CS lab had a central server which served a lot of important functions and also was the terminal server you could SSH into when working from your dorm. All of these had shared home directories.
Late one night working from my dorm before a big project was due I ran:
I believe that nproc limits are only useful against accidents. In particular the following shell script is very good at taking out systems no matter what limits you set.
If you prevent it from taking out all of the process spots, it still is going to wipe out your memory. If you set paranoid enough limits on both memory and process spots, the system is going to be unusable for normal use cases.
There is no API for that currently. And there is pressure to not add new complications around memory management because allocating memory is so often called that it affects the performance of everything.
Classic stuff. So I'll just remove the eval and subshell and let echo through to uudecode so I can see what this mess will do.. aaaaaaaand there goes my system.
I'd neglected to see the backquoted strings in the mess. This one had some layers!
Story time: I once worked part time with a company, and their DBA was doing a project to look up all the IP addresses that had been logged into one of their database tables. For every address he was running a bash script to do the reverse lookup.
This was going to take a few days to run, largely because it was forking 10-20 times for every IP address, most of the lookups themselves were fairly quick (though some weren't). I explained to him that forks are fairly expensive operations, and every line in his shell script was 1+ forks.
I thought this would be an easy win, I picked up a multi-threaded DNS lookup tool and showed him that it could look up a thousand addresses in < a second. "Oh, so I can just replace the "nslookup" with this other program in my script?"
I explained that he would need to make a file with all the IP addresses he needed to look up, I'd run the program on a server at our data center (to not clog the office T1), and then I'd give him back a file containing "address,name".
"Oh... So I'd have to correlate each address to a name myself? I can't do that, I need to run this script." In my head I said "You're the DBA, how can you NOT correlate this data?"
I worked in a hospital years ago as an IT Tech. I realized one day the printers were not on a separate VLAN. The network guy didn’t seem to care so I wrote a short telnet script to submit a 1000 page (blank) print job to his office printer, flash all the lights and change the display to PC LOAD LETTER. I hit enter and 5 min later sure enough there was a ticket in my queue to diagnose the printer. I killed the script, set the lights to normal and went to his office. Never was able to replicate his complaint...
Replacing his automated process with 2-3 manual steps and with a dependency on you. Yeah, he probably said whatever popped into his mind to make you go away.
In college 20 years ago some student hit "reply all" on some random email to complain about something and thus started a 2 day long chain of emails of people arguing with the person and others yelling at everyone for hitting "reply all" And so thought it was a good idea to reply with a link that said something like "go here to make the emails stop" which was just my picture making a stupid face and some javascript I made that would open 2 more identical windows, then those 2 would execute until something crashed. It was amazing I didn't get in trouble for it and some guy at the 7-11 recognized me. Highlight of my life.
On a lesser scale, I know that some companies have issues with emails that end up being sent up to huge mailing lists ballooning into huge chains when people try to get removed from the list and decide the best way to do so is to reply all to the email.
Working at a big bank in the early 90's we all had Sparks on our desks. If you walked away without your screen locked, you might come back to find 'ls' aliased to a fork bomb or 'rm -rf *' or something else fun. The guy who sat next to me was truly a master. He would start with aliasing cat, more, ls, cd and then alias itself.
The other fun trick was finding someone who had left xhost+ open and while a boss was at their desk, popping open NSFW pictures on their screen in an xv window.
I worked in IT at a hospital where leaving workstations unlocked is a big no-no. Any time my coworkers did so it was standard procedure to do the following:
1) Change all their desktop icons to target shutdown.exe (I had a script on the shared drive for this).
2) Screenshot the desktop, rotate it 180 in paint then set it to the desktop background.
3) Select all the icons on their destop and hide them.
4) Close all the open applications.
5) Hide the task bar.
6) Hit CTRL+ALT+Up Arrow to enter “projector mode” and get the inverted desktop screenshot back to “normal” but completely screwing up mouse movement.
7) Turn the monitor off.
8) Unplug the keyboard and mouse.
Always fun to watch them struggle through the process in reverse just to end up shutting down when trying to open outlook.
I had an internship at a mostly Apple place at one point. Using the mac `say` command with cron or a timeout in the background was a lot of fun.
One of the Linux guys had a script that detected changes to his wallpaper, set it back to the previous one and insulted the person who attempted to change it.
I had a great cron prank that I pulled on the only other linux user at my high school 2 years ago. It made a folder, took a screenshot of his background, moved all of his desktop into said folder, then changed the background to the screenshot. In retrospect, It was probably overkill, but at least he learned to use ctrl+alt+l when sharing a lunch period with another linux enthusiast.
I stopped a few people from doing this much mischief on a couple occasions and substituted minor mischief instead.
A friend and I arrived at changing their .plan or .project to say "I really need to learn to log out when I leave the computer lab." then log them out and amuse ourselves with how long it would take them or their friends to notice.
What I should have done was note the account name and check in from time to time to see how long it took, but I apparently wasn't that forward-looking.
The early Suns had no security on /dev/framebuffer so one could remote into someone else's machine, and run a process that would continuously dump their screen to yours. The LAN was fast enough to get a near-realtime display that would update every few seconds. Obviously one could do the opposite and send NSFW content to the remote screen as well. No need for any XWindows permissions because the hardware layer access was wide open.
They had a similar security issue with /dev/audio where one could "bug" a remote machine and play the audio locally.
We did both of those. We took screen caps of our managers -- the issue with that was that there was a noticeable pause when you were snapping and we were afraid of getting caught.
In terms of audio there was a desk analyst on the MBS trading desk who wrote a script that would play a clip of someone in a thick accent screaming 'You are a stupid man!' on the targeted machine. The traders and analysts did it to each other for a while. When that got boring and they modified the script to play it on all the machines on the MBS trdaing desk, repeatedly. When the head of mortgage research would stop by to speak to one of the traders, someone would quite subtly run the script and every ones machine would start barking 'You are a stupid man!'
Weirdly it never occurred to us to use the microphone.
> The other fun trick was finding someone who had left xhost+ open and while a boss was at their desk, popping open NSFW pictures on their screen in an xv window.
Did this ever end up actually getting someone in trouble? I've worked at a few places where it certainly would.
No. There was some judgement involved. (Also back in those days, there were honestly a lot fewer NSFW images floating around -- this is pre Netscape days.) The goal was to freak people out, not get them (or you) fired.
A new guy was working on a shell script that somehow wound up forking copies of itself. This was in the early 90's on HP workstations that were attached to a cluster server and relied on it for disk and other services, and he was running his script there. All of the connected workstations froze up.
When my workstation locked up, I stood up and heard a commotion coming from his cube. He was on the phone with one of our sysadmins, desperately trying to kill the processes via his non-functional terminal. I asked for the phone, and told the sysadmin (who still had a functioning terminal) to rename "sh" to something else for a second.
Boom! In just a few seconds all of the processes died out.
I said "Thanks", handed the phone back and went back to my cube while he just stared at me slack-jawed.
In those days, I admined SunOS, Solaris, HP-UX, AIX, SCO, FreeBSD, Linux and Windows NT boxes at a nuclear engineering consultancy that had an IPv4 Class C just for an Ethernet LAN. (Heck, I checked the other day and that defunct company still has the this range allocated for no reason whatsoever: https://whois.arin.net/rest/net/NET-206-197-48-0-1 ) Fun fact: the hostnames were names of Simpson characters. :)
It wasn't pid exhaustion...it was tying up too many resources on the server for it to serve the workstation requests. These were HP 9000 Series 300 workstations configured to share the disk on a "cluster server". You could also log into the server and run jobs, and that's what this guy had done. So while the admin still had control through an existing logon window, the rest of us were stopped because the system was wedged with the fork bomb.
My most memorable fork-related cockup was in 1999ish. I was working on a program to purge cache entries from a web server’s front-end proxies when users uploaded or deleted files. At one point I redid the restart/daemonize logic and I got a condition backwards. The result was that when the daemon received a restart signal it went into a loop, repeatedly forking - but it wasn’t a fork bomb: the parent immediately died and the child looped to fork and die, etc., so only one was running at a time.
In most situations this would have been OK, but it was running as root on a production server. So I could not (for example) kill all my processes with kill -9 -1 because that would have killed the machine.
So the pid of my errant program was counting up quite fast. I tried finding it in the output of ps then running while !kill $pid; do :; done for a slightly bigger $pid, hoping that my program would be killed when its pid reached $pid - nope, it won the race, and forked right past the kill loop. I tried rewriting the kill loop in C and the problem program still won the race.
In the end I needed to run several copies of the C kill loop on consecutive pids in order to kill the problem program as it forked through the kill zone. The collateral damage was only a few ftp login attempts...
I did this inadvertently in the 80s on an Encore Multimax, a parallel computer base don NS 32k processors. I was writing a parallel program in assembly that had to call fork() in a loop to spawn a few child processes. I did not realize that register contents are not copied over to the child process after a fork call and the loop counter was in a register. They had to actually power down the system to get it out of this state :-)
Yes, but the way you write child processes is to check the return of fork() and then break out of whatever the parent was doing and go into a child function.
In high school we had access to the Univac 90/70 at the local college. It supported interactive use via dial up terminals and batch jobs. There were exactly two slots in the batch queue. I wrote an assembler program which created a last-chance exit handler and then went to sleep. In the exit handler, it spawned two new copies of itself in the batch queue. Eventually the operator (who wore a NORML pin on his blue jean jacket) noticed a job was stuck in one of the active slots. So he killed it.
Later, he came out of the machine room and asked me to look at something. There were a whole bunch of stalled batch jobs and two jobs sleeping in the active slots. I calmed him down and showed him the equivalent of "kill -9" and promised never to do it again.
I related a story recently about a casual friend who decided to mess with me by using email spam. Instead of learning to do loops in csh, he wrote a recursive variant a lot like what you have here. He had to go to the admin to get back into his account.
My favorite bit was he showed me the code, I saw the problem and rather than telling him how to flood my mailbox properly (because really, who would?) I just said, "You don't want to do that..." and walked away.
Iirc, Champaign-Urbana had a C fork bomb source code spray painted on an underpass wall. I suppose it relied on a passing victim to enter it into their own computer ;)
A Python fork bomb was my first major achievement in college. Four lines of code took out a server. I'd like to claim it was a great achievement in hacking but nope, just trying to grok concurrency and failing hard.
This was a right of passage for CS students when I was in school - to (usually) accidentally write one when trying to implement some server or service. Fortunately most "modern" UNIX systems at our school by then (mid 1990s) had per user process limits so you'd just screw yourself up.
The real issue is even with the limits, when the entire operating systems class was learning about forking it was really easy for a distributed fork bomb to occur.
In my school it was my "Since there are limits and no one can tell me what they are, I can figure them out by counting the number of forks that I did until it blocks" that made our head sysadmin try figuring out how to add the limits
initd also had a habit of killing child processes once the parent dies so even if you lock yourself up you could in theory log out and just wait a while (unless you nohup the process, then you are fucked)
No such luck for the first guy I knew who fork-bombed himself on a Sequent.
I accidentally took down Netcom with a fork bomb in the early 90's. They quickly discovered the problem and had the system back up within about 10 minutes, after which I found that I could no longer log in because they had banned my account.
I called them up and explained that it was an accident, but also asked why they did not enforce quotas on user accounts to prevent such things. They thanked me and re-enabled my account right away.
In college in an OS course about 20 years ago, we tried fork-bomb on HP-UX, AIX, Solaris, Linux and MINIX (2.0)(they have FreeBSD now). On some OSes, it created a boat-load of zombie processes.
Another one was the malloc() bomb (sometimes combining with the fork-bomb to be the malloc-fork-bomb(). On some modern OSes, you have to actually initialize memory to something other than zeroes and keep a pointer to them to prevent aggressive compression and heap compaction.
Finally, running John the Ripper when they still ran NIS and getting the passwords of 26 lecturers and professors in 30 seconds by simply taking the output from getent passwd.
PS: Back in the day, before people lost their minds and over-criminalize nothingburgers, I almost got Aaron Schwartz'ed when I setup a web proxy in the computer lab to access some payware documentation off-campus that was IP locked. Thankfully, they use Postgres instead of Redwood Shores'-ware now.
In college we had a project to implement a shell that supported pipes. All students developed on a school server. This project was famous for students inadvertently fork-bombing the server. Part of the difficulty of this project was writing and testing your code while not fork bombing and working around other students who had.
In the late '90s, I was working for CMU as a programmer and general-purpose janitor for the Andrew system, the campus computing environment. Students frequently worked on a pool of shared machines, particularly for a class like Operating Systems that required Unix. (Yalnix did not run on Linux at the time.) The shared machines had no per-user quota, and generally, abuse wasn't a problem.
But one semester, the OS class added a new first assignment: write a shell. It took about a day or two, but after the second or third accidental fork bomb, a generous per-user process limit was imposed.
Change that `except Exception:` to just a bare `except:` to catch KeyboardInterrupts as well and prevent Ctrl+C from killing any of them while it expands.
But what's your point? You can also be a jerk and do
$ cat nice.sh
rm -rf $HOME
$
In the end the user trusts the program/script to not be harmful. That's why we have the browser platform (which shields programs (aka web apps) from the local file system) and advanced permission management in the popular app stores ("this app wants to access your local file system").
> That's why we have the browser platform (which shields programs (aka web apps) from the local file system) and advanced permission management in the popular app stores ("this app wants to access your local file system").
Don't tell browsers that. Javascript hooks for everything, from your clipboard (hope you don't use a password manager), to Bluetooth (oh you like screaming in your music?), and even your USB devices (is your $HOME mounted over USB?)...
I think everybody discovers, and then has fun with, this in their first Systems course on the shared school servers. In mine I discovered something much more fun: https://linux.die.net/man/1/talk
I found some ascii art of the trollface (https://i.kym-cdn.com/entries/icons/original/000/000/091/Tro...) and saved it to a file, then wrote a script that would find user $1 and infinitely "talk" trollfaces at them, making their terminal completely unusable. Then I'd run it against my friends when we were working in the computer lab :)
Shared Unix systems are rife with prank opportunities
net send in high school was pretty hilarious. leave to go get a book in the library and someone is gonna net send from your terminal something dumb to the whole school. took them forever to turn it off
I wanted to try this out, but I didn't want to kill my daily driver. I fired up a Raspberry Pi 3. perl -e 'fork() while 1;' took it down in about two seconds. I couldn't even switch to a different TTY to kill the processes.
> I couldn't even switch to a different TTY to kill the processes
An interesting technique i've heard is to do:
```
while true; do sleep 10m &; done
```
The goal is to exhaust the PID space, which will cause forking to fail and eventually bring the system back under control.
In grad school some of my lab mates accidentally fork-bombed UT Austin’s entire CS department compute cluster. Someone had written this weird re-entrant shell script that would, depending on arguments, either submit a batch of jobs to the cluster or actually run a job.
Unfortunately the script was called with the wrong arguments, leading to the cluster submitting jobs recursively back to itself until the entire thing went down.
I used to build .bat(ch) scripts that would do this to crash the computers in middle/jr/high school to get out of schoolwork.
With limited computers in the computer lab this was especially efficient if you set them to open, spawn, and replicate on startup. The old systems could barely handle it and would just error out and the cycle continued.
Because deliberately obtuse hn comments do not benefit anyone: line buffers are copied on fork and flushed on exit, so you get two 'choo's. If you add a \n it goes down to just one because it flushes on newline.
This remember me a program I wrote in high school in Pascal.
I think it was like this:
Program Bomb
uses crt,graph;
Var
Graphics,Mode: smallint;
begin
Graphics:=Detect;
Mode:=detectMode;
while(1!=0)
InitGraph(Graphics, Mode,'');
I like fork bombs that actually limit or halt the system. Creating a sub-process of some kind in language X usually boils down to multiple processes getting killed/stalled or - if there is one - a VM to crash. Meh.
> The trick here is that : is used as a function name, which is possible because the colon is not a reserved character in Bash as it is in most other languages.
There is an additional subtlety in that : is the null command, which is being redefined.
I don't believe this is correct. It will just spawn green threads, which are neither system threads nor processes. You'd really want to use syscall.ForkExec: https://golang.org/pkg/syscall/#ForkExec
EDIT: thinking about this further, I don't think that would be right either, as state from the process won't come over with the fork. So maybe there isn't a way?
Correct, it only spawns goroutines. It will still eat as much CPU as possible, but will be much easier to get "a word in edgewise" since it's only one process. Part of why fork bombs are nasty is that the OS scheduler can't tell the processes shouldn't be scheduled as easily as it will tell that a single CPU-bound process should be scheduled out forcibly when its timeslice is up (or whatever exact thing the scheduler is doing).
Also, when the OOM-killer gets around to killing your Go program, it'll take the whole thing down in the single OS process, rather than a fork bomb where you have to get all the processes.
Writing a true Go forkbomb is actually a bit harder, because as with many such runtimes designed from top-to-bottom around the idea of having a lot of threads, "fork" is not readily available. It's generally not meaningful to fork a highly multi-threaded program. The closest you could get would be to repeatedly execute /proc/self/exe over and over, which will come close, but probably still somewhat slower.
Like many bad ideas, it starts with an innocent question: "What happens if we recursively fork?"
Five minutes and a couple of C compiles later, we're sitting at the DEC printing console watching the system panic. The sysadmin comes running in a minute later.
"What did you THINK would happen?"
We explained that we didn't know, and we wanted to find out. He rebooted the system, fixed up a couple of busted inodes with ncheck and clri and so forth (this, children, was in the days before fsck...) and went back to his meeting, grumbling "... (inaudible) interns..."
And that's when I got seriously interested in how kernels worked.