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.

Merge patch series "fix architecture-specific compat_ftruncate64 implementations"

Christoph Hellwig <hch@lst.de> says:

This series fixes a really old bug found by code inspection, where the
architecture-specific 32-bit compat ftruncate64 implementations enforce
the non-LFS file size limit unless opened with O_LARGEFILE.

* patches from https://patch.msgid.link/20260323070205.2939118-1-hch@lst.de:
fs: remove do_sys_truncate
fs: pass on FTRUNCATE_* flags to do_truncate
fs: fix archiecture-specific compat_ftruncate64

Link: https://patch.msgid.link/20260323070205.2939118-1-hch@lst.de
Signed-off-by: Christian Brauner <brauner@kernel.org>

+32 -44
+1 -1
arch/arm64/kernel/sys32.c
··· 89 89 COMPAT_SYSCALL_DEFINE4(aarch32_ftruncate64, unsigned int, fd, u32, __pad, 90 90 arg_u32p(length)) 91 91 { 92 - return ksys_ftruncate(fd, arg_u64(length)); 92 + return ksys_ftruncate(fd, arg_u64(length), FTRUNCATE_LFS); 93 93 } 94 94 95 95 COMPAT_SYSCALL_DEFINE5(aarch32_readahead, int, fd, u32, __pad,
+1 -1
arch/mips/kernel/linux32.c
··· 60 60 SYSCALL_DEFINE4(32_ftruncate64, unsigned long, fd, unsigned long, __dummy, 61 61 unsigned long, a2, unsigned long, a3) 62 62 { 63 - return ksys_ftruncate(fd, merge_64(a2, a3)); 63 + return ksys_ftruncate(fd, merge_64(a2, a3), FTRUNCATE_LFS); 64 64 } 65 65 66 66 SYSCALL_DEFINE5(32_llseek, unsigned int, fd, unsigned int, offset_high,
+2 -2
arch/parisc/kernel/sys_parisc.c
··· 216 216 asmlinkage long parisc_ftruncate64(unsigned int fd, 217 217 unsigned int high, unsigned int low) 218 218 { 219 - return ksys_ftruncate(fd, (long)high << 32 | low); 219 + return ksys_ftruncate(fd, (long)high << 32 | low, FTRUNCATE_LFS); 220 220 } 221 221 222 222 /* stubs for the benefit of the syscall_table since truncate64 and truncate ··· 227 227 } 228 228 asmlinkage long sys_ftruncate64(unsigned int fd, unsigned long length) 229 229 { 230 - return ksys_ftruncate(fd, length); 230 + return ksys_ftruncate(fd, length, FTRUNCATE_LFS); 231 231 } 232 232 asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) 233 233 {
+1 -1
arch/powerpc/kernel/sys_ppc32.c
··· 101 101 unsigned int, fd, u32, reg4, 102 102 unsigned long, len1, unsigned long, len2) 103 103 { 104 - return ksys_ftruncate(fd, merge_64(len1, len2)); 104 + return ksys_ftruncate(fd, merge_64(len1, len2), FTRUNCATE_LFS); 105 105 } 106 106 107 107 PPC32_SYSCALL_DEFINE6(ppc32_fadvise64,
+1 -1
arch/sparc/kernel/sys_sparc32.c
··· 58 58 59 59 COMPAT_SYSCALL_DEFINE3(ftruncate64, unsigned int, fd, u32, high, u32, low) 60 60 { 61 - return ksys_ftruncate(fd, ((u64)high << 32) | low); 61 + return ksys_ftruncate(fd, ((u64)high << 32) | low, FTRUNCATE_LFS); 62 62 } 63 63 64 64 static int cp_compat_stat64(struct kstat *stat,
+2 -1
arch/x86/kernel/sys_ia32.c
··· 61 61 SYSCALL_DEFINE3(ia32_ftruncate64, unsigned int, fd, 62 62 unsigned long, offset_low, unsigned long, offset_high) 63 63 { 64 - return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low); 64 + return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low, 65 + FTRUNCATE_LFS); 65 66 } 66 67 67 68 /* warning: next two assume little endian */
+1 -2
fs/internal.h
··· 198 198 extern int build_open_flags(const struct open_how *how, struct open_flags *op); 199 199 struct file *file_close_fd_locked(struct files_struct *files, unsigned fd); 200 200 201 - int do_ftruncate(struct file *file, loff_t length, int small); 202 - int do_sys_ftruncate(unsigned int fd, loff_t length, int small); 201 + int do_ftruncate(struct file *file, loff_t length, unsigned int flags); 203 202 int chmod_common(const struct path *path, umode_t mode); 204 203 int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, 205 204 int flag);
+19 -21
fs/open.c
··· 126 126 } 127 127 EXPORT_SYMBOL_GPL(vfs_truncate); 128 128 129 - int do_sys_truncate(const char __user *pathname, loff_t length) 129 + int ksys_truncate(const char __user *pathname, loff_t length) 130 130 { 131 131 unsigned int lookup_flags = LOOKUP_FOLLOW; 132 132 struct path path; ··· 151 151 152 152 SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) 153 153 { 154 - return do_sys_truncate(path, length); 154 + return ksys_truncate(path, length); 155 155 } 156 156 157 157 #ifdef CONFIG_COMPAT 158 158 COMPAT_SYSCALL_DEFINE2(truncate, const char __user *, path, compat_off_t, length) 159 159 { 160 - return do_sys_truncate(path, length); 160 + return ksys_truncate(path, length); 161 161 } 162 162 #endif 163 163 164 - int do_ftruncate(struct file *file, loff_t length, int small) 164 + int do_ftruncate(struct file *file, loff_t length, unsigned int flags) 165 165 { 166 - struct inode *inode; 167 - struct dentry *dentry; 166 + struct dentry *dentry = file->f_path.dentry; 167 + struct inode *inode = dentry->d_inode; 168 168 int error; 169 169 170 - /* explicitly opened as large or we are on 64-bit box */ 171 - if (file->f_flags & O_LARGEFILE) 172 - small = 0; 173 - 174 - dentry = file->f_path.dentry; 175 - inode = dentry->d_inode; 176 170 if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) 177 171 return -EINVAL; 178 172 179 - /* Cannot ftruncate over 2^31 bytes without large file support */ 180 - if (small && length > MAX_NON_LFS) 173 + /* 174 + * Cannot ftruncate over 2^31 bytes without large file support, either 175 + * through opening with O_LARGEFILE or by using ftruncate64(). 176 + */ 177 + if (length > MAX_NON_LFS && 178 + !(file->f_flags & O_LARGEFILE) && !(flags & FTRUNCATE_LFS)) 181 179 return -EINVAL; 182 180 183 181 /* Check IS_APPEND on real upper inode */ ··· 195 197 ATTR_MTIME | ATTR_CTIME, file); 196 198 } 197 199 198 - int do_sys_ftruncate(unsigned int fd, loff_t length, int small) 200 + int ksys_ftruncate(unsigned int fd, loff_t length, unsigned int flags) 199 201 { 200 202 if (length < 0) 201 203 return -EINVAL; ··· 203 205 if (fd_empty(f)) 204 206 return -EBADF; 205 207 206 - return do_ftruncate(fd_file(f), length, small); 208 + return do_ftruncate(fd_file(f), length, flags); 207 209 } 208 210 209 211 SYSCALL_DEFINE2(ftruncate, unsigned int, fd, off_t, length) 210 212 { 211 - return do_sys_ftruncate(fd, length, 1); 213 + return ksys_ftruncate(fd, length, 0); 212 214 } 213 215 214 216 #ifdef CONFIG_COMPAT 215 217 COMPAT_SYSCALL_DEFINE2(ftruncate, unsigned int, fd, compat_off_t, length) 216 218 { 217 - return do_sys_ftruncate(fd, length, 1); 219 + return ksys_ftruncate(fd, length, 0); 218 220 } 219 221 #endif 220 222 ··· 222 224 #if BITS_PER_LONG == 32 223 225 SYSCALL_DEFINE2(truncate64, const char __user *, path, loff_t, length) 224 226 { 225 - return do_sys_truncate(path, length); 227 + return ksys_truncate(path, length); 226 228 } 227 229 228 230 SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length) 229 231 { 230 - return do_sys_ftruncate(fd, length, 0); 232 + return ksys_ftruncate(fd, length, FTRUNCATE_LFS); 231 233 } 232 234 #endif /* BITS_PER_LONG == 32 */ 233 235 ··· 243 245 COMPAT_SYSCALL_DEFINE3(ftruncate64, unsigned int, fd, 244 246 compat_arg_u64_dual(length)) 245 247 { 246 - return ksys_ftruncate(fd, compat_arg_u64_glue(length)); 248 + return ksys_ftruncate(fd, compat_arg_u64_glue(length), FTRUNCATE_LFS); 247 249 } 248 250 #endif 249 251
+3 -13
include/linux/syscalls.h
··· 1283 1283 AT_SYMLINK_NOFOLLOW); 1284 1284 } 1285 1285 1286 - int do_sys_ftruncate(unsigned int fd, loff_t length, int small); 1287 - 1288 - static inline long ksys_ftruncate(unsigned int fd, loff_t length) 1289 - { 1290 - return do_sys_ftruncate(fd, length, 1); 1291 - } 1292 - 1293 - int do_sys_truncate(const char __user *pathname, loff_t length); 1294 - 1295 - static inline long ksys_truncate(const char __user *pathname, loff_t length) 1296 - { 1297 - return do_sys_truncate(pathname, length); 1298 - } 1286 + #define FTRUNCATE_LFS (1u << 0) /* allow truncating > 32-bit */ 1287 + int ksys_ftruncate(unsigned int fd, loff_t length, unsigned int flags); 1288 + int ksys_truncate(const char __user *pathname, loff_t length); 1299 1289 1300 1290 static inline unsigned int ksys_personality(unsigned int personality) 1301 1291 {
+1 -1
io_uring/truncate.c
··· 41 41 42 42 WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); 43 43 44 - ret = do_ftruncate(req->file, ft->len, 1); 44 + ret = do_ftruncate(req->file, ft->len, 0); 45 45 46 46 io_req_set_res(req, ret, 0); 47 47 return IOU_COMPLETE;