summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2018-08-15 21:20:46 -0500
committerEric W. Biederman <ebiederm@xmission.com>2018-08-15 23:03:20 -0500
commit84fe4cc09abc1a5ef3a282db3ed10f4d3f1e6a0b (patch)
tree8bca92f3c76e42aee803946cd458a0c081862884
parentc3ad2c3b02e953ead2b8d52a0c9e70312930c3d0 (diff)
downloadlinux-84fe4cc09abc1a5ef3a282db3ed10f4d3f1e6a0b.tar.gz
linux-84fe4cc09abc1a5ef3a282db3ed10f4d3f1e6a0b.tar.bz2
linux-84fe4cc09abc1a5ef3a282db3ed10f4d3f1e6a0b.zip
signal: Don't send signals to tasks that don't exist
Recently syzbot reported crashes in send_sigio_to_task and send_sigurg_to_task in linux-next. Despite finding a reproducer syzbot apparently did not bisected this or otherwise track down the offending commit in linux-next. I happened to see this report and examined the code because I had recently changed these functions as part of making PIDTYPE_TGID a real pid type so that fork would does not need to restart when receiving a signal. By examination I see that I spotted a bug in the code that could explain the reported crashes. When I took Oleg's suggestion and optimized send_sigurg and send_sigio to only send to a single task when type is PIDTYPE_PID or PIDTYPE_TGID I failed to handle pids that no longer point to tasks. The macro do_each_pid_task simply iterates for zero iterations. With pid_task an explicit NULL test is needed. Update the code to include the missing NULL test. Fixes: 019191342fec ("signal: Use PIDTYPE_TGID to clearly store where file signals will be sent") Reported-by: syzkaller-bugs@googlegroups.com Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r--fs/fcntl.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c
index a04accf6847f..4137d96534a6 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -791,7 +791,8 @@ void send_sigio(struct fown_struct *fown, int fd, int band)
if (type <= PIDTYPE_TGID) {
rcu_read_lock();
p = pid_task(pid, PIDTYPE_PID);
- send_sigio_to_task(p, fown, fd, band, type);
+ if (p)
+ send_sigio_to_task(p, fown, fd, band, type);
rcu_read_unlock();
} else {
read_lock(&tasklist_lock);
@@ -830,7 +831,8 @@ int send_sigurg(struct fown_struct *fown)
if (type <= PIDTYPE_TGID) {
rcu_read_lock();
p = pid_task(pid, PIDTYPE_PID);
- send_sigurg_to_task(p, fown, type);
+ if (p)
+ send_sigurg_to_task(p, fown, type);
rcu_read_unlock();
} else {
read_lock(&tasklist_lock);