Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d8423793
Commit
d8423793
authored
Jun 25, 2024
by
Christian Brauner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fs: use guard for namespace_sem in statmount()
Signed-off-by:
Christian Brauner
<
brauner@kernel.org
>
parent
a7ebb0fe
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
83 additions
and
77 deletions
+83
-77
fs/namespace.c
fs/namespace.c
+83
-77
No files found.
fs/namespace.c
View file @
d8423793
...
...
@@ -5040,17 +5040,70 @@ static int copy_statmount_to_user(struct kstatmount *s)
return
0
;
}
static
int
do_statmount
(
struct
kstatmount
*
s
)
static
struct
mount
*
listmnt_next
(
struct
mount
*
curr
,
bool
reverse
)
{
struct
mount
*
m
=
real_mount
(
s
->
mnt
);
struct
mnt_namespace
*
ns
=
m
->
mnt_ns
;
struct
rb_node
*
node
;
if
(
reverse
)
node
=
rb_prev
(
&
curr
->
mnt_node
);
else
node
=
rb_next
(
&
curr
->
mnt_node
);
return
node_to_mount
(
node
);
}
static
int
grab_requested_root
(
struct
mnt_namespace
*
ns
,
struct
path
*
root
)
{
struct
mount
*
first
;
rwsem_assert_held
(
&
namespace_sem
);
/* We're looking at our own ns, just use get_fs_root. */
if
(
ns
==
current
->
nsproxy
->
mnt_ns
)
{
get_fs_root
(
current
->
fs
,
root
);
return
0
;
}
/*
* We have to find the first mount in our ns and use that, however it
* may not exist, so handle that properly.
*/
if
(
RB_EMPTY_ROOT
(
&
ns
->
mounts
))
return
-
ENOENT
;
first
=
listmnt_next
(
ns
->
root
,
false
);
if
(
!
first
)
return
-
ENOENT
;
root
->
mnt
=
mntget
(
&
first
->
mnt
);
root
->
dentry
=
dget
(
root
->
mnt
->
mnt_root
);
return
0
;
}
static
int
do_statmount
(
struct
kstatmount
*
s
,
u64
mnt_id
,
u64
mnt_ns_id
,
struct
mnt_namespace
*
ns
)
{
struct
path
root
__free
(
path_put
)
=
{};
struct
mount
*
m
;
int
err
;
/* Has the namespace already been emptied? */
if
(
mnt_ns_id
&&
RB_EMPTY_ROOT
(
&
ns
->
mounts
))
return
-
ENOENT
;
s
->
mnt
=
lookup_mnt_in_ns
(
mnt_id
,
ns
);
if
(
!
s
->
mnt
)
return
-
ENOENT
;
err
=
grab_requested_root
(
ns
,
&
root
);
if
(
err
)
return
err
;
/*
* Don't trigger audit denials. We just want to determine what
* mounts to show users.
*/
if
(
!
is_path_reachable
(
m
,
m
->
mnt
.
mnt_root
,
&
s
->
root
)
&&
m
=
real_mount
(
s
->
mnt
);
if
(
!
is_path_reachable
(
m
,
m
->
mnt
.
mnt_root
,
&
root
)
&&
!
ns_capable_noaudit
(
ns
->
user_ns
,
CAP_SYS_ADMIN
))
return
-
EPERM
;
...
...
@@ -5058,6 +5111,7 @@ static int do_statmount(struct kstatmount *s)
if
(
err
)
return
err
;
s
->
root
=
root
;
if
(
s
->
mask
&
STATMOUNT_SB_BASIC
)
statmount_sb_basic
(
s
);
...
...
@@ -5096,6 +5150,9 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
return
true
;
}
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
STATMOUNT_FS_TYPE)
static
int
prepare_kstatmount
(
struct
kstatmount
*
ks
,
struct
mnt_id_req
*
kreq
,
struct
statmount
__user
*
buf
,
size_t
bufsize
,
size_t
seq_size
)
...
...
@@ -5107,10 +5164,18 @@ static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
ks
->
mask
=
kreq
->
param
;
ks
->
buf
=
buf
;
ks
->
bufsize
=
bufsize
;
ks
->
seq
.
size
=
seq_size
;
ks
->
seq
.
buf
=
kvmalloc
(
seq_size
,
GFP_KERNEL_ACCOUNT
);
if
(
!
ks
->
seq
.
buf
)
return
-
ENOMEM
;
if
(
ks
->
mask
&
STATMOUNT_STRING_REQ
)
{
if
(
bufsize
==
sizeof
(
ks
->
sm
))
return
-
EOVERFLOW
;
ks
->
seq
.
buf
=
kvmalloc
(
seq_size
,
GFP_KERNEL_ACCOUNT
);
if
(
!
ks
->
seq
.
buf
)
return
-
ENOMEM
;
ks
->
seq
.
size
=
seq_size
;
}
return
0
;
}
...
...
@@ -5138,45 +5203,6 @@ static int copy_mnt_id_req(const struct mnt_id_req __user *req,
return
0
;
}
static
struct
mount
*
listmnt_next
(
struct
mount
*
curr
,
bool
reverse
)
{
struct
rb_node
*
node
;
if
(
reverse
)
node
=
rb_prev
(
&
curr
->
mnt_node
);
else
node
=
rb_next
(
&
curr
->
mnt_node
);
return
node_to_mount
(
node
);
}
static
int
grab_requested_root
(
struct
mnt_namespace
*
ns
,
struct
path
*
root
)
{
struct
mount
*
first
;
rwsem_assert_held
(
&
namespace_sem
);
/* We're looking at our own ns, just use get_fs_root. */
if
(
ns
==
current
->
nsproxy
->
mnt_ns
)
{
get_fs_root
(
current
->
fs
,
root
);
return
0
;
}
/*
* We have to find the first mount in our ns and use that, however it
* may not exist, so handle that properly.
*/
if
(
RB_EMPTY_ROOT
(
&
ns
->
mounts
))
return
-
ENOENT
;
first
=
listmnt_next
(
ns
->
root
,
false
);
if
(
!
first
)
return
-
ENOENT
;
root
->
mnt
=
mntget
(
&
first
->
mnt
);
root
->
dentry
=
dget
(
root
->
mnt
->
mnt_root
);
return
0
;
}
/*
* If the user requested a specific mount namespace id, look that up and return
* 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,
unsigned
int
,
flags
)
{
struct
mnt_namespace
*
ns
__free
(
mnt_ns_release
)
=
NULL
;
struct
vfsmount
*
mnt
;
struct
kstatmount
*
ks
__free
(
kfree
)
=
NULL
;
struct
mnt_id_req
kreq
;
struct
kstatmount
ks
;
/* We currently support retrieval of 3 strings. */
size_t
seq_size
=
3
*
PATH_MAX
;
int
ret
;
...
...
@@ -5217,40 +5242,21 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
!
ns_capable_noaudit
(
ns
->
user_ns
,
CAP_SYS_ADMIN
))
return
-
ENOENT
;
ks
=
kmalloc
(
sizeof
(
*
ks
),
GFP_KERNEL_ACCOUNT
);
if
(
!
ks
)
return
-
ENOMEM
;
retry:
ret
=
prepare_kstatmount
(
&
ks
,
&
kreq
,
buf
,
bufsize
,
seq_size
);
ret
=
prepare_kstatmount
(
ks
,
&
kreq
,
buf
,
bufsize
,
seq_size
);
if
(
ret
)
return
ret
;
down_read
(
&
namespace_sem
);
/* Has the namespace already been emptied? */
if
(
kreq
.
mnt_ns_id
&&
RB_EMPTY_ROOT
(
&
ns
->
mounts
))
{
up_read
(
&
namespace_sem
);
kvfree
(
ks
.
seq
.
buf
);
return
-
ENOENT
;
}
mnt
=
lookup_mnt_in_ns
(
kreq
.
mnt_id
,
ns
);
if
(
!
mnt
)
{
up_read
(
&
namespace_sem
);
kvfree
(
ks
.
seq
.
buf
);
return
-
ENOENT
;
}
ks
.
mnt
=
mnt
;
ret
=
grab_requested_root
(
ns
,
&
ks
.
root
);
if
(
ret
)
{
up_read
(
&
namespace_sem
);
kvfree
(
ks
.
seq
.
buf
);
return
ret
;
}
ret
=
do_statmount
(
&
ks
);
path_put
(
&
ks
.
root
);
up_read
(
&
namespace_sem
);
scoped_guard
(
rwsem_read
,
&
namespace_sem
)
ret
=
do_statmount
(
ks
,
kreq
.
mnt_id
,
kreq
.
mnt_ns_id
,
ns
);
if
(
!
ret
)
ret
=
copy_statmount_to_user
(
&
ks
);
kvfree
(
ks
.
seq
.
buf
);
ret
=
copy_statmount_to_user
(
ks
);
kvfree
(
ks
->
seq
.
buf
);
if
(
retry_statmount
(
ret
,
&
seq_size
))
goto
retry
;
return
ret
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment