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 | |
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>
-rw-r--r-- | drivers/net/tun.c | 2 | ||||
-rw-r--r-- | fs/dnotify.c | 2 | ||||
-rw-r--r-- | fs/fcntl.c | 77 | ||||
-rw-r--r-- | fs/file_table.c | 1 | ||||
-rw-r--r-- | fs/locks.c | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 5 | ||||
-rw-r--r-- | kernel/futex.c | 2 | ||||
-rw-r--r-- | net/socket.c | 2 |
8 files changed, 59 insertions, 34 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bc0face01d25..151a2e10e4f3 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -697,7 +697,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on) | |||
697 | return ret; | 697 | return ret; |
698 | 698 | ||
699 | if (on) { | 699 | if (on) { |
700 | ret = f_setown(file, current->pid, 0); | 700 | ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0); |
701 | if (ret) | 701 | if (ret) |
702 | return ret; | 702 | return ret; |
703 | tun->flags |= TUN_FASYNC; | 703 | tun->flags |= TUN_FASYNC; |
diff --git a/fs/dnotify.c b/fs/dnotify.c index f932591df5a4..2b0442db67e0 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c | |||
@@ -92,7 +92,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
92 | prev = &odn->dn_next; | 92 | prev = &odn->dn_next; |
93 | } | 93 | } |
94 | 94 | ||
95 | error = f_setown(filp, current->pid, 0); | 95 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
96 | if (error) | 96 | if (error) |
97 | goto out_free; | 97 | goto out_free; |
98 | 98 | ||
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); |
diff --git a/fs/file_table.c b/fs/file_table.c index bc35a40417d7..24f25a057d9c 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -174,6 +174,7 @@ void fastcall __fput(struct file *file) | |||
174 | fops_put(file->f_op); | 174 | fops_put(file->f_op); |
175 | if (file->f_mode & FMODE_WRITE) | 175 | if (file->f_mode & FMODE_WRITE) |
176 | put_write_access(inode); | 176 | put_write_access(inode); |
177 | put_pid(file->f_owner.pid); | ||
177 | file_kill(file); | 178 | file_kill(file); |
178 | file->f_dentry = NULL; | 179 | file->f_dentry = NULL; |
179 | file->f_vfsmnt = NULL; | 180 | file->f_vfsmnt = NULL; |
diff --git a/fs/locks.c b/fs/locks.c index 21dfadfca2bc..e0b6a80649a0 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1514,7 +1514,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |||
1514 | goto out_unlock; | 1514 | goto out_unlock; |
1515 | } | 1515 | } |
1516 | 1516 | ||
1517 | error = f_setown(filp, current->pid, 0); | 1517 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
1518 | out_unlock: | 1518 | out_unlock: |
1519 | unlock_kernel(); | 1519 | unlock_kernel(); |
1520 | return error; | 1520 | return error; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 2e29a2edaeec..91c0b2a32a90 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -684,7 +684,8 @@ extern struct block_device *I_BDEV(struct inode *inode); | |||
684 | 684 | ||
685 | struct fown_struct { | 685 | struct fown_struct { |
686 | rwlock_t lock; /* protects pid, uid, euid fields */ | 686 | rwlock_t lock; /* protects pid, uid, euid fields */ |
687 | int pid; /* pid or -pgrp where SIGIO should be sent */ | 687 | struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ |
688 | enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ | ||
688 | uid_t uid, euid; /* uid/euid of process setting the owner */ | 689 | uid_t uid, euid; /* uid/euid of process setting the owner */ |
689 | int signum; /* posix.1b rt signal to be delivered on IO */ | 690 | int signum; /* posix.1b rt signal to be delivered on IO */ |
690 | }; | 691 | }; |
@@ -880,8 +881,10 @@ extern void kill_fasync(struct fasync_struct **, int, int); | |||
880 | /* only for net: no internal synchronization */ | 881 | /* only for net: no internal synchronization */ |
881 | extern void __kill_fasync(struct fasync_struct *, int, int); | 882 | extern void __kill_fasync(struct fasync_struct *, int, int); |
882 | 883 | ||
884 | extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force); | ||
883 | extern int f_setown(struct file *filp, unsigned long arg, int force); | 885 | extern int f_setown(struct file *filp, unsigned long arg, int force); |
884 | extern void f_delown(struct file *filp); | 886 | extern void f_delown(struct file *filp); |
887 | extern pid_t f_getown(struct file *filp); | ||
885 | extern int send_sigurg(struct fown_struct *fown); | 888 | extern int send_sigurg(struct fown_struct *fown); |
886 | 889 | ||
887 | /* | 890 | /* |
diff --git a/kernel/futex.c b/kernel/futex.c index 4b6770e9806d..4aaf91951a43 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -1527,7 +1527,7 @@ static int futex_fd(u32 __user *uaddr, int signal) | |||
1527 | filp->f_mapping = filp->f_dentry->d_inode->i_mapping; | 1527 | filp->f_mapping = filp->f_dentry->d_inode->i_mapping; |
1528 | 1528 | ||
1529 | if (signal) { | 1529 | if (signal) { |
1530 | err = f_setown(filp, current->pid, 1); | 1530 | err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1); |
1531 | if (err < 0) { | 1531 | if (err < 0) { |
1532 | goto error; | 1532 | goto error; |
1533 | } | 1533 | } |
diff --git a/net/socket.c b/net/socket.c index 01918f7a301a..6c9b9b326d76 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -825,7 +825,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
825 | break; | 825 | break; |
826 | case FIOGETOWN: | 826 | case FIOGETOWN: |
827 | case SIOCGPGRP: | 827 | case SIOCGPGRP: |
828 | err = put_user(sock->file->f_owner.pid, | 828 | err = put_user(f_getown(sock->file), |
829 | (int __user *)argp); | 829 | (int __user *)argp); |
830 | break; | 830 | break; |
831 | case SIOCGIFBR: | 831 | case SIOCGIFBR: |