Skip to content

Commit

Permalink
[PATCH] file: modify struct fown_struct to use a struct pid
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
ebiederm authored and Linus Torvalds committed Oct 2, 2006
1 parent bde0d2c commit 609d7fa
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 34 deletions.
2 changes: 1 addition & 1 deletion drivers/net/tun.c
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
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;
Expand Down
2 changes: 1 addition & 1 deletion fs/dnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
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;

Expand Down
77 changes: 49 additions & 28 deletions fs/fcntl.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,35 +250,65 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
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;

err = security_file_set_fowner(filp);
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 (filp->f_owner.pid_type == PIDTYPE_PGID)
pid = -pid;
return pid;
}

static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
Expand Down Expand Up @@ -319,7 +349,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
* 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:
Expand Down Expand Up @@ -470,24 +500,19 @@ static void send_sigio_to_task(struct task_struct *p,
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);
Expand All @@ -503,26 +528,22 @@ static void send_sigurg_to_task(struct task_struct *p,
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;

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);
Expand Down
1 change: 1 addition & 0 deletions fs/file_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
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;
Expand Down
5 changes: 4 additions & 1 deletion include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,8 @@ extern struct block_device *I_BDEV(struct inode *inode);

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 */
};
Expand Down Expand Up @@ -880,8 +881,10 @@ extern void kill_fasync(struct fasync_struct **, int, int);
/* 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);

/*
Expand Down
2 changes: 1 addition & 1 deletion kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ static int futex_fd(u32 __user *uaddr, int signal)
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;
}
Expand Down
2 changes: 1 addition & 1 deletion net/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
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:
Expand Down

0 comments on commit 609d7fa

Please sign in to comment.