aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-04-27 20:04:15 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-05-01 13:08:57 -0400
commit5c598b3428c372a1209597cee99a70da20625876 (patch)
tree2ab9df5d60471e28074e97dca3c97b8c37d626b3
parent2030a42cecd4dd1985a2ab03e25f3cd6106a5ca8 (diff)
[PATCH] fix sysctl_nr_open bugs
* if luser with root sets it to something that is not a multiple of BITS_PER_LONG, the system is screwed. * if it gets decreased at the wrong time, we can get expand_files() returning success and _not_ increasing the size of table as asked. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/file.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/fs/file.c b/fs/file.c
index f6fbcb49faf7..4c6f0ea12c41 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -150,8 +150,16 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
150 nr /= (1024 / sizeof(struct file *)); 150 nr /= (1024 / sizeof(struct file *));
151 nr = roundup_pow_of_two(nr + 1); 151 nr = roundup_pow_of_two(nr + 1);
152 nr *= (1024 / sizeof(struct file *)); 152 nr *= (1024 / sizeof(struct file *));
153 if (nr > sysctl_nr_open) 153 /*
154 nr = sysctl_nr_open; 154 * Note that this can drive nr *below* what we had passed if sysctl_nr_open
155 * had been set lower between the check in expand_files() and here. Deal
156 * with that in caller, it's cheaper that way.
157 *
158 * We make sure that nr remains a multiple of BITS_PER_LONG - otherwise
159 * bitmaps handling below becomes unpleasant, to put it mildly...
160 */
161 if (unlikely(nr > sysctl_nr_open))
162 nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;
155 163
156 fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL); 164 fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
157 if (!fdt) 165 if (!fdt)
@@ -200,6 +208,16 @@ static int expand_fdtable(struct files_struct *files, int nr)
200 if (!new_fdt) 208 if (!new_fdt)
201 return -ENOMEM; 209 return -ENOMEM;
202 /* 210 /*
211 * extremely unlikely race - sysctl_nr_open decreased between the check in
212 * caller and alloc_fdtable(). Cheaper to catch it here...
213 */
214 if (unlikely(new_fdt->max_fds <= nr)) {
215 free_fdarr(new_fdt);
216 free_fdset(new_fdt);
217 kfree(new_fdt);
218 return -EMFILE;
219 }
220 /*
203 * Check again since another task may have expanded the fd table while 221 * Check again since another task may have expanded the fd table while
204 * we dropped the lock 222 * we dropped the lock
205 */ 223 */