The patch titled Subject: vfs: parse: deal with zero length string value has been added to the -mm mm-nonmm-unstable branch. Its filename is vfs-parse-deal-with-zero-length-string-value.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/vfs-parse-deal-with-zero-length-string-value.patch This patch will later appear in the mm-nonmm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via the mm-everything branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there every 2-3 working days ------------------------------------------------------ From: Ian Kent <raven@xxxxxxxxxx> Subject: vfs: parse: deal with zero length string value Date: Tue, 20 Sep 2022 15:26:29 +0800 Parsing an fs string that has zero length should result in the parameter being set to NULL so that downstream processing handles it correctly. For example, the proc mount table processing should print "(none)" in this case to preserve mount record field count, but if the value points to the NULL string this doesn't happen. Link: https://lkml.kernel.org/r/166365878918.39016.12757946948158123324.stgit@xxxxxxxxxxxxxxxxx Signed-off-by: Ian Kent <raven@xxxxxxxxxx> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Carlos Maiolino <cmaiolino@xxxxxxxxxx> Cc: David Howells <dhowells@xxxxxxxxxx> Cc: kernel test robot <oliver.sang@xxxxxxxxx> Cc: Miklos Szeredi <miklos@xxxxxxxxxx> Cc: Siddhesh Poyarekar <siddhesh@xxxxxxxxxx> Cc: Theodore Ts'o <tytso@xxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- fs/fs_context.c | 17 ++++++++++++----- fs/fs_parser.c | 16 ++++++++++++++++ include/linux/fs_context.h | 3 ++- 3 files changed, 30 insertions(+), 6 deletions(-) --- a/fs/fs_context.c~vfs-parse-deal-with-zero-length-string-value +++ a/fs/fs_context.c @@ -96,7 +96,9 @@ int vfs_parse_fs_param_source(struct fs_ if (strcmp(param->key, "source") != 0) return -ENOPARAM; - if (param->type != fs_value_is_string) + /* source value may be NULL */ + if (param->type != fs_value_is_string && + param->type != fs_value_is_empty) return invalf(fc, "Non-string source"); if (fc->source) @@ -175,10 +177,15 @@ int vfs_parse_fs_string(struct fs_contex }; if (value) { - param.string = kmemdup_nul(value, v_size, GFP_KERNEL); - if (!param.string) - return -ENOMEM; - param.type = fs_value_is_string; + if (!v_size) { + param.string = NULL; + param.type = fs_value_is_empty; + } else { + param.string = kmemdup_nul(value, v_size, GFP_KERNEL); + if (!param.string) + return -ENOMEM; + param.type = fs_value_is_string; + } } ret = vfs_parse_fs_param(fc, ¶m); --- a/fs/fs_parser.c~vfs-parse-deal-with-zero-length-string-value +++ a/fs/fs_parser.c @@ -197,6 +197,8 @@ int fs_param_is_bool(struct p_log *log, struct fs_parameter *param, struct fs_parse_result *result) { int b; + if (param->type == fs_value_is_empty) + return 0; if (param->type != fs_value_is_string) return fs_param_bad_value(log, param); if (!*param->string && (p->flags & fs_param_can_be_empty)) @@ -213,6 +215,8 @@ int fs_param_is_u32(struct p_log *log, c struct fs_parameter *param, struct fs_parse_result *result) { int base = (unsigned long)p->data; + if (param->type == fs_value_is_empty) + return 0; if (param->type != fs_value_is_string) return fs_param_bad_value(log, param); if (!*param->string && (p->flags & fs_param_can_be_empty)) @@ -226,6 +230,8 @@ EXPORT_SYMBOL(fs_param_is_u32); int fs_param_is_s32(struct p_log *log, const struct fs_parameter_spec *p, struct fs_parameter *param, struct fs_parse_result *result) { + if (param->type == fs_value_is_empty) + return 0; if (param->type != fs_value_is_string) return fs_param_bad_value(log, param); if (!*param->string && (p->flags & fs_param_can_be_empty)) @@ -239,6 +245,8 @@ EXPORT_SYMBOL(fs_param_is_s32); int fs_param_is_u64(struct p_log *log, const struct fs_parameter_spec *p, struct fs_parameter *param, struct fs_parse_result *result) { + if (param->type == fs_value_is_empty) + return 0; if (param->type != fs_value_is_string) return fs_param_bad_value(log, param); if (!*param->string && (p->flags & fs_param_can_be_empty)) @@ -253,6 +261,8 @@ int fs_param_is_enum(struct p_log *log, struct fs_parameter *param, struct fs_parse_result *result) { const struct constant_table *c; + if (param->type == fs_value_is_empty) + return 0; if (param->type != fs_value_is_string) return fs_param_bad_value(log, param); if (!*param->string && (p->flags & fs_param_can_be_empty)) @@ -268,6 +278,8 @@ EXPORT_SYMBOL(fs_param_is_enum); int fs_param_is_string(struct p_log *log, const struct fs_parameter_spec *p, struct fs_parameter *param, struct fs_parse_result *result) { + if (param->type == fs_value_is_empty) + return 0; if (param->type != fs_value_is_string || (!*param->string && !(p->flags & fs_param_can_be_empty))) return fs_param_bad_value(log, param); @@ -278,6 +290,8 @@ EXPORT_SYMBOL(fs_param_is_string); int fs_param_is_blob(struct p_log *log, const struct fs_parameter_spec *p, struct fs_parameter *param, struct fs_parse_result *result) { + if (param->type == fs_value_is_empty) + return 0; if (param->type != fs_value_is_blob) return fs_param_bad_value(log, param); return 0; @@ -287,6 +301,8 @@ EXPORT_SYMBOL(fs_param_is_blob); int fs_param_is_fd(struct p_log *log, const struct fs_parameter_spec *p, struct fs_parameter *param, struct fs_parse_result *result) { + if (param->type == fs_value_is_empty) + return 0; switch (param->type) { case fs_value_is_string: if ((!*param->string && !(p->flags & fs_param_can_be_empty)) || --- a/include/linux/fs_context.h~vfs-parse-deal-with-zero-length-string-value +++ a/include/linux/fs_context.h @@ -50,7 +50,8 @@ enum fs_context_phase { */ enum fs_value_type { fs_value_is_undefined, - fs_value_is_flag, /* Value not given a value */ + fs_value_is_flag, /* Does not take a value */ + fs_value_is_empty, /* Value is not given */ fs_value_is_string, /* Value is a string */ fs_value_is_blob, /* Value is a binary blob */ fs_value_is_filename, /* Value is a filename* + dirfd */ _ Patches currently in -mm which might be from raven@xxxxxxxxxx are ext4-fix-possible-null-pointer-dereference.patch vfs-parse-deal-with-zero-length-string-value.patch