diff options
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index 1ad703150dee..a040b764f8e3 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -198,15 +198,19 @@ static int setfl(int fd, struct file * filp, unsigned long arg) | |||
198 | } | 198 | } |
199 | 199 | ||
200 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, | 200 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, |
201 | uid_t uid, uid_t euid, int force) | 201 | int force) |
202 | { | 202 | { |
203 | write_lock_irq(&filp->f_owner.lock); | 203 | write_lock_irq(&filp->f_owner.lock); |
204 | if (force || !filp->f_owner.pid) { | 204 | if (force || !filp->f_owner.pid) { |
205 | put_pid(filp->f_owner.pid); | 205 | put_pid(filp->f_owner.pid); |
206 | filp->f_owner.pid = get_pid(pid); | 206 | filp->f_owner.pid = get_pid(pid); |
207 | filp->f_owner.pid_type = type; | 207 | filp->f_owner.pid_type = type; |
208 | filp->f_owner.uid = uid; | 208 | |
209 | filp->f_owner.euid = euid; | 209 | if (pid) { |
210 | const struct cred *cred = current_cred(); | ||
211 | filp->f_owner.uid = cred->uid; | ||
212 | filp->f_owner.euid = cred->euid; | ||
213 | } | ||
210 | } | 214 | } |
211 | write_unlock_irq(&filp->f_owner.lock); | 215 | write_unlock_irq(&filp->f_owner.lock); |
212 | } | 216 | } |
@@ -214,14 +218,13 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, | |||
214 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, | 218 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, |
215 | int force) | 219 | int force) |
216 | { | 220 | { |
217 | const struct cred *cred = current_cred(); | ||
218 | int err; | 221 | int err; |
219 | 222 | ||
220 | err = security_file_set_fowner(filp); | 223 | err = security_file_set_fowner(filp); |
221 | if (err) | 224 | if (err) |
222 | return err; | 225 | return err; |
223 | 226 | ||
224 | f_modown(filp, pid, type, cred->uid, cred->euid, force); | 227 | f_modown(filp, pid, type, force); |
225 | return 0; | 228 | return 0; |
226 | } | 229 | } |
227 | EXPORT_SYMBOL(__f_setown); | 230 | EXPORT_SYMBOL(__f_setown); |
@@ -247,7 +250,7 @@ EXPORT_SYMBOL(f_setown); | |||
247 | 250 | ||
248 | void f_delown(struct file *filp) | 251 | void f_delown(struct file *filp) |
249 | { | 252 | { |
250 | f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1); | 253 | f_modown(filp, NULL, PIDTYPE_PID, 1); |
251 | } | 254 | } |
252 | 255 | ||
253 | pid_t f_getown(struct file *filp) | 256 | pid_t f_getown(struct file *filp) |
@@ -425,14 +428,20 @@ static inline int sigio_perm(struct task_struct *p, | |||
425 | } | 428 | } |
426 | 429 | ||
427 | static void send_sigio_to_task(struct task_struct *p, | 430 | static void send_sigio_to_task(struct task_struct *p, |
428 | struct fown_struct *fown, | 431 | struct fown_struct *fown, |
429 | int fd, | 432 | int fd, |
430 | int reason) | 433 | int reason) |
431 | { | 434 | { |
432 | if (!sigio_perm(p, fown, fown->signum)) | 435 | /* |
436 | * F_SETSIG can change ->signum lockless in parallel, make | ||
437 | * sure we read it once and use the same value throughout. | ||
438 | */ | ||
439 | int signum = ACCESS_ONCE(fown->signum); | ||
440 | |||
441 | if (!sigio_perm(p, fown, signum)) | ||
433 | return; | 442 | return; |
434 | 443 | ||
435 | switch (fown->signum) { | 444 | switch (signum) { |
436 | siginfo_t si; | 445 | siginfo_t si; |
437 | default: | 446 | default: |
438 | /* Queue a rt signal with the appropriate fd as its | 447 | /* Queue a rt signal with the appropriate fd as its |
@@ -441,7 +450,7 @@ static void send_sigio_to_task(struct task_struct *p, | |||
441 | delivered even if we can't queue. Failure to | 450 | delivered even if we can't queue. Failure to |
442 | queue in this case _should_ be reported; we fall | 451 | queue in this case _should_ be reported; we fall |
443 | back to SIGIO in that case. --sct */ | 452 | back to SIGIO in that case. --sct */ |
444 | si.si_signo = fown->signum; | 453 | si.si_signo = signum; |
445 | si.si_errno = 0; | 454 | si.si_errno = 0; |
446 | si.si_code = reason; | 455 | si.si_code = reason; |
447 | /* Make sure we are called with one of the POLL_* | 456 | /* Make sure we are called with one of the POLL_* |
@@ -453,7 +462,7 @@ static void send_sigio_to_task(struct task_struct *p, | |||
453 | else | 462 | else |
454 | si.si_band = band_table[reason - POLL_IN]; | 463 | si.si_band = band_table[reason - POLL_IN]; |
455 | si.si_fd = fd; | 464 | si.si_fd = fd; |
456 | if (!group_send_sig_info(fown->signum, &si, p)) | 465 | if (!group_send_sig_info(signum, &si, p)) |
457 | break; | 466 | break; |
458 | /* fall-through: fall back on the old plain SIGIO signal */ | 467 | /* fall-through: fall back on the old plain SIGIO signal */ |
459 | case 0: | 468 | case 0: |