From: yangerkun yangerkun@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8JE4E?from=project-issue
---------------------------
UBSAN has reported a overflow with mem_lseek. And it's fine with mem_open set file mode with FMODE_UNSIGNED_OFFSET(memory_lseek). However, another file use mem_lseek do lseek can have not FMODE_UNSIGNED_OFFSET(proc_kpagecount_operations/proc_pagemap_operations), fix it by checking overflow and FMODE_UNSIGNED_OFFSET. Reviewed-by: zhangyi (F) yi.zhang@huawei.com
================================================================== UBSAN: Undefined behaviour in ../fs/proc/base.c:941:15 signed integer overflow: 4611686018427387904 + 4611686018427387904 cannot be represented in type 'long long int' CPU: 4 PID: 4762 Comm: syz-executor.1 Not tainted 4.4.189 #3 Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 Call trace: [<ffffff90080a5f28>] dump_backtrace+0x0/0x590 arch/arm64/kernel/traps.c:91 [<ffffff90080a64f0>] show_stack+0x38/0x60 arch/arm64/kernel/traps.c:234 [<ffffff9008986a34>] __dump_stack lib/dump_stack.c:15 [inline] [<ffffff9008986a34>] dump_stack+0x128/0x184 lib/dump_stack.c:51 [<ffffff9008a2d120>] ubsan_epilogue+0x34/0x9c lib/ubsan.c:166 [<ffffff9008a2d8b8>] handle_overflow+0x228/0x280 lib/ubsan.c:197 [<ffffff9008a2da2c>] __ubsan_handle_add_overflow+0x4c/0x68 lib/ubsan.c:204 [<ffffff900862b9f4>] mem_lseek+0x12c/0x130 fs/proc/base.c:941 [<ffffff90084ef78c>] vfs_llseek fs/read_write.c:260 [inline] [<ffffff90084ef78c>] SYSC_lseek fs/read_write.c:285 [inline] [<ffffff90084ef78c>] SyS_lseek+0x164/0x1f0 fs/read_write.c:276 [<ffffff9008093c80>] el0_svc_naked+0x30/0x34 ==================================================================
Signed-off-by: yangerkun yangerkun@huawei.com Signed-off-by: Zizhi Wo wozizhi@huawei.com --- fs/proc/base.c | 32 ++++++++++++++++++++++++-------- fs/read_write.c | 5 ----- include/linux/fs.h | 4 ++++ 3 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c index ffd54617c354..00642e7fe99f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -903,18 +903,34 @@ static ssize_t mem_write(struct file *file, const char __user *buf,
loff_t mem_lseek(struct file *file, loff_t offset, int orig) { + loff_t ret = 0; + + spin_lock(&file->f_lock); switch (orig) { - case 0: - file->f_pos = offset; - break; - case 1: - file->f_pos += offset; + case SEEK_CUR: + offset += file->f_pos; + __attribute__((__fallthrough__)); + case SEEK_SET: + /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ + if ((unsigned long long)offset >= -MAX_ERRNO) + ret = -EOVERFLOW; break; default: - return -EINVAL; + ret = -EINVAL; + } + + if (!ret) { + if (offset < 0 && !(unsigned_offsets(file))) { + ret = -EINVAL; + } else { + file->f_pos = offset; + ret = file->f_pos; + force_successful_syscall_return(); + } } - force_successful_syscall_return(); - return file->f_pos; + + spin_unlock(&file->f_lock); + return ret; }
static int mem_release(struct inode *inode, struct file *file) diff --git a/fs/read_write.c b/fs/read_write.c index 4771701c896b..2f456d5a1df5 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -34,11 +34,6 @@ const struct file_operations generic_ro_fops = {
EXPORT_SYMBOL(generic_ro_fops);
-static inline bool unsigned_offsets(struct file *file) -{ - return file->f_mode & FMODE_UNSIGNED_OFFSET; -} - /** * vfs_setpos - update the file offset for lseek * @file: file structure in question diff --git a/include/linux/fs.h b/include/linux/fs.h index 4f6b15e960ec..59d4edee1b96 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2932,6 +2932,10 @@ extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); extern loff_t noop_llseek(struct file *file, loff_t offset, int whence); +static inline bool unsigned_offsets(struct file *file) +{ + return file->f_mode & FMODE_UNSIGNED_OFFSET; +} #define no_llseek NULL extern loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize); extern loff_t generic_file_llseek(struct file *file, loff_t offset, int whence);
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/3089 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/F...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/3089 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/F...