summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Blank Jr <mitch@sfgoth.com>2006-04-11 09:54:08 +0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-11 17:18:41 +0400
commitb04eb6aa08ecc3e24df2f78ebc486011ebd74feb (patch)
tree8dbf6a2449f886f0db9c3082dabdf83d4c4f04f7
parenta9cdf410ca8f59b52bc7061a6751050010c7cc5b (diff)
downloadlinux-b04eb6aa08ecc3e24df2f78ebc486011ebd74feb.tar.xz
[PATCH] select: don't overflow if (SELECT_STACK_ALLOC % sizeof(long) != 0)
If SELECT_STACK_ALLOC is not a multiple of sizeof(long) then stack_fds[] would be shorter than SELECT_STACK_ALLOC bytes and could overflow later in the function. Fixed by simply rearranging the test later to work on sizeof(stack_fds) Currently SELECT_STACK_ALLOC is 256 so this doesn't happen, but it's nasty to have things like this hidden in the code. What if later someone decides to change SELECT_STACK_ALLOC to 300? Signed-off-by: Mitchell Blank Jr <mitch@sfgoth.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/select.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/fs/select.c b/fs/select.c
index fce0fd1bb1d1..a8109baa5e46 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -311,7 +311,8 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
{
fd_set_bits fds;
void *bits;
- int ret, size, max_fdset;
+ int ret, max_fdset;
+ unsigned int size;
struct fdtable *fdt;
/* Allocate small arguments on the stack to save memory and be faster */
long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
@@ -333,14 +334,15 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
* since we used fdset we need to allocate memory in units of
* long-words.
*/
- ret = -ENOMEM;
size = FDS_BYTES(n);
- if (6*size < SELECT_STACK_ALLOC)
- bits = stack_fds;
- else
+ bits = stack_fds;
+ if (size > sizeof(stack_fds) / 6) {
+ /* Not enough space in on-stack array; must use kmalloc */
+ ret = -ENOMEM;
bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
+ if (!bits)
+ goto out_nofds;
+ }
fds.in = bits;
fds.out = bits + size;
fds.ex = bits + 2*size;