Messages in this thread Patch in this message | | | Date | Tue, 11 May 2004 23:50:27 +0400 | From | Stas Sergeev <> | Subject | Bug in VM accounting code, probably exploitable |
| |
Hello.
As far as I know, if overcommit is disabled, the OOM kill should never happen. It seems to be the bug in the linux kernel though (any version I think, probably also including 2.4.x), which makes it possible to overcommit almost arbitrary and provoke an OOM kill afterwards. Attached is a program that demonstrates the bug. Don't forget to "swapoff -a" before starting it, or touching pages will take eternity. And the amount of RAM must be <1Gb, or the prog will not work:)
On 2.4.25 I get: --- May 11 22:28:18 lin kernel: __alloc_pages: 0-order allocation failed (gfp=0x1d2/0) May 11 22:28:20 lin syslogd: /var/log/debug: Cannot allocate memory May 11 22:28:18 lin kernel: VM: killing process mozilla-bin May 11 22:28:18 lin kernel: __alloc_pages: 0-order allocation failed (gfp=0x1f0/0) May 11 22:28:20 lin kernel: __alloc_pages: 0-order allocation failed (gfp=0x1d2/0) May 11 22:28:21 lin kernel: __alloc_pages: 0-order allocation failed (gfp=0x1d2/0) May 11 22:28:21 lin kernel: VM: killing process X May 11 22:28:21 lin gnome-name-server[1254]: input condition is: 0x11, exiting May 11 22:29:00 lin kernel: __alloc_pages: 0-order allocation failed (gfp=0x1d2/0) May 11 22:29:00 lin kernel: VM: killing process overc_test --- As you can see, the program caused many other processes to be killed, before it died itself.
2.6.6 seems to kill only the test program itself, but there is one nasty side-effect here, that mprotect() fails to merge VMAs because one VMA can end up with VM_ACCOUNT flag set, and another - without that flag. That makes several apps of mine to malfuncate. Also it might be possible to bypass the security_vm_enough_memory() checks, which may probably be exploitable in some other ways.
I am also attaching the fix for 2.6 kernels.
Would be nice if someone can confirm the bug and verify the fix. Perhaps I am missing something obvious here, at least the fact that both 2.6 and 2.4 behaves similar, confuses me. And the fix looks also very strange, but it seems to work.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <asm/page.h> #include <errno.h>
#define SIZE (1024 * 1024 * 1024)
int main(int argc, char *argv[]) { char *addr; int i;
if ((addr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { printf("You have more than %i memory, increase SIZE\n", SIZE); return 1; } perror("mmap()"); printf("OK, now trying uncommited...\n"); if ((addr = mmap(0, SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) { perror("mmap()"); return 1; } if (mprotect(addr, SIZE, PROT_READ | PROT_WRITE) == -1) { perror("mprotect()"); return 1; }
printf("Memory of size %i successfully committed!\n", SIZE); printf("overcommit_memory: "); fflush(stdout); system("cat /proc/sys/vm/overcommit_memory");
for (i = 0; i < SIZE; i += PAGE_SIZE) { addr[i] = 1; }
return 0; }
--- linux/include/linux/mm.h 2004-04-14 09:41:36.000000000 +0400 +++ linux/include/linux/mm.h 2004-05-11 15:29:00.447968384 +0400 @@ -126,7 +126,7 @@ #define VM_NONLINEAR 0x00800000 /* Is non-linear (remap_file_pages) */ /* It makes sense to apply VM_ACCOUNT to this vma. */ -#define VM_MAYACCT(vma) (!!((vma)->vm_flags & VM_HUGETLB)) +#define VM_MAYACCT(vma) (!((vma)->vm_flags & VM_HUGETLB)) #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS Scanned by evaluation version of Dr.Web antivirus Daemon http://drweb.ru/unix/
| |