Skip to content

Commit

Permalink
statmount: retrieve security mount options
Browse files Browse the repository at this point in the history
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 <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
  • Loading branch information
Christian Brauner committed Nov 14, 2024
1 parent 45c9faf commit aefff51
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 15 deletions.
74 changes: 60 additions & 14 deletions fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -5072,13 +5072,30 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
return 0;
}

static inline int statmount_opt_unescape(struct seq_file *seq, char *buf_start)
{
char *buf_end, *opt_start, *opt_end;
int count = 0;

buf_end = seq->buf + seq->count;
*buf_end = '\0';
for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
opt_end = strchrnul(opt_start, ',');
*opt_end = '\0';
buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
if (WARN_ON_ONCE(++count == INT_MAX))
return -EOVERFLOW;
}
seq->count = buf_start - 1 - seq->buf;
return count;
}

static int statmount_opt_array(struct kstatmount *s, struct seq_file *seq)
{
struct vfsmount *mnt = s->mnt;
struct super_block *sb = mnt->mnt_sb;
size_t start = seq->count;
char *buf_start, *buf_end, *opt_start, *opt_end;
u32 count = 0;
char *buf_start;
int err;

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

buf_end = seq->buf + seq->count;
*buf_end = '\0';
for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
opt_end = strchrnul(opt_start, ',');
*opt_end = '\0';
buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
if (WARN_ON_ONCE(++count == 0))
return -EOVERFLOW;
}
seq->count = buf_start - 1 - seq->buf;
s->sm.opt_num = count;
err = statmount_opt_unescape(seq, buf_start);
if (err < 0)
return err;

s->sm.opt_num = err;
return 0;
}

static int statmount_opt_sec_array(struct kstatmount *s, struct seq_file *seq)
{
struct vfsmount *mnt = s->mnt;
struct super_block *sb = mnt->mnt_sb;
size_t start = seq->count;
char *buf_start;
int err;

buf_start = seq->buf + start;

err = security_sb_show_options(seq, sb);
if (!err)
return err;

if (unlikely(seq_has_overflowed(seq)))
return -EAGAIN;

if (seq->count == start)
return 0;

err = statmount_opt_unescape(seq, buf_start);
if (err < 0)
return err;

s->sm.opt_sec_num = err;
return 0;
}

Expand Down Expand Up @@ -5138,6 +5177,10 @@ static int statmount_string(struct kstatmount *s, u64 flag)
sm->opt_array = start;
ret = statmount_opt_array(s, seq);
break;
case STATMOUNT_OPT_SEC_ARRAY:
sm->opt_sec_array = start;
ret = statmount_opt_sec_array(s, seq);
break;
case STATMOUNT_FS_SUBTYPE:
sm->fs_subtype = start;
statmount_fs_subtype(s, seq);
Expand Down Expand Up @@ -5294,6 +5337,9 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
if (!err && s->mask & STATMOUNT_OPT_ARRAY)
err = statmount_string(s, STATMOUNT_OPT_ARRAY);

if (!err && s->mask & STATMOUNT_OPT_SEC_ARRAY)
err = statmount_string(s, STATMOUNT_OPT_SEC_ARRAY);

if (!err && s->mask & STATMOUNT_FS_SUBTYPE)
err = statmount_string(s, STATMOUNT_FS_SUBTYPE);

Expand Down Expand Up @@ -5323,7 +5369,7 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \
STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE | \
STATMOUNT_OPT_ARRAY)
STATMOUNT_OPT_ARRAY | STATMOUNT_OPT_SEC_ARRAY)

static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
struct statmount __user *buf, size_t bufsize,
Expand Down
5 changes: 4 additions & 1 deletion include/uapi/linux/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ struct statmount {
__u32 sb_source; /* [str] Source string of the mount */
__u32 opt_num; /* Number of fs options */
__u32 opt_array; /* [str] Array of nul terminated fs options */
__u64 __spare2[47];
__u32 opt_sec_num; /* Number of security options */
__u32 opt_sec_array; /* [str] Array of nul terminated security options */
__u64 __spare2[46];
char str[]; /* Variable size part containing strings */
};

Expand Down Expand Up @@ -214,6 +216,7 @@ struct mnt_id_req {
#define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
#define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */
#define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */

/*
* Special @mnt_id values that can be passed to listmount
Expand Down

0 comments on commit aefff51

Please sign in to comment.