From: "Eric W. Biederman" 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 Signed-off-by: Andrew Morton --- drivers/net/tun.c | 2 - fs/dnotify.c | 2 - fs/fcntl.c | 77 +++++++++++++++++++++++++++---------------- fs/file_table.c | 1 fs/locks.c | 2 - include/linux/fs.h | 5 ++ kernel/futex.c | 2 - net/socket.c | 2 - 8 files changed, 59 insertions(+), 34 deletions(-) diff -puN drivers/net/tun.c~file-modify-struct-fown_struct-to-use-a-struct-pid drivers/net/tun.c --- a/drivers/net/tun.c~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/drivers/net/tun.c @@ -697,7 +697,7 @@ static int tun_chr_fasync(int fd, struct return ret; if (on) { - ret = f_setown(file, current->pid, 0); + ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0); if (ret) return ret; tun->flags |= TUN_FASYNC; diff -puN fs/dnotify.c~file-modify-struct-fown_struct-to-use-a-struct-pid fs/dnotify.c --- a/fs/dnotify.c~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/fs/dnotify.c @@ -92,7 +92,7 @@ int fcntl_dirnotify(int fd, struct file prev = &odn->dn_next; } - error = f_setown(filp, current->pid, 0); + error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); if (error) goto out_free; diff -puN fs/fcntl.c~file-modify-struct-fown_struct-to-use-a-struct-pid fs/fcntl.c --- a/fs/fcntl.c~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/fs/fcntl.c @@ -250,19 +250,22 @@ static int setfl(int fd, struct file * f return error; } -static void f_modown(struct file *filp, unsigned long pid, +static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, uid_t uid, uid_t euid, int force) { write_lock_irq(&filp->f_owner.lock); if (force || !filp->f_owner.pid) { - filp->f_owner.pid = pid; + put_pid(filp->f_owner.pid); + filp->f_owner.pid = get_pid(pid); + filp->f_owner.pid_type = type; filp->f_owner.uid = uid; filp->f_owner.euid = euid; } write_unlock_irq(&filp->f_owner.lock); } -int f_setown(struct file *filp, unsigned long arg, int force) +int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, + int force) { int err; @@ -270,15 +273,42 @@ int f_setown(struct file *filp, unsigned if (err) return err; - f_modown(filp, arg, current->uid, current->euid, force); + f_modown(filp, pid, type, current->uid, current->euid, force); return 0; } +EXPORT_SYMBOL(__f_setown); +int f_setown(struct file *filp, unsigned long arg, int force) +{ + enum pid_type type; + struct pid *pid; + int who = arg; + int result; + type = PIDTYPE_PID; + if (who < 0) { + type = PIDTYPE_PGID; + who = -who; + } + rcu_read_lock(); + pid = find_pid(who); + result = __f_setown(filp, pid, type, force); + rcu_read_unlock(); + return result; +} EXPORT_SYMBOL(f_setown); void f_delown(struct file *filp) { - f_modown(filp, 0, 0, 0, 1); + f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1); +} + +pid_t f_getown(struct file *filp) +{ + pid_t pid; + pid = pid_nr(filp->f_owner.pid); + if (sock->file->f_owner.pid_type == PIDTYPE_PGID) + pid = -pid; + return pid; } static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, @@ -319,7 +349,7 @@ static long do_fcntl(int fd, unsigned in * current syscall conventions, the only way * to fix this will be in libc. */ - err = filp->f_owner.pid; + err = f_getown(filp); force_successful_syscall_return(); break; case F_SETOWN: @@ -470,24 +500,19 @@ static void send_sigio_to_task(struct ta void send_sigio(struct fown_struct *fown, int fd, int band) { struct task_struct *p; - int pid; + enum pid_type type; + struct pid *pid; read_lock(&fown->lock); + type = fown->pid_type; pid = fown->pid; if (!pid) goto out_unlock_fown; read_lock(&tasklist_lock); - if (pid > 0) { - p = find_task_by_pid(pid); - if (p) { - send_sigio_to_task(p, fown, fd, band); - } - } else { - do_each_task_pid(-pid, PIDTYPE_PGID, p) { - send_sigio_to_task(p, fown, fd, band); - } while_each_task_pid(-pid, PIDTYPE_PGID, p); - } + do_each_pid_task(pid, type, p) { + send_sigio_to_task(p, fown, fd, band); + } while_each_pid_task(pid, type, p); read_unlock(&tasklist_lock); out_unlock_fown: read_unlock(&fown->lock); @@ -503,9 +528,12 @@ static void send_sigurg_to_task(struct t int send_sigurg(struct fown_struct *fown) { struct task_struct *p; - int pid, ret = 0; + enum pid_type type; + struct pid *pid; + int ret = 0; read_lock(&fown->lock); + type = fown->pid_type; pid = fown->pid; if (!pid) goto out_unlock_fown; @@ -513,16 +541,9 @@ int send_sigurg(struct fown_struct *fown ret = 1; read_lock(&tasklist_lock); - if (pid > 0) { - p = find_task_by_pid(pid); - if (p) { - send_sigurg_to_task(p, fown); - } - } else { - do_each_task_pid(-pid, PIDTYPE_PGID, p) { - send_sigurg_to_task(p, fown); - } while_each_task_pid(-pid, PIDTYPE_PGID, p); - } + do_each_pid_task(pid, type, p) { + send_sigurg_to_task(p, fown); + } while_each_pid_task(pid, type, p); read_unlock(&tasklist_lock); out_unlock_fown: read_unlock(&fown->lock); diff -puN fs/file_table.c~file-modify-struct-fown_struct-to-use-a-struct-pid fs/file_table.c --- a/fs/file_table.c~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/fs/file_table.c @@ -174,6 +174,7 @@ void fastcall __fput(struct file *file) fops_put(file->f_op); if (file->f_mode & FMODE_WRITE) put_write_access(inode); + put_pid(file->f_owner.pid); file_kill(file); file->f_dentry = NULL; file->f_vfsmnt = NULL; diff -puN fs/locks.c~file-modify-struct-fown_struct-to-use-a-struct-pid fs/locks.c --- a/fs/locks.c~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/fs/locks.c @@ -1514,7 +1514,7 @@ int fcntl_setlease(unsigned int fd, stru goto out_unlock; } - error = f_setown(filp, current->pid, 0); + error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); out_unlock: unlock_kernel(); return error; diff -puN include/linux/fs.h~file-modify-struct-fown_struct-to-use-a-struct-pid include/linux/fs.h --- a/include/linux/fs.h~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/include/linux/fs.h @@ -668,7 +668,8 @@ extern struct block_device *I_BDEV(struc struct fown_struct { rwlock_t lock; /* protects pid, uid, euid fields */ - int pid; /* pid or -pgrp where SIGIO should be sent */ + struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ + enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ uid_t uid, euid; /* uid/euid of process setting the owner */ int signum; /* posix.1b rt signal to be delivered on IO */ }; @@ -864,8 +865,10 @@ extern void kill_fasync(struct fasync_st /* only for net: no internal synchronization */ extern void __kill_fasync(struct fasync_struct *, int, int); +extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force); extern int f_setown(struct file *filp, unsigned long arg, int force); extern void f_delown(struct file *filp); +extern pid_t f_getown(struct file *filp); extern int send_sigurg(struct fown_struct *fown); /* diff -puN kernel/futex.c~file-modify-struct-fown_struct-to-use-a-struct-pid kernel/futex.c --- a/kernel/futex.c~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/kernel/futex.c @@ -1589,7 +1589,7 @@ static int futex_fd(u32 __user *uaddr, i filp->f_mapping = filp->f_dentry->d_inode->i_mapping; if (signal) { - err = f_setown(filp, current->pid, 1); + err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1); if (err < 0) { goto error; } diff -puN net/socket.c~file-modify-struct-fown_struct-to-use-a-struct-pid net/socket.c --- a/net/socket.c~file-modify-struct-fown_struct-to-use-a-struct-pid +++ a/net/socket.c @@ -825,7 +825,7 @@ static long sock_ioctl(struct file *file break; case FIOGETOWN: case SIOCGPGRP: - err = put_user(sock->file->f_owner.pid, + err = put_user(f_getown(sock->file), (int __user *)argp); break; case SIOCGIFBR: _