diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-10-02 05:17:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:14 -0400 |
commit | 609d7fa9565c754428d2520cac2accc9052e1245 (patch) | |
tree | 1c5114ec3720166fe99ce3885e8767929a8a84e0 /fs/fcntl.c | |
parent | bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92 (diff) |
[PATCH] file: modify struct fown_struct to use a struct pid
File handles can be requested to send sigio and sigurg to processes. By
tracking the destination processes using struct pid instead of pid_t we make
the interface safe from all potential pid wrap around problems.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 77 |
1 files changed, 49 insertions, 28 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index d35cbc6bc112..e7c66a1bf831 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -250,19 +250,22 @@ static int setfl(int fd, struct file * filp, unsigned long arg) | |||
250 | return error; | 250 | return error; |
251 | } | 251 | } |
252 | 252 | ||
253 | static void f_modown(struct file *filp, unsigned long pid, | 253 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, |
254 | uid_t uid, uid_t euid, int force) | 254 | uid_t uid, uid_t euid, int force) |
255 | { | 255 | { |
256 | write_lock_irq(&filp->f_owner.lock); | 256 | write_lock_irq(&filp->f_owner.lock); |
257 | if (force || !filp->f_owner.pid) { | 257 | if (force || !filp->f_owner.pid) { |
258 | filp->f_owner.pid = pid; | 258 | put_pid(filp->f_owner.pid); |
259 | filp->f_owner.pid = get_pid(pid); | ||
260 | filp->f_owner.pid_type = type; | ||
259 | filp->f_owner.uid = uid; | 261 | filp->f_owner.uid = uid; |
260 | filp->f_owner.euid = euid; | 262 | filp->f_owner.euid = euid; |
261 | } | 263 | } |
262 | write_unlock_irq(&filp->f_owner.lock); | 264 | write_unlock_irq(&filp->f_owner.lock); |
263 | } | 265 | } |
264 | 266 | ||
265 | int f_setown(struct file *filp, unsigned long arg, int force) | 267 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, |
268 | int force) | ||
266 | { | 269 | { |
267 | int err; | 270 | int err; |
268 | 271 | ||
@@ -270,15 +273,42 @@ int f_setown(struct file *filp, unsigned long arg, int force) | |||
270 | if (err) | 273 | if (err) |
271 | return err; | 274 | return err; |
272 | 275 | ||
273 | f_modown(filp, arg, current->uid, current->euid, force); | 276 | f_modown(filp, pid, type, current->uid, current->euid, force); |
274 | return 0; | 277 | return 0; |
275 | } | 278 | } |
279 | EXPORT_SYMBOL(__f_setown); | ||
276 | 280 | ||
281 | int f_setown(struct file *filp, unsigned long arg, int force) | ||
282 | { | ||
283 | enum pid_type type; | ||
284 | struct pid *pid; | ||
285 | int who = arg; | ||
286 | int result; | ||
287 | type = PIDTYPE_PID; | ||
288 | if (who < 0) { | ||
289 | type = PIDTYPE_PGID; | ||
290 | who = -who; | ||
291 | } | ||
292 | rcu_read_lock(); | ||
293 | pid = find_pid(who); | ||
294 | result = __f_setown(filp, pid, type, force); | ||
295 | rcu_read_unlock(); | ||
296 | return result; | ||
297 | } | ||
277 | EXPORT_SYMBOL(f_setown); | 298 | EXPORT_SYMBOL(f_setown); |
278 | 299 | ||
279 | void f_delown(struct file *filp) | 300 | void f_delown(struct file *filp) |
280 | { | 301 | { |
281 | f_modown(filp, 0, 0, 0, 1); | 302 | f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1); |
303 | } | ||
304 | |||
305 | pid_t f_getown(struct file *filp) | ||
306 | { | ||
307 | pid_t pid; | ||
308 | pid = pid_nr(filp->f_owner.pid); | ||
309 | if (filp->f_owner.pid_type == PIDTYPE_PGID) | ||
310 | pid = -pid; | ||
311 | return pid; | ||
282 | } | 312 | } |
283 | 313 | ||
284 | static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | 314 | static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, |
@@ -319,7 +349,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
319 | * current syscall conventions, the only way | 349 | * current syscall conventions, the only way |
320 | * to fix this will be in libc. | 350 | * to fix this will be in libc. |
321 | */ | 351 | */ |
322 | err = filp->f_owner.pid; | 352 | err = f_getown(filp); |
323 | force_successful_syscall_return(); | 353 | force_successful_syscall_return(); |
324 | break; | 354 | break; |
325 | case F_SETOWN: | 355 | case F_SETOWN: |
@@ -470,24 +500,19 @@ static void send_sigio_to_task(struct task_struct *p, | |||
470 | void send_sigio(struct fown_struct *fown, int fd, int band) | 500 | void send_sigio(struct fown_struct *fown, int fd, int band) |
471 | { | 501 | { |
472 | struct task_struct *p; | 502 | struct task_struct *p; |
473 | int pid; | 503 | enum pid_type type; |
504 | struct pid *pid; | ||
474 | 505 | ||
475 | read_lock(&fown->lock); | 506 | read_lock(&fown->lock); |
507 | type = fown->pid_type; | ||
476 | pid = fown->pid; | 508 | pid = fown->pid; |
477 | if (!pid) | 509 | if (!pid) |
478 | goto out_unlock_fown; | 510 | goto out_unlock_fown; |
479 | 511 | ||
480 | read_lock(&tasklist_lock); | 512 | read_lock(&tasklist_lock); |
481 | if (pid > 0) { | 513 | do_each_pid_task(pid, type, p) { |
482 | p = find_task_by_pid(pid); | 514 | send_sigio_to_task(p, fown, fd, band); |
483 | if (p) { | 515 | } while_each_pid_task(pid, type, p); |
484 | send_sigio_to_task(p, fown, fd, band); | ||
485 | } | ||
486 | } else { | ||
487 | do_each_task_pid(-pid, PIDTYPE_PGID, p) { | ||
488 | send_sigio_to_task(p, fown, fd, band); | ||
489 | } while_each_task_pid(-pid, PIDTYPE_PGID, p); | ||
490 | } | ||
491 | read_unlock(&tasklist_lock); | 516 | read_unlock(&tasklist_lock); |
492 | out_unlock_fown: | 517 | out_unlock_fown: |
493 | read_unlock(&fown->lock); | 518 | read_unlock(&fown->lock); |
@@ -503,9 +528,12 @@ static void send_sigurg_to_task(struct task_struct *p, | |||
503 | int send_sigurg(struct fown_struct *fown) | 528 | int send_sigurg(struct fown_struct *fown) |
504 | { | 529 | { |
505 | struct task_struct *p; | 530 | struct task_struct *p; |
506 | int pid, ret = 0; | 531 | enum pid_type type; |
532 | struct pid *pid; | ||
533 | int ret = 0; | ||
507 | 534 | ||
508 | read_lock(&fown->lock); | 535 | read_lock(&fown->lock); |
536 | type = fown->pid_type; | ||
509 | pid = fown->pid; | 537 | pid = fown->pid; |
510 | if (!pid) | 538 | if (!pid) |
511 | goto out_unlock_fown; | 539 | goto out_unlock_fown; |
@@ -513,16 +541,9 @@ int send_sigurg(struct fown_struct *fown) | |||
513 | ret = 1; | 541 | ret = 1; |
514 | 542 | ||
515 | read_lock(&tasklist_lock); | 543 | read_lock(&tasklist_lock); |
516 | if (pid > 0) { | 544 | do_each_pid_task(pid, type, p) { |
517 | p = find_task_by_pid(pid); | 545 | send_sigurg_to_task(p, fown); |
518 | if (p) { | 546 | } while_each_pid_task(pid, type, p); |
519 | send_sigurg_to_task(p, fown); | ||
520 | } | ||
521 | } else { | ||
522 | do_each_task_pid(-pid, PIDTYPE_PGID, p) { | ||
523 | send_sigurg_to_task(p, fown); | ||
524 | } while_each_task_pid(-pid, PIDTYPE_PGID, p); | ||
525 | } | ||
526 | read_unlock(&tasklist_lock); | 547 | read_unlock(&tasklist_lock); |
527 | out_unlock_fown: | 548 | out_unlock_fown: |
528 | read_unlock(&fown->lock); | 549 | read_unlock(&fown->lock); |