aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2009-06-16 18:27:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 18:36:17 -0400
commit8eeee4e2f04fc551f50c9d9847da2d73d7d33728 (patch)
treec5b7a2c9b912369c82506f8363b8eb10538f5d8e
parentf83b1e616f2f68b56b09b2f5116591981fee0c1c (diff)
send_sigio_to_task: sanitize the usage of fown->signum
send_sigio_to_task() reads fown->signum several times, we can race with F_SETSIG which changes ->signum lockless. In theory, this can fool security checks or we can call group_send_sig_info() with the wrong ->si_signo which does not match "int sig". Change the code to cache ->signum. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/fcntl.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c
index f9c03ca3b2f4..a040b764f8e3 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -428,14 +428,20 @@ static inline int sigio_perm(struct task_struct *p,
428} 428}
429 429
430static void send_sigio_to_task(struct task_struct *p, 430static void send_sigio_to_task(struct task_struct *p,
431 struct fown_struct *fown, 431 struct fown_struct *fown,
432 int fd, 432 int fd,
433 int reason) 433 int reason)
434{ 434{
435 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))
436 return; 442 return;
437 443
438 switch (fown->signum) { 444 switch (signum) {
439 siginfo_t si; 445 siginfo_t si;
440 default: 446 default:
441 /* Queue a rt signal with the appropriate fd as its 447 /* Queue a rt signal with the appropriate fd as its
@@ -444,7 +450,7 @@ static void send_sigio_to_task(struct task_struct *p,
444 delivered even if we can't queue. Failure to 450 delivered even if we can't queue. Failure to
445 queue in this case _should_ be reported; we fall 451 queue in this case _should_ be reported; we fall
446 back to SIGIO in that case. --sct */ 452 back to SIGIO in that case. --sct */
447 si.si_signo = fown->signum; 453 si.si_signo = signum;
448 si.si_errno = 0; 454 si.si_errno = 0;
449 si.si_code = reason; 455 si.si_code = reason;
450 /* Make sure we are called with one of the POLL_* 456 /* Make sure we are called with one of the POLL_*
@@ -456,7 +462,7 @@ static void send_sigio_to_task(struct task_struct *p,
456 else 462 else
457 si.si_band = band_table[reason - POLL_IN]; 463 si.si_band = band_table[reason - POLL_IN];
458 si.si_fd = fd; 464 si.si_fd = fd;
459 if (!group_send_sig_info(fown->signum, &si, p)) 465 if (!group_send_sig_info(signum, &si, p))
460 break; 466 break;
461 /* fall-through: fall back on the old plain SIGIO signal */ 467 /* fall-through: fall back on the old plain SIGIO signal */
462 case 0: 468 case 0: