Convert syscall from an INF entry to a REG one. This way we can perform and cache the permission checks during ->open(). The ptrace capability is only cached, it will be re-checked during ->read(). If the opener did not have enough privileges then fail. Signed-off-by: Djalal Harouni <tixxdz@xxxxxxxxxx> --- fs/proc/base.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index ef35544..f0ce94a 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -183,6 +183,18 @@ out_no_task: return length; } +static int pid_entry_attach(struct file *filp) +{ + int ret = pid_entry_access(filp, PTRACE_MODE_ATTACH); + + if (ret) + filp->private_data = (void *)(unsigned long)PID_ENTRY_DENY; + else + filp->private_data = (void *)(unsigned long)PID_ENTRY_ALLOW; + + return ret; +} + /* * Count the number of hardlinks for the pid_entry table, excluding the . * and .. links. @@ -574,11 +586,25 @@ static int proc_pid_limits(struct task_struct *task, char *buffer) } #ifdef CONFIG_HAVE_ARCH_TRACEHOOK -static int proc_pid_syscall(struct task_struct *task, char *buffer) +static int syscall_open(struct inode *inode, struct file *filp) +{ + /* we only cache the result */ + pid_entry_attach(filp); + + return 0; +} + +static int proc_pid_syscall(char *buffer, + struct task_struct *task, int permitted) { long nr; + int res = -EPERM; unsigned long args[6], sp, pc; - int res = lock_trace(task); + + if (!permitted) + return res; + + res = lock_trace(task); if (res) return res; @@ -595,6 +621,28 @@ static int proc_pid_syscall(struct task_struct *task, char *buffer) unlock_trace(task); return res; } + +static ssize_t syscall_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t length; + unsigned long page = 0UL; + + length = pid_entry_read(file, &page, proc_pid_syscall); + if (length >= 0) { + length = proc_read_from_buffer(buf, count, ppos, + (char *)page, length); + free_page(page); + } + + return length; +} + +static const struct file_operations proc_pid_syscall_operations = { + .open = syscall_open, + .read = syscall_read, + .llseek = generic_file_llseek, +}; #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ /************************************************************************/ @@ -2649,7 +2697,7 @@ static const struct pid_entry tgid_base_stuff[] = { #endif REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), #ifdef CONFIG_HAVE_ARCH_TRACEHOOK - INF("syscall", S_IRUSR, proc_pid_syscall), + REG("syscall", S_IRUSR, proc_pid_syscall_operations), #endif INF("cmdline", S_IRUGO, proc_pid_cmdline), ONE("stat", S_IRUGO, proc_tgid_stat), @@ -2983,7 +3031,7 @@ static const struct pid_entry tid_base_stuff[] = { #endif REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), #ifdef CONFIG_HAVE_ARCH_TRACEHOOK - INF("syscall", S_IRUSR, proc_pid_syscall), + REG("syscall", S_IRUSR, proc_pid_syscall_operations), #endif INF("cmdline", S_IRUGO, proc_pid_cmdline), ONE("stat", S_IRUGO, proc_tid_stat), -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html