Re: Out of memory kernel death

Rauli Ruohonen (raulir@fishy.sci.fi)
Thu, 8 May 1997 19:21:47 +0300


On May 05, 1997 at 12:04:20AM, david parsons wrote:

> Well, if the alternative comes down to either having a console session
> die because of a lack of memory or having everything, including that
> console session, come to a screeching stop as the kernel flails around
> looking for memory, I'd think that losing the X server die would be
> by far the better solution.

Yes, and here's what I suggest to be the algorithm ot determine the
process to kill. Comments?

There should be a part of memory reserved for root, this isn't a problem
as many systems have plenty of swap space. No percentages like in ext2, just
a fixed value, ~4 megs? (so that machines with lots of mem+swap won't
get a ridiculous amount of reserved memory)

When allocating memory, this would happen:

(here "free mem"=memory + swap, of course)

1) Check whether free mem > reserved, if yes, alloc normally
2) If not, check whether this is root process. If yes, alloc normally.
3) goto A

So memory can't fill up when root starts X (4 megs) and users start big,
malicious processes. They still cat't get that reserved 4MB :)

This is not enough, of course, the system should work correctly even when
root is not near, and users could start setuid-root processes to fill
that 4MB, so:

A) Find out the process to kill, with some weight function like:
weight=total_size+(alloced_in_last_minute*WEIGHT_VALUE);
if(is_root_process) weight/=USER_BIAS;
else
weight+=count_memory_used_by_this_user's_processes()/CURPROC_BIAS;
B) print a message in logs, what process was killed, whose process that was,
what size,...
C) Kill the process with SIGTERM
D) flag the process with die_you_bastard flag :)
E) if not dead in 5 secs, send SIGKILL

The algorithm's WEIGHT_VALUE and USER_BIAS should be adjustable through
/proc.

This algo has following advantages:

1) malicious user starts a memory-hogger software which just does
"while(1) { malloc(big_number); dirty_the_area; }"
doesn't kill other users' number-crunching processes, because
this one allocated all that memory recently and gets a big weight value
2) if X gets killed, it gets killed with SIGTERM instead of SIGKILL,
and you can recover your display (without GGI ;))
3) there's no way the machine is going to grind to halt, even when root's
not there (because in no-memory situation processes get killed)
4) logs the attempts so root can determine who the scumbag was and lock
his account
5) no root processes will die because of lacking memory (they have that
4 MB in use) For example, if crond would need memory in that situation,
it would not be killed because there's no memory..
6) root runs a program which has an programming error and it mallocs
all memory => it gets killed, and other user processes will not..
If root processes wouldn't ever be killed, all non-root processes would
die first :/
7) user can't fork() 10 processes which allocate 1/10th of the memory
and won't be killed because they use only little amount of memory each

The WEIGHT_VALUE is the parameter which needs the most thinking, because

for(;;) { malloc(4096); dirty_block(); sleep(10); }

and

for(;;) { malloc(40960); dirty_block(); sleep(1); }

have both to be handled 'correctly'.