From 8eeee4e2f04fc551f50c9d9847da2d73d7d33728 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 17 Jun 2009 00:27:10 +0200 Subject: 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 Signed-off-by: Linus Torvalds --- fs/fcntl.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'fs') 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, } static void send_sigio_to_task(struct task_struct *p, - struct fown_struct *fown, + struct fown_struct *fown, int fd, int reason) { - if (!sigio_perm(p, fown, fown->signum)) + /* + * F_SETSIG can change ->signum lockless in parallel, make + * sure we read it once and use the same value throughout. + */ + int signum = ACCESS_ONCE(fown->signum); + + if (!sigio_perm(p, fown, signum)) return; - switch (fown->signum) { + switch (signum) { siginfo_t si; default: /* Queue a rt signal with the appropriate fd as its @@ -444,7 +450,7 @@ static void send_sigio_to_task(struct task_struct *p, delivered even if we can't queue. Failure to queue in this case _should_ be reported; we fall back to SIGIO in that case. --sct */ - si.si_signo = fown->signum; + si.si_signo = signum; si.si_errno = 0; si.si_code = reason; /* Make sure we are called with one of the POLL_* @@ -456,7 +462,7 @@ static void send_sigio_to_task(struct task_struct *p, else si.si_band = band_table[reason - POLL_IN]; si.si_fd = fd; - if (!group_send_sig_info(fown->signum, &si, p)) + if (!group_send_sig_info(signum, &si, p)) break; /* fall-through: fall back on the old plain SIGIO signal */ case 0: -- cgit v1.2.3