Skip to content

Commit d842379

Browse files
committed
fs: use guard for namespace_sem in statmount()
Signed-off-by: Christian Brauner <[email protected]>
1 parent a7ebb0f commit d842379

File tree

1 file changed

+83
-77
lines changed

1 file changed

+83
-77
lines changed

fs/namespace.c

Lines changed: 83 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -5040,24 +5040,78 @@ static int copy_statmount_to_user(struct kstatmount *s)
50405040
return 0;
50415041
}
50425042

5043-
static int do_statmount(struct kstatmount *s)
5043+
static struct mount *listmnt_next(struct mount *curr, bool reverse)
50445044
{
5045-
struct mount *m = real_mount(s->mnt);
5046-
struct mnt_namespace *ns = m->mnt_ns;
5045+
struct rb_node *node;
5046+
5047+
if (reverse)
5048+
node = rb_prev(&curr->mnt_node);
5049+
else
5050+
node = rb_next(&curr->mnt_node);
5051+
5052+
return node_to_mount(node);
5053+
}
5054+
5055+
static int grab_requested_root(struct mnt_namespace *ns, struct path *root)
5056+
{
5057+
struct mount *first;
5058+
5059+
rwsem_assert_held(&namespace_sem);
5060+
5061+
/* We're looking at our own ns, just use get_fs_root. */
5062+
if (ns == current->nsproxy->mnt_ns) {
5063+
get_fs_root(current->fs, root);
5064+
return 0;
5065+
}
5066+
5067+
/*
5068+
* We have to find the first mount in our ns and use that, however it
5069+
* may not exist, so handle that properly.
5070+
*/
5071+
if (RB_EMPTY_ROOT(&ns->mounts))
5072+
return -ENOENT;
5073+
5074+
first = listmnt_next(ns->root, false);
5075+
if (!first)
5076+
return -ENOENT;
5077+
root->mnt = mntget(&first->mnt);
5078+
root->dentry = dget(root->mnt->mnt_root);
5079+
return 0;
5080+
}
5081+
5082+
static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
5083+
struct mnt_namespace *ns)
5084+
{
5085+
struct path root __free(path_put) = {};
5086+
struct mount *m;
50475087
int err;
50485088

5089+
/* Has the namespace already been emptied? */
5090+
if (mnt_ns_id && RB_EMPTY_ROOT(&ns->mounts))
5091+
return -ENOENT;
5092+
5093+
s->mnt = lookup_mnt_in_ns(mnt_id, ns);
5094+
if (!s->mnt)
5095+
return -ENOENT;
5096+
5097+
err = grab_requested_root(ns, &root);
5098+
if (err)
5099+
return err;
5100+
50495101
/*
50505102
* Don't trigger audit denials. We just want to determine what
50515103
* mounts to show users.
50525104
*/
5053-
if (!is_path_reachable(m, m->mnt.mnt_root, &s->root) &&
5105+
m = real_mount(s->mnt);
5106+
if (!is_path_reachable(m, m->mnt.mnt_root, &root) &&
50545107
!ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN))
50555108
return -EPERM;
50565109

50575110
err = security_sb_statfs(s->mnt->mnt_root);
50585111
if (err)
50595112
return err;
50605113

5114+
s->root = root;
50615115
if (s->mask & STATMOUNT_SB_BASIC)
50625116
statmount_sb_basic(s);
50635117

@@ -5096,6 +5150,9 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
50965150
return true;
50975151
}
50985152

5153+
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
5154+
STATMOUNT_FS_TYPE)
5155+
50995156
static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
51005157
struct statmount __user *buf, size_t bufsize,
51015158
size_t seq_size)
@@ -5107,10 +5164,18 @@ static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
51075164
ks->mask = kreq->param;
51085165
ks->buf = buf;
51095166
ks->bufsize = bufsize;
5110-
ks->seq.size = seq_size;
5111-
ks->seq.buf = kvmalloc(seq_size, GFP_KERNEL_ACCOUNT);
5112-
if (!ks->seq.buf)
5113-
return -ENOMEM;
5167+
5168+
if (ks->mask & STATMOUNT_STRING_REQ) {
5169+
if (bufsize == sizeof(ks->sm))
5170+
return -EOVERFLOW;
5171+
5172+
ks->seq.buf = kvmalloc(seq_size, GFP_KERNEL_ACCOUNT);
5173+
if (!ks->seq.buf)
5174+
return -ENOMEM;
5175+
5176+
ks->seq.size = seq_size;
5177+
}
5178+
51145179
return 0;
51155180
}
51165181

@@ -5138,45 +5203,6 @@ static int copy_mnt_id_req(const struct mnt_id_req __user *req,
51385203
return 0;
51395204
}
51405205

5141-
static struct mount *listmnt_next(struct mount *curr, bool reverse)
5142-
{
5143-
struct rb_node *node;
5144-
5145-
if (reverse)
5146-
node = rb_prev(&curr->mnt_node);
5147-
else
5148-
node = rb_next(&curr->mnt_node);
5149-
5150-
return node_to_mount(node);
5151-
}
5152-
5153-
static int grab_requested_root(struct mnt_namespace *ns, struct path *root)
5154-
{
5155-
struct mount *first;
5156-
5157-
rwsem_assert_held(&namespace_sem);
5158-
5159-
/* We're looking at our own ns, just use get_fs_root. */
5160-
if (ns == current->nsproxy->mnt_ns) {
5161-
get_fs_root(current->fs, root);
5162-
return 0;
5163-
}
5164-
5165-
/*
5166-
* We have to find the first mount in our ns and use that, however it
5167-
* may not exist, so handle that properly.
5168-
*/
5169-
if (RB_EMPTY_ROOT(&ns->mounts))
5170-
return -ENOENT;
5171-
5172-
first = listmnt_next(ns->root, false);
5173-
if (!first)
5174-
return -ENOENT;
5175-
root->mnt = mntget(&first->mnt);
5176-
root->dentry = dget(root->mnt->mnt_root);
5177-
return 0;
5178-
}
5179-
51805206
/*
51815207
* If the user requested a specific mount namespace id, look that up and return
51825208
* that, or if not simply grab a passive reference on our mount namespace and
@@ -5195,9 +5221,8 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
51955221
unsigned int, flags)
51965222
{
51975223
struct mnt_namespace *ns __free(mnt_ns_release) = NULL;
5198-
struct vfsmount *mnt;
5224+
struct kstatmount *ks __free(kfree) = NULL;
51995225
struct mnt_id_req kreq;
5200-
struct kstatmount ks;
52015226
/* We currently support retrieval of 3 strings. */
52025227
size_t seq_size = 3 * PATH_MAX;
52035228
int ret;
@@ -5217,40 +5242,21 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
52175242
!ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN))
52185243
return -ENOENT;
52195244

5245+
ks = kmalloc(sizeof(*ks), GFP_KERNEL_ACCOUNT);
5246+
if (!ks)
5247+
return -ENOMEM;
5248+
52205249
retry:
5221-
ret = prepare_kstatmount(&ks, &kreq, buf, bufsize, seq_size);
5250+
ret = prepare_kstatmount(ks, &kreq, buf, bufsize, seq_size);
52225251
if (ret)
52235252
return ret;
52245253

5225-
down_read(&namespace_sem);
5226-
/* Has the namespace already been emptied? */
5227-
if (kreq.mnt_ns_id && RB_EMPTY_ROOT(&ns->mounts)) {
5228-
up_read(&namespace_sem);
5229-
kvfree(ks.seq.buf);
5230-
return -ENOENT;
5231-
}
5232-
5233-
mnt = lookup_mnt_in_ns(kreq.mnt_id, ns);
5234-
if (!mnt) {
5235-
up_read(&namespace_sem);
5236-
kvfree(ks.seq.buf);
5237-
return -ENOENT;
5238-
}
5239-
5240-
ks.mnt = mnt;
5241-
ret = grab_requested_root(ns, &ks.root);
5242-
if (ret) {
5243-
up_read(&namespace_sem);
5244-
kvfree(ks.seq.buf);
5245-
return ret;
5246-
}
5247-
ret = do_statmount(&ks);
5248-
path_put(&ks.root);
5249-
up_read(&namespace_sem);
5254+
scoped_guard(rwsem_read, &namespace_sem)
5255+
ret = do_statmount(ks, kreq.mnt_id, kreq.mnt_ns_id, ns);
52505256

52515257
if (!ret)
5252-
ret = copy_statmount_to_user(&ks);
5253-
kvfree(ks.seq.buf);
5258+
ret = copy_statmount_to_user(ks);
5259+
kvfree(ks->seq.buf);
52545260
if (retry_statmount(ret, &seq_size))
52555261
goto retry;
52565262
return ret;

0 commit comments

Comments
 (0)