diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-02-16 19:54:13 -0500 |
---|---|---|
committer | Mike Marshall <hubcap@omnibond.com> | 2016-03-25 22:30:54 -0400 |
commit | 9f5e2f7f1b4bf7d0b19d88edd9425510fadbb9e4 (patch) | |
tree | 7c0ac500aa53497534eed471e7889c149876f2c5 /fs/orangefs | |
parent | fecd86aac5a7621635b61e7491f0ed73610d76fa (diff) |
orangefs: get rid of readdir_handle_s
no point, really - we couldn't keep those across the calls of
getdents(); it would be too easy to DoS, having all slots exhausted.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Diffstat (limited to 'fs/orangefs')
-rw-r--r-- | fs/orangefs/dir.c | 93 |
1 files changed, 30 insertions, 63 deletions
diff --git a/fs/orangefs/dir.c b/fs/orangefs/dir.c index 259b667f6c8f..53a411732606 100644 --- a/fs/orangefs/dir.c +++ b/fs/orangefs/dir.c | |||
@@ -8,11 +8,6 @@ | |||
8 | #include "orangefs-kernel.h" | 8 | #include "orangefs-kernel.h" |
9 | #include "orangefs-bufmap.h" | 9 | #include "orangefs-bufmap.h" |
10 | 10 | ||
11 | struct readdir_handle_s { | ||
12 | struct orangefs_readdir_response_s readdir_response; | ||
13 | void *dents_buf; | ||
14 | }; | ||
15 | |||
16 | /* | 11 | /* |
17 | * decode routine used by kmod to deal with the blob sent from | 12 | * decode routine used by kmod to deal with the blob sent from |
18 | * userspace for readdirs. The blob contains zero or more of these | 13 | * userspace for readdirs. The blob contains zero or more of these |
@@ -141,44 +136,6 @@ out: | |||
141 | return ret; | 136 | return ret; |
142 | } | 137 | } |
143 | 138 | ||
144 | static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf, | ||
145 | size_t size) | ||
146 | { | ||
147 | long ret; | ||
148 | |||
149 | if (buf == NULL) { | ||
150 | gossip_err | ||
151 | ("Invalid NULL buffer specified in readdir_handle_ctor\n"); | ||
152 | return -ENOMEM; | ||
153 | } | ||
154 | rhandle->dents_buf = buf; | ||
155 | ret = decode_dirents(buf, size, &rhandle->readdir_response); | ||
156 | if (ret < 0) { | ||
157 | gossip_err("Could not decode readdir from buffer %ld\n", ret); | ||
158 | gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf); | ||
159 | vfree(buf); | ||
160 | rhandle->dents_buf = NULL; | ||
161 | } | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static void readdir_handle_dtor(struct readdir_handle_s *rhandle) | ||
166 | { | ||
167 | if (rhandle == NULL) | ||
168 | return; | ||
169 | |||
170 | /* kfree(NULL) is safe */ | ||
171 | kfree(rhandle->readdir_response.dirent_array); | ||
172 | rhandle->readdir_response.dirent_array = NULL; | ||
173 | |||
174 | if (rhandle->dents_buf) { | ||
175 | gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", | ||
176 | rhandle->dents_buf); | ||
177 | vfree(rhandle->dents_buf); | ||
178 | rhandle->dents_buf = NULL; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /* | 139 | /* |
183 | * Read directory entries from an instance of an open directory. | 140 | * Read directory entries from an instance of an open directory. |
184 | */ | 141 | */ |
@@ -198,7 +155,8 @@ static int orangefs_readdir(struct file *file, struct dir_context *ctx) | |||
198 | struct orangefs_kernel_op_s *new_op = NULL; | 155 | struct orangefs_kernel_op_s *new_op = NULL; |
199 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode); | 156 | struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode); |
200 | int buffer_full = 0; | 157 | int buffer_full = 0; |
201 | struct readdir_handle_s rhandle; | 158 | struct orangefs_readdir_response_s readdir_response; |
159 | void *dents_buf; | ||
202 | int i = 0; | 160 | int i = 0; |
203 | int len = 0; | 161 | int len = 0; |
204 | ino_t current_ino = 0; | 162 | ino_t current_ino = 0; |
@@ -224,8 +182,7 @@ static int orangefs_readdir(struct file *file, struct dir_context *ctx) | |||
224 | "orangefs_readdir called on %s (pos=%llu)\n", | 182 | "orangefs_readdir called on %s (pos=%llu)\n", |
225 | dentry->d_name.name, llu(pos)); | 183 | dentry->d_name.name, llu(pos)); |
226 | 184 | ||
227 | rhandle.dents_buf = NULL; | 185 | memset(&readdir_response, 0, sizeof(readdir_response)); |
228 | memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response)); | ||
229 | 186 | ||
230 | new_op = op_alloc(ORANGEFS_VFS_OP_READDIR); | 187 | new_op = op_alloc(ORANGEFS_VFS_OP_READDIR); |
231 | if (!new_op) | 188 | if (!new_op) |
@@ -278,7 +235,7 @@ get_new_buffer_index: | |||
278 | if (ret == -EIO && op_state_purged(new_op)) { | 235 | if (ret == -EIO && op_state_purged(new_op)) { |
279 | gossip_err("%s: Client is down. Aborting readdir call.\n", | 236 | gossip_err("%s: Client is down. Aborting readdir call.\n", |
280 | __func__); | 237 | __func__); |
281 | goto out_free_op; | 238 | goto out_slot; |
282 | } | 239 | } |
283 | 240 | ||
284 | if (ret < 0 || new_op->downcall.status != 0) { | 241 | if (ret < 0 || new_op->downcall.status != 0) { |
@@ -287,18 +244,22 @@ get_new_buffer_index: | |||
287 | new_op->downcall.status); | 244 | new_op->downcall.status); |
288 | if (ret >= 0) | 245 | if (ret >= 0) |
289 | ret = new_op->downcall.status; | 246 | ret = new_op->downcall.status; |
290 | goto out_free_op; | 247 | goto out_slot; |
248 | } | ||
249 | |||
250 | dents_buf = new_op->downcall.trailer_buf; | ||
251 | if (dents_buf == NULL) { | ||
252 | gossip_err("Invalid NULL buffer in readdir response\n"); | ||
253 | ret = -ENOMEM; | ||
254 | goto out_slot; | ||
291 | } | 255 | } |
292 | 256 | ||
293 | bytes_decoded = | 257 | bytes_decoded = decode_dirents(dents_buf, new_op->downcall.trailer_size, |
294 | readdir_handle_ctor(&rhandle, | 258 | &readdir_response); |
295 | new_op->downcall.trailer_buf, | ||
296 | new_op->downcall.trailer_size); | ||
297 | if (bytes_decoded < 0) { | 259 | if (bytes_decoded < 0) { |
298 | gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n", | ||
299 | ret); | ||
300 | ret = bytes_decoded; | 260 | ret = bytes_decoded; |
301 | goto out_free_op; | 261 | gossip_err("Could not decode readdir from buffer %d\n", ret); |
262 | goto out_vfree; | ||
302 | } | 263 | } |
303 | 264 | ||
304 | if (bytes_decoded != new_op->downcall.trailer_size) { | 265 | if (bytes_decoded != new_op->downcall.trailer_size) { |
@@ -345,14 +306,14 @@ get_new_buffer_index: | |||
345 | gossip_debug(GOSSIP_DIR_DEBUG, | 306 | gossip_debug(GOSSIP_DIR_DEBUG, |
346 | "%s: dirent_outcount:%d:\n", | 307 | "%s: dirent_outcount:%d:\n", |
347 | __func__, | 308 | __func__, |
348 | rhandle.readdir_response.orangefs_dirent_outcount); | 309 | readdir_response.orangefs_dirent_outcount); |
349 | for (i = ctx->pos; | 310 | for (i = ctx->pos; |
350 | i < rhandle.readdir_response.orangefs_dirent_outcount; | 311 | i < readdir_response.orangefs_dirent_outcount; |
351 | i++) { | 312 | i++) { |
352 | len = rhandle.readdir_response.dirent_array[i].d_length; | 313 | len = readdir_response.dirent_array[i].d_length; |
353 | current_entry = rhandle.readdir_response.dirent_array[i].d_name; | 314 | current_entry = readdir_response.dirent_array[i].d_name; |
354 | current_ino = orangefs_khandle_to_ino( | 315 | current_ino = orangefs_khandle_to_ino( |
355 | &(rhandle.readdir_response.dirent_array[i].khandle)); | 316 | &readdir_response.dirent_array[i].khandle); |
356 | 317 | ||
357 | gossip_debug(GOSSIP_DIR_DEBUG, | 318 | gossip_debug(GOSSIP_DIR_DEBUG, |
358 | "calling dir_emit for %s with len %d" | 319 | "calling dir_emit for %s with len %d" |
@@ -382,14 +343,14 @@ get_new_buffer_index: | |||
382 | * getting another batch... | 343 | * getting another batch... |
383 | */ | 344 | */ |
384 | if (ret) { | 345 | if (ret) { |
385 | *ptoken = rhandle.readdir_response.token; | 346 | *ptoken = readdir_response.token; |
386 | ctx->pos = ORANGEFS_ITERATE_NEXT; | 347 | ctx->pos = ORANGEFS_ITERATE_NEXT; |
387 | } | 348 | } |
388 | 349 | ||
389 | /* | 350 | /* |
390 | * Did we hit the end of the directory? | 351 | * Did we hit the end of the directory? |
391 | */ | 352 | */ |
392 | if (rhandle.readdir_response.token == ORANGEFS_READDIR_END && | 353 | if (readdir_response.token == ORANGEFS_READDIR_END && |
393 | !buffer_full) { | 354 | !buffer_full) { |
394 | gossip_debug(GOSSIP_DIR_DEBUG, | 355 | gossip_debug(GOSSIP_DIR_DEBUG, |
395 | "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n"); | 356 | "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n"); |
@@ -397,7 +358,13 @@ get_new_buffer_index: | |||
397 | } | 358 | } |
398 | 359 | ||
399 | out_destroy_handle: | 360 | out_destroy_handle: |
400 | readdir_handle_dtor(&rhandle); | 361 | /* kfree(NULL) is safe */ |
362 | kfree(readdir_response.dirent_array); | ||
363 | out_vfree: | ||
364 | gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", dents_buf); | ||
365 | vfree(dents_buf); | ||
366 | out_slot: | ||
367 | orangefs_readdir_index_put(buffer_index); | ||
401 | out_free_op: | 368 | out_free_op: |
402 | op_release(new_op); | 369 | op_release(new_op); |
403 | gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret); | 370 | gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret); |