Skip to content

Commit aefff51

Browse files
committed
statmount: retrieve security mount options
Add the ability to retrieve security mount options. Keep them separate from filesystem specific mount options so it's easy to tell them apart. Also allow to retrieve them separate from other mount options as most of the time users won't be interested in security specific mount options. Link: https://lore.kernel.org/r/20241114-radtour-ofenrohr-ff34b567b40a@brauner Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 45c9faf commit aefff51

File tree

2 files changed

+64
-15
lines changed

2 files changed

+64
-15
lines changed

fs/namespace.c

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5072,13 +5072,30 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
50725072
return 0;
50735073
}
50745074

5075+
static inline int statmount_opt_unescape(struct seq_file *seq, char *buf_start)
5076+
{
5077+
char *buf_end, *opt_start, *opt_end;
5078+
int count = 0;
5079+
5080+
buf_end = seq->buf + seq->count;
5081+
*buf_end = '\0';
5082+
for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
5083+
opt_end = strchrnul(opt_start, ',');
5084+
*opt_end = '\0';
5085+
buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
5086+
if (WARN_ON_ONCE(++count == INT_MAX))
5087+
return -EOVERFLOW;
5088+
}
5089+
seq->count = buf_start - 1 - seq->buf;
5090+
return count;
5091+
}
5092+
50755093
static int statmount_opt_array(struct kstatmount *s, struct seq_file *seq)
50765094
{
50775095
struct vfsmount *mnt = s->mnt;
50785096
struct super_block *sb = mnt->mnt_sb;
50795097
size_t start = seq->count;
5080-
char *buf_start, *buf_end, *opt_start, *opt_end;
5081-
u32 count = 0;
5098+
char *buf_start;
50825099
int err;
50835100

50845101
if (!sb->s_op->show_options)
@@ -5095,17 +5112,39 @@ static int statmount_opt_array(struct kstatmount *s, struct seq_file *seq)
50955112
if (seq->count == start)
50965113
return 0;
50975114

5098-
buf_end = seq->buf + seq->count;
5099-
*buf_end = '\0';
5100-
for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
5101-
opt_end = strchrnul(opt_start, ',');
5102-
*opt_end = '\0';
5103-
buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
5104-
if (WARN_ON_ONCE(++count == 0))
5105-
return -EOVERFLOW;
5106-
}
5107-
seq->count = buf_start - 1 - seq->buf;
5108-
s->sm.opt_num = count;
5115+
err = statmount_opt_unescape(seq, buf_start);
5116+
if (err < 0)
5117+
return err;
5118+
5119+
s->sm.opt_num = err;
5120+
return 0;
5121+
}
5122+
5123+
static int statmount_opt_sec_array(struct kstatmount *s, struct seq_file *seq)
5124+
{
5125+
struct vfsmount *mnt = s->mnt;
5126+
struct super_block *sb = mnt->mnt_sb;
5127+
size_t start = seq->count;
5128+
char *buf_start;
5129+
int err;
5130+
5131+
buf_start = seq->buf + start;
5132+
5133+
err = security_sb_show_options(seq, sb);
5134+
if (!err)
5135+
return err;
5136+
5137+
if (unlikely(seq_has_overflowed(seq)))
5138+
return -EAGAIN;
5139+
5140+
if (seq->count == start)
5141+
return 0;
5142+
5143+
err = statmount_opt_unescape(seq, buf_start);
5144+
if (err < 0)
5145+
return err;
5146+
5147+
s->sm.opt_sec_num = err;
51095148
return 0;
51105149
}
51115150

@@ -5138,6 +5177,10 @@ static int statmount_string(struct kstatmount *s, u64 flag)
51385177
sm->opt_array = start;
51395178
ret = statmount_opt_array(s, seq);
51405179
break;
5180+
case STATMOUNT_OPT_SEC_ARRAY:
5181+
sm->opt_sec_array = start;
5182+
ret = statmount_opt_sec_array(s, seq);
5183+
break;
51415184
case STATMOUNT_FS_SUBTYPE:
51425185
sm->fs_subtype = start;
51435186
statmount_fs_subtype(s, seq);
@@ -5294,6 +5337,9 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
52945337
if (!err && s->mask & STATMOUNT_OPT_ARRAY)
52955338
err = statmount_string(s, STATMOUNT_OPT_ARRAY);
52965339

5340+
if (!err && s->mask & STATMOUNT_OPT_SEC_ARRAY)
5341+
err = statmount_string(s, STATMOUNT_OPT_SEC_ARRAY);
5342+
52975343
if (!err && s->mask & STATMOUNT_FS_SUBTYPE)
52985344
err = statmount_string(s, STATMOUNT_FS_SUBTYPE);
52995345

@@ -5323,7 +5369,7 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
53235369
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
53245370
STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \
53255371
STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE | \
5326-
STATMOUNT_OPT_ARRAY)
5372+
STATMOUNT_OPT_ARRAY | STATMOUNT_OPT_SEC_ARRAY)
53275373

53285374
static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
53295375
struct statmount __user *buf, size_t bufsize,

include/uapi/linux/mount.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,9 @@ struct statmount {
177177
__u32 sb_source; /* [str] Source string of the mount */
178178
__u32 opt_num; /* Number of fs options */
179179
__u32 opt_array; /* [str] Array of nul terminated fs options */
180-
__u64 __spare2[47];
180+
__u32 opt_sec_num; /* Number of security options */
181+
__u32 opt_sec_array; /* [str] Array of nul terminated security options */
182+
__u64 __spare2[46];
181183
char str[]; /* Variable size part containing strings */
182184
};
183185

@@ -214,6 +216,7 @@ struct mnt_id_req {
214216
#define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
215217
#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
216218
#define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */
219+
#define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */
217220

218221
/*
219222
* Special @mnt_id values that can be passed to listmount

0 commit comments

Comments
 (0)