From 44367d15f89f15a3b6b034097ade430afc9d651a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 14 May 2004 20:13:39 -0700 Subject: [PATCH] [PATCH] autofs4: dnotify + autofs may create signal/restart syscall loop From: Ian Kent From: Jeff Mahoney I saw a recent bug report that showed when a process set up a dnotify against the autofs root and then attempted an access(2) call inside the autofs namespace on a mount that would fail, it would create a signal/restart loop. The cause is that the autofs code checks to see if any signals are pending after it waits on a response from the autofs daemon. If it finds any, it assumes that autofs_wait was interrupted, and that it should return -ERESTARTNOINTR. The problem with this is that a signal_pending(current) check will return true if *any* signals were received, not just if a signal that interrupted the wait was received. autofs_wait explicitly blocks all signals except for SIGKILL, SIGQUIT, and SIGINT before calling interruptible_sleep_on. The effect is that if a dnotify is set against the autofs root, when the autofs daemon creates the directory, a dnotify event will be sent to the originating process. Since the code in autofs_root_lookup doesn't check to see what signals are actually pending, it bails early, telling the caller to try again. The loop goes on forever until interrupted via one of the actual interrupting signals. The following patch makes both autofs_root_lookup and autofs4_root_lookup verify that one of its defined "shutdown" signals are pending before bailing out early. Any other signal should be delivered later, as expected. It doesn't matter if the signal occured outside of the sleep in autofs_wait. The calling process will either go away or try again. --- fs/autofs4/inode.c | 2 ++ fs/autofs4/root.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 649c3dfd108a1..f3ea460c4b386 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -203,6 +203,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) sbi->oz_pgrp = process_group(current); sbi->sb = s; sbi->version = 0; + sbi->sub_version = 0; sbi->queues = NULL; s->s_blocksize = 1024; s->s_blocksize_bits = 10; @@ -244,6 +245,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) } sbi->version = maxproto > AUTOFS_MAX_PROTO_VERSION ? AUTOFS_MAX_PROTO_VERSION : maxproto; + sbi->sub_version = AUTOFS_PROTO_SUBVERSION; DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp)); pipe = fget(pipefd); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 458dfdc787f74..09a56fa851fee 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -292,9 +292,15 @@ static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dent * a signal. If so we can force a restart.. */ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { + /* See if we were interrupted */ if (signal_pending(current)) { - unlock_kernel(); - return ERR_PTR(-ERESTARTNOINTR); + sigset_t *sigset = ¤t->pending.signal; + if (sigismember (sigset, SIGKILL) || + sigismember (sigset, SIGQUIT) || + sigismember (sigset, SIGINT)) { + unlock_kernel(); + return ERR_PTR(-ERESTARTNOINTR); + } } } unlock_kernel(); -- 2.53.0