fs_parse: add uid & gid option option parsing helpers

Multiple filesystems take uid and gid as options, and the code to
create the ID from an integer and validate it is standard boilerplate
that can be moved into common helper functions, so do that for
consistency and less cut&paste.

This also helps avoid the buggy pattern noted by Seth Jenkins at
https://lore.kernel.org/lkml/CALxfFW4BXhEwxR0Q5LSkg-8Vb4r2MONKCcUCVioehXQKr35eHg@mail.gmail.com/
because uid/gid parsing will fail before any assignment in most
filesystems.

Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
Link: https://lore.kernel.org/r/de859d0a-feb9-473d-a5e2-c195a3d47abb@redhat.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Eric Sandeen 2024-06-27 19:26:24 -05:00 committed by Christian Brauner
parent 104eef133f
commit 9f111059e7
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
3 changed files with 46 additions and 3 deletions

View File

@ -645,6 +645,8 @@ The members are as follows:
fs_param_is_blockdev Blockdev path * Needs lookup fs_param_is_blockdev Blockdev path * Needs lookup
fs_param_is_path Path * Needs lookup fs_param_is_path Path * Needs lookup
fs_param_is_fd File descriptor result->int_32 fs_param_is_fd File descriptor result->int_32
fs_param_is_uid User ID (u32) result->uid
fs_param_is_gid Group ID (u32) result->gid
======================= ======================= ===================== ======================= ======================= =====================
Note that if the value is of fs_param_is_bool type, fs_parse() will try Note that if the value is of fs_param_is_bool type, fs_parse() will try
@ -678,6 +680,8 @@ The members are as follows:
fsparam_bdev() fs_param_is_blockdev fsparam_bdev() fs_param_is_blockdev
fsparam_path() fs_param_is_path fsparam_path() fs_param_is_path
fsparam_fd() fs_param_is_fd fsparam_fd() fs_param_is_fd
fsparam_uid() fs_param_is_uid
fsparam_gid() fs_param_is_gid
======================= =============================================== ======================= ===============================================
all of which take two arguments, name string and option number - for all of which take two arguments, name string and option number - for
@ -784,8 +788,9 @@ process the parameters it is given.
option number (which it returns). option number (which it returns).
If successful, and if the parameter type indicates the result is a If successful, and if the parameter type indicates the result is a
boolean, integer or enum type, the value is converted by this function and boolean, integer, enum, uid, or gid type, the value is converted by this
the result stored in result->{boolean,int_32,uint_32,uint_64}. function and the result stored in
result->{boolean,int_32,uint_32,uint_64,uid,gid}.
If a match isn't initially made, the key is prefixed with "no" and no If a match isn't initially made, the key is prefixed with "no" and no
value is present then an attempt will be made to look up the key with the value is present then an attempt will be made to look up the key with the

View File

@ -308,6 +308,40 @@ int fs_param_is_fd(struct p_log *log, const struct fs_parameter_spec *p,
} }
EXPORT_SYMBOL(fs_param_is_fd); EXPORT_SYMBOL(fs_param_is_fd);
int fs_param_is_uid(struct p_log *log, const struct fs_parameter_spec *p,
struct fs_parameter *param, struct fs_parse_result *result)
{
kuid_t uid;
if (fs_param_is_u32(log, p, param, result) != 0)
return fs_param_bad_value(log, param);
uid = make_kuid(current_user_ns(), result->uint_32);
if (!uid_valid(uid))
return inval_plog(log, "Invalid uid '%s'", param->string);
result->uid = uid;
return 0;
}
EXPORT_SYMBOL(fs_param_is_uid);
int fs_param_is_gid(struct p_log *log, const struct fs_parameter_spec *p,
struct fs_parameter *param, struct fs_parse_result *result)
{
kgid_t gid;
if (fs_param_is_u32(log, p, param, result) != 0)
return fs_param_bad_value(log, param);
gid = make_kgid(current_user_ns(), result->uint_32);
if (!gid_valid(gid))
return inval_plog(log, "Invalid gid '%s'", param->string);
result->gid = gid;
return 0;
}
EXPORT_SYMBOL(fs_param_is_gid);
int fs_param_is_blockdev(struct p_log *log, const struct fs_parameter_spec *p, int fs_param_is_blockdev(struct p_log *log, const struct fs_parameter_spec *p,
struct fs_parameter *param, struct fs_parse_result *result) struct fs_parameter *param, struct fs_parse_result *result)
{ {

View File

@ -28,7 +28,7 @@ typedef int fs_param_type(struct p_log *,
*/ */
fs_param_type fs_param_is_bool, fs_param_is_u32, fs_param_is_s32, fs_param_is_u64, fs_param_type fs_param_is_bool, fs_param_is_u32, fs_param_is_s32, fs_param_is_u64,
fs_param_is_enum, fs_param_is_string, fs_param_is_blob, fs_param_is_blockdev, fs_param_is_enum, fs_param_is_string, fs_param_is_blob, fs_param_is_blockdev,
fs_param_is_path, fs_param_is_fd; fs_param_is_path, fs_param_is_fd, fs_param_is_uid, fs_param_is_gid;
/* /*
* Specification of the type of value a parameter wants. * Specification of the type of value a parameter wants.
@ -57,6 +57,8 @@ struct fs_parse_result {
int int_32; /* For spec_s32/spec_enum */ int int_32; /* For spec_s32/spec_enum */
unsigned int uint_32; /* For spec_u32{,_octal,_hex}/spec_enum */ unsigned int uint_32; /* For spec_u32{,_octal,_hex}/spec_enum */
u64 uint_64; /* For spec_u64 */ u64 uint_64; /* For spec_u64 */
kuid_t uid;
kgid_t gid;
}; };
}; };
@ -131,6 +133,8 @@ static inline bool fs_validate_description(const char *name,
#define fsparam_bdev(NAME, OPT) __fsparam(fs_param_is_blockdev, NAME, OPT, 0, NULL) #define fsparam_bdev(NAME, OPT) __fsparam(fs_param_is_blockdev, NAME, OPT, 0, NULL)
#define fsparam_path(NAME, OPT) __fsparam(fs_param_is_path, NAME, OPT, 0, NULL) #define fsparam_path(NAME, OPT) __fsparam(fs_param_is_path, NAME, OPT, 0, NULL)
#define fsparam_fd(NAME, OPT) __fsparam(fs_param_is_fd, NAME, OPT, 0, NULL) #define fsparam_fd(NAME, OPT) __fsparam(fs_param_is_fd, NAME, OPT, 0, NULL)
#define fsparam_uid(NAME, OPT) __fsparam(fs_param_is_uid, NAME, OPT, 0, NULL)
#define fsparam_gid(NAME, OPT) __fsparam(fs_param_is_gid, NAME, OPT, 0, NULL)
/* String parameter that allows empty argument */ /* String parameter that allows empty argument */
#define fsparam_string_empty(NAME, OPT) \ #define fsparam_string_empty(NAME, OPT) \