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

Configure Feed

Select the types of activity you want to include in your feed.

stat: fix inconsistency between struct stat and struct compat_stat

struct stat (defined in arch/x86/include/uapi/asm/stat.h) has 32-bit
st_dev and st_rdev; struct compat_stat (defined in
arch/x86/include/asm/compat.h) has 16-bit st_dev and st_rdev followed by
a 16-bit padding.

This patch fixes struct compat_stat to match struct stat.

[ Historical note: the old x86 'struct stat' did have that 16-bit field
that the compat layer had kept around, but it was changes back in 2003
by "struct stat - support larger dev_t":

https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/?id=e95b2065677fe32512a597a79db94b77b90c968d

and back in those days, the x86_64 port was still new, and separate
from the i386 code, and had already picked up the old version with a
16-bit st_dev field ]

Note that we can't change compat_dev_t because it is used by
compat_loop_info.

Also, if the st_dev and st_rdev values are 32-bit, we don't have to use
old_valid_dev to test if the value fits into them. This fixes
-EOVERFLOW on filesystems that are on NVMe because NVMe uses the major
number 259.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: Andreas Schwab <schwab@linux-m68k.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Mikulas Patocka and committed by
Linus Torvalds
932aba1e 7281a59c

+12 -13
+2 -4
arch/x86/include/asm/compat.h
··· 28 28 typedef __kernel_fsid_t compat_fsid_t; 29 29 30 30 struct compat_stat { 31 - compat_dev_t st_dev; 32 - u16 __pad1; 31 + u32 st_dev; 33 32 compat_ino_t st_ino; 34 33 compat_mode_t st_mode; 35 34 compat_nlink_t st_nlink; 36 35 __compat_uid_t st_uid; 37 36 __compat_gid_t st_gid; 38 - compat_dev_t st_rdev; 39 - u16 __pad2; 37 + u32 st_rdev; 40 38 u32 st_size; 41 39 u32 st_blksize; 42 40 u32 st_blocks;
+10 -9
fs/stat.c
··· 348 348 # define choose_32_64(a,b) b 349 349 #endif 350 350 351 - #define valid_dev(x) choose_32_64(old_valid_dev(x),true) 352 - #define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x) 353 - 354 351 #ifndef INIT_STRUCT_STAT_PADDING 355 352 # define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st)) 356 353 #endif ··· 356 359 { 357 360 struct stat tmp; 358 361 359 - if (!valid_dev(stat->dev) || !valid_dev(stat->rdev)) 362 + if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) 363 + return -EOVERFLOW; 364 + if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) 360 365 return -EOVERFLOW; 361 366 #if BITS_PER_LONG == 32 362 367 if (stat->size > MAX_NON_LFS) ··· 366 367 #endif 367 368 368 369 INIT_STRUCT_STAT_PADDING(tmp); 369 - tmp.st_dev = encode_dev(stat->dev); 370 + tmp.st_dev = new_encode_dev(stat->dev); 370 371 tmp.st_ino = stat->ino; 371 372 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 372 373 return -EOVERFLOW; ··· 376 377 return -EOVERFLOW; 377 378 SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 378 379 SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 379 - tmp.st_rdev = encode_dev(stat->rdev); 380 + tmp.st_rdev = new_encode_dev(stat->rdev); 380 381 tmp.st_size = stat->size; 381 382 tmp.st_atime = stat->atime.tv_sec; 382 383 tmp.st_mtime = stat->mtime.tv_sec; ··· 664 665 { 665 666 struct compat_stat tmp; 666 667 667 - if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) 668 + if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) 669 + return -EOVERFLOW; 670 + if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) 668 671 return -EOVERFLOW; 669 672 670 673 memset(&tmp, 0, sizeof(tmp)); 671 - tmp.st_dev = old_encode_dev(stat->dev); 674 + tmp.st_dev = new_encode_dev(stat->dev); 672 675 tmp.st_ino = stat->ino; 673 676 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 674 677 return -EOVERFLOW; ··· 680 679 return -EOVERFLOW; 681 680 SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 682 681 SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 683 - tmp.st_rdev = old_encode_dev(stat->rdev); 682 + tmp.st_rdev = new_encode_dev(stat->rdev); 684 683 if ((u64) stat->size > MAX_NON_LFS) 685 684 return -EOVERFLOW; 686 685 tmp.st_size = stat->size;