Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

statmount: let unset strings be empty

Just like it's normal for unset values to be zero, unset strings should be
empty instead of containing random values.

It seems to be a typical mistake that the mask returned by statmount is not
checked, which can result in various bugs.

With this fix, these bugs are prevented, since it is highly likely that
userspace would just want to turn the missing mask case into an empty
string anyway (most of the recently found cases are of this type).

Link: https://lore.kernel.org/all/CAJfpegsVCPfCn2DpM8iiYSS5DpMsLB8QBUCHecoj6s0Vxf4jzg@mail.gmail.com/
Fixes: 68385d77c05b ("statmount: simplify string option retrieval")
Fixes: 46eae99ef733 ("add statmount(2) syscall")
Cc: stable@vger.kernel.org # v6.8
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Link: https://lore.kernel.org/r/20250130121500.113446-1-mszeredi@redhat.com
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Miklos Szeredi and committed by
Christian Brauner
e52e97f0 4e748724

+16 -9
+16 -9
fs/namespace.c
··· 5191 5191 size_t kbufsize; 5192 5192 struct seq_file *seq = &s->seq; 5193 5193 struct statmount *sm = &s->sm; 5194 - u32 start = seq->count; 5194 + u32 start, *offp; 5195 + 5196 + /* Reserve an empty string at the beginning for any unset offsets */ 5197 + if (!seq->count) 5198 + seq_putc(seq, 0); 5199 + 5200 + start = seq->count; 5195 5201 5196 5202 switch (flag) { 5197 5203 case STATMOUNT_FS_TYPE: 5198 - sm->fs_type = start; 5204 + offp = &sm->fs_type; 5199 5205 ret = statmount_fs_type(s, seq); 5200 5206 break; 5201 5207 case STATMOUNT_MNT_ROOT: 5202 - sm->mnt_root = start; 5208 + offp = &sm->mnt_root; 5203 5209 ret = statmount_mnt_root(s, seq); 5204 5210 break; 5205 5211 case STATMOUNT_MNT_POINT: 5206 - sm->mnt_point = start; 5212 + offp = &sm->mnt_point; 5207 5213 ret = statmount_mnt_point(s, seq); 5208 5214 break; 5209 5215 case STATMOUNT_MNT_OPTS: 5210 - sm->mnt_opts = start; 5216 + offp = &sm->mnt_opts; 5211 5217 ret = statmount_mnt_opts(s, seq); 5212 5218 break; 5213 5219 case STATMOUNT_OPT_ARRAY: 5214 - sm->opt_array = start; 5220 + offp = &sm->opt_array; 5215 5221 ret = statmount_opt_array(s, seq); 5216 5222 break; 5217 5223 case STATMOUNT_OPT_SEC_ARRAY: 5218 - sm->opt_sec_array = start; 5224 + offp = &sm->opt_sec_array; 5219 5225 ret = statmount_opt_sec_array(s, seq); 5220 5226 break; 5221 5227 case STATMOUNT_FS_SUBTYPE: 5222 - sm->fs_subtype = start; 5228 + offp = &sm->fs_subtype; 5223 5229 statmount_fs_subtype(s, seq); 5224 5230 break; 5225 5231 case STATMOUNT_SB_SOURCE: 5226 - sm->sb_source = start; 5232 + offp = &sm->sb_source; 5227 5233 ret = statmount_sb_source(s, seq); 5228 5234 break; 5229 5235 default: ··· 5257 5251 5258 5252 seq->buf[seq->count++] = '\0'; 5259 5253 sm->mask |= flag; 5254 + *offp = start; 5260 5255 return 0; 5261 5256 } 5262 5257