Skip to content

Commit 99421c1

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull namespace fixes from Eric Biederman: "This tree contains 4 fixes. The first is a fix for a race that can causes oopses under the right circumstances, and that someone just recently encountered. Past that are several small trivial correct fixes. A real issue that was blocking development of an out of tree driver, but does not appear to have caused any actual problems for in-tree code. A potential deadlock that was reported by lockdep. And a deadlock people have experienced and took the time to track down caused by a cleanup that removed the code to drop a reference count" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: sysctl: Drop reference added by grab_header in proc_sys_readdir pid: fix lockdep deadlock warning due to ucount_lock libfs: Modify mount_pseudo_xattr to be clear it is not a userspace mount mnt: Protect the mountpoint hashtable with mount_lock
2 parents c928162 + 93362fa commit 99421c1

File tree

5 files changed

+60
-27
lines changed

5 files changed

+60
-27
lines changed

fs/dcache.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,8 +1336,11 @@ int d_set_mounted(struct dentry *dentry)
13361336
}
13371337
spin_lock(&dentry->d_lock);
13381338
if (!d_unlinked(dentry)) {
1339-
dentry->d_flags |= DCACHE_MOUNTED;
1340-
ret = 0;
1339+
ret = -EBUSY;
1340+
if (!d_mountpoint(dentry)) {
1341+
dentry->d_flags |= DCACHE_MOUNTED;
1342+
ret = 0;
1343+
}
13411344
}
13421345
spin_unlock(&dentry->d_lock);
13431346
out:

fs/libfs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
245245
struct inode *root;
246246
struct qstr d_name = QSTR_INIT(name, strlen(name));
247247

248-
s = sget(fs_type, NULL, set_anon_super, MS_NOUSER, NULL);
248+
s = sget_userns(fs_type, NULL, set_anon_super, MS_KERNMOUNT|MS_NOUSER,
249+
&init_user_ns, NULL);
249250
if (IS_ERR(s))
250251
return ERR_CAST(s);
251252

fs/namespace.c

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -742,26 +742,50 @@ static struct mountpoint *lookup_mountpoint(struct dentry *dentry)
742742
return NULL;
743743
}
744744

745-
static struct mountpoint *new_mountpoint(struct dentry *dentry)
745+
static struct mountpoint *get_mountpoint(struct dentry *dentry)
746746
{
747-
struct hlist_head *chain = mp_hash(dentry);
748-
struct mountpoint *mp;
747+
struct mountpoint *mp, *new = NULL;
749748
int ret;
750749

751-
mp = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
752-
if (!mp)
750+
if (d_mountpoint(dentry)) {
751+
mountpoint:
752+
read_seqlock_excl(&mount_lock);
753+
mp = lookup_mountpoint(dentry);
754+
read_sequnlock_excl(&mount_lock);
755+
if (mp)
756+
goto done;
757+
}
758+
759+
if (!new)
760+
new = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
761+
if (!new)
753762
return ERR_PTR(-ENOMEM);
754763

764+
765+
/* Exactly one processes may set d_mounted */
755766
ret = d_set_mounted(dentry);
756-
if (ret) {
757-
kfree(mp);
758-
return ERR_PTR(ret);
759-
}
760767

761-
mp->m_dentry = dentry;
762-
mp->m_count = 1;
763-
hlist_add_head(&mp->m_hash, chain);
764-
INIT_HLIST_HEAD(&mp->m_list);
768+
/* Someone else set d_mounted? */
769+
if (ret == -EBUSY)
770+
goto mountpoint;
771+
772+
/* The dentry is not available as a mountpoint? */
773+
mp = ERR_PTR(ret);
774+
if (ret)
775+
goto done;
776+
777+
/* Add the new mountpoint to the hash table */
778+
read_seqlock_excl(&mount_lock);
779+
new->m_dentry = dentry;
780+
new->m_count = 1;
781+
hlist_add_head(&new->m_hash, mp_hash(dentry));
782+
INIT_HLIST_HEAD(&new->m_list);
783+
read_sequnlock_excl(&mount_lock);
784+
785+
mp = new;
786+
new = NULL;
787+
done:
788+
kfree(new);
765789
return mp;
766790
}
767791

@@ -1595,11 +1619,11 @@ void __detach_mounts(struct dentry *dentry)
15951619
struct mount *mnt;
15961620

15971621
namespace_lock();
1622+
lock_mount_hash();
15981623
mp = lookup_mountpoint(dentry);
15991624
if (IS_ERR_OR_NULL(mp))
16001625
goto out_unlock;
16011626

1602-
lock_mount_hash();
16031627
event++;
16041628
while (!hlist_empty(&mp->m_list)) {
16051629
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
@@ -1609,9 +1633,9 @@ void __detach_mounts(struct dentry *dentry)
16091633
}
16101634
else umount_tree(mnt, UMOUNT_CONNECTED);
16111635
}
1612-
unlock_mount_hash();
16131636
put_mountpoint(mp);
16141637
out_unlock:
1638+
unlock_mount_hash();
16151639
namespace_unlock();
16161640
}
16171641

@@ -2038,9 +2062,7 @@ static struct mountpoint *lock_mount(struct path *path)
20382062
namespace_lock();
20392063
mnt = lookup_mnt(path);
20402064
if (likely(!mnt)) {
2041-
struct mountpoint *mp = lookup_mountpoint(dentry);
2042-
if (!mp)
2043-
mp = new_mountpoint(dentry);
2065+
struct mountpoint *mp = get_mountpoint(dentry);
20442066
if (IS_ERR(mp)) {
20452067
namespace_unlock();
20462068
inode_unlock(dentry->d_inode);
@@ -2059,7 +2081,11 @@ static struct mountpoint *lock_mount(struct path *path)
20592081
static void unlock_mount(struct mountpoint *where)
20602082
{
20612083
struct dentry *dentry = where->m_dentry;
2084+
2085+
read_seqlock_excl(&mount_lock);
20622086
put_mountpoint(where);
2087+
read_sequnlock_excl(&mount_lock);
2088+
20632089
namespace_unlock();
20642090
inode_unlock(dentry->d_inode);
20652091
}
@@ -3135,9 +3161,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
31353161
touch_mnt_namespace(current->nsproxy->mnt_ns);
31363162
/* A moved mount should not expire automatically */
31373163
list_del_init(&new_mnt->mnt_expire);
3164+
put_mountpoint(root_mp);
31383165
unlock_mount_hash();
31393166
chroot_fs_refs(&root, &new);
3140-
put_mountpoint(root_mp);
31413167
error = 0;
31423168
out4:
31433169
unlock_mount(old_mp);

fs/proc/proc_sysctl.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
709709
ctl_dir = container_of(head, struct ctl_dir, header);
710710

711711
if (!dir_emit_dots(file, ctx))
712-
return 0;
712+
goto out;
713713

714714
pos = 2;
715715

@@ -719,6 +719,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
719719
break;
720720
}
721721
}
722+
out:
722723
sysctl_head_finish(head);
723724
return 0;
724725
}

kernel/pid_namespace.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,12 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
151151

152152
static void delayed_free_pidns(struct rcu_head *p)
153153
{
154-
kmem_cache_free(pid_ns_cachep,
155-
container_of(p, struct pid_namespace, rcu));
154+
struct pid_namespace *ns = container_of(p, struct pid_namespace, rcu);
155+
156+
dec_pid_namespaces(ns->ucounts);
157+
put_user_ns(ns->user_ns);
158+
159+
kmem_cache_free(pid_ns_cachep, ns);
156160
}
157161

158162
static void destroy_pid_namespace(struct pid_namespace *ns)
@@ -162,8 +166,6 @@ static void destroy_pid_namespace(struct pid_namespace *ns)
162166
ns_free_inum(&ns->ns);
163167
for (i = 0; i < PIDMAP_ENTRIES; i++)
164168
kfree(ns->pidmap[i].page);
165-
dec_pid_namespaces(ns->ucounts);
166-
put_user_ns(ns->user_ns);
167169
call_rcu(&ns->rcu, delayed_free_pidns);
168170
}
169171

0 commit comments

Comments
 (0)