summaryrefslogtreecommitdiff
path: root/fs/fcntl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r--fs/fcntl.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c
index ac4f7db9f134..cdc141946724 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -19,6 +19,7 @@
#include <linux/signal.h>
#include <linux/rcupdate.h>
#include <linux/pid_namespace.h>
+#include <linux/smp_lock.h>
#include <asm/poll.h>
#include <asm/siginfo.h>
@@ -175,6 +176,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
if (error)
return error;
+ /*
+ * We still need a lock here for now to keep multiple FASYNC calls
+ * from racing with each other.
+ */
+ lock_kernel();
if ((arg ^ filp->f_flags) & FASYNC) {
if (filp->f_op && filp->f_op->fasync) {
error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
@@ -185,6 +191,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
out:
+ unlock_kernel();
return error;
}
@@ -205,13 +212,14 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
int force)
{
+ const struct cred *cred = current_cred();
int err;
err = security_file_set_fowner(filp);
if (err)
return err;
- f_modown(filp, pid, type, current->uid, current->euid, force);
+ f_modown(filp, pid, type, cred->uid, cred->euid, force);
return 0;
}
EXPORT_SYMBOL(__f_setown);
@@ -400,10 +408,17 @@ static const long band_table[NSIGPOLL] = {
static inline int sigio_perm(struct task_struct *p,
struct fown_struct *fown, int sig)
{
- return (((fown->euid == 0) ||
- (fown->euid == p->suid) || (fown->euid == p->uid) ||
- (fown->uid == p->suid) || (fown->uid == p->uid)) &&
- !security_file_send_sigiotask(p, fown, sig));
+ const struct cred *cred;
+ int ret;
+
+ rcu_read_lock();
+ cred = __task_cred(p);
+ ret = ((fown->euid == 0 ||
+ fown->euid == cred->suid || fown->euid == cred->uid ||
+ fown->uid == cred->suid || fown->uid == cred->uid) &&
+ !security_file_send_sigiotask(p, fown, sig));
+ rcu_read_unlock();
+ return ret;
}
static void send_sigio_to_task(struct task_struct *p,