4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Ivan Delalande <colona@xxxxxxxxxx> commit ea5751ccd665a2fd1b24f9af81f6167f0718c5f6 upstream. proc_sys_lookup can fail with ENOMEM instead of ENOENT when the corresponding sysctl table is being unregistered. In our case we see this upon opening /proc/sys/net/*/conf files while network interfaces are being deleted, which confuses our configuration daemon. The problem was successfully reproduced and this fix tested on v4.9.122 and v4.20-rc6. v2: return ERR_PTRs in all cases when proc_sys_make_inode fails instead of mixing them with NULL. Thanks Al Viro for the feedback. Fixes: ace0c791e6c3 ("proc/sysctl: Don't grab i_lock under sysctl_lock.") Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: Ivan Delalande <colona@xxxxxxxxxx> Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- fs/proc/proc_sysctl.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -466,7 +466,7 @@ static struct inode *proc_sys_make_inode inode = new_inode(sb); if (!inode) - goto out; + return ERR_PTR(-ENOMEM); inode->i_ino = get_next_ino(); @@ -476,8 +476,7 @@ static struct inode *proc_sys_make_inode if (unlikely(head->unregistering)) { spin_unlock(&sysctl_lock); iput(inode); - inode = NULL; - goto out; + return ERR_PTR(-ENOENT); } ei->sysctl = head; ei->sysctl_entry = table; @@ -502,7 +501,6 @@ static struct inode *proc_sys_make_inode if (root->set_ownership) root->set_ownership(head, table, &inode->i_uid, &inode->i_gid); -out: return inode; } @@ -551,10 +549,11 @@ static struct dentry *proc_sys_lookup(st goto out; } - err = ERR_PTR(-ENOMEM); inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); - if (!inode) + if (IS_ERR(inode)) { + err = ERR_CAST(inode); goto out; + } err = NULL; d_set_d_op(dentry, &proc_sys_dentry_operations); @@ -687,7 +686,7 @@ static bool proc_sys_fill_cache(struct f return false; if (d_in_lookup(child)) { inode = proc_sys_make_inode(dir->d_sb, head, table); - if (!inode) { + if (IS_ERR(inode)) { d_lookup_done(child); dput(child); return false;