diff --git a/fs/proc/proc_xcall.c b/fs/proc/proc_xcall.c index 8f73752358031277c159012065c144fb97a8db66..47f3d4f253936ffba0ad753e468dc8edd50f9050 100644 --- a/fs/proc/proc_xcall.c +++ b/fs/proc/proc_xcall.c @@ -61,12 +61,15 @@ static int xcall_open(struct inode *inode, struct file *filp) return single_open(filp, xcall_show, inode); } +#define MAX_SYSNO_DIGITS 3 +#define MAX_BUF_SIZE (1 + MAX_SYSNO_DIGITS + 1) // "!" + digits + '\0' static ssize_t xcall_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) { unsigned int sc_no = __NR_syscalls; + char buf[MAX_BUF_SIZE]; struct task_struct *p; - char buf[5]; + int is_clear = 0; int ret = 0; if (!static_key_enabled(&xcall_enable)) @@ -76,13 +79,19 @@ static ssize_t xcall_write(struct file *file, const char __user *ubuf, if (!p || !TASK_XINFO(p)) return -ESRCH; - memset(buf, '\0', 5); - if (!count || (count > 5) || copy_from_user(buf, ubuf, count)) { + memset(buf, '\0', MAX_BUF_SIZE); + if (!count || (count > MAX_BUF_SIZE)) { ret = -EFAULT; goto out; } - if (kstrtouint((buf + (int)(buf[0] == '!')), 10, &sc_no)) { + if (copy_from_user(buf, ubuf, count > MAX_BUF_SIZE - 1 ? MAX_BUF_SIZE - 1 : count)) { + ret = -EFAULT; + goto out; + } + + is_clear = (buf[0] == '!'); + if (kstrtouint((buf + is_clear), 10, &sc_no)) { ret = -EINVAL; goto out; } @@ -92,9 +101,12 @@ static ssize_t xcall_write(struct file *file, const char __user *ubuf, goto out; } - (TASK_XINFO(p))->xcall_enable[sc_no] = (int)(buf[0] != '!'); - ret = 0; - + if (!is_clear && !(TASK_XINFO(p))->xcall_enable[sc_no]) + (TASK_XINFO(p))->xcall_enable[sc_no] = 1; + else if (is_clear && (TASK_XINFO(p))->xcall_enable[sc_no]) + (TASK_XINFO(p))->xcall_enable[sc_no] = 0; + else + ret = -EINVAL; out: put_task_struct(p); diff --git a/kernel/fork.c b/kernel/fork.c index f0271e915b0ed07fb93aba7b2e91487d7ef69183..328bbf6a36d20f4c6c583d938085946b834010fc 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -975,7 +975,6 @@ void __mmdrop(struct mm_struct *mm) mm_free_pgd(mm); destroy_context(mm); mmu_notifier_subscriptions_destroy(mm); - clear_xcall_area(mm); check_mm(mm); put_user_ns(mm->user_ns); mm_pasid_drop(mm); @@ -1434,6 +1433,7 @@ static inline void __mmput(struct mm_struct *mm) ksm_exit(mm); khugepaged_exit(mm); /* must run before exit_mmap */ exit_mmap(mm); + clear_xcall_area(mm); sp_mm_clean(mm); mm_put_huge_zero_page(mm); set_mm_exe_file(mm, NULL);