[PATCH 4/9] procfs: improve /proc/<pid>/wchan protection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Convert wchan from an INF entry to a REG one. This way we can perform
and cache the permission checks during ->open().

The checks are only cached, since /proc/<pid>/wchan is world readable,
and it needs permissions only when returning an address, returning the
symbol name is not subject to permission checks, so do not change this.

With this logic userspace should continue to work without any problem,
only cases where users are trying to play tricks or something
sophisticated is trying to use privileged programs to disclose sensitive
data will notice.

Suggested-by: Alexey Dobriyan <adobriyan@xxxxxxxxx>
Signed-off-by: Djalal Harouni <tixxdz@xxxxxxxxxx>
---
 fs/proc/base.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index efe2a11..ef35544 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -273,21 +273,64 @@ static int proc_pid_auxv(struct task_struct *task, char *buffer)
  * Provides a wchan file via kallsyms in a proper one-value-per-file format.
  * Returns the resolved symbol.  If that fails, simply return the address.
  */
-static int proc_pid_wchan(struct task_struct *task, char *buffer)
+static int wchan_open(struct inode *inode, struct file *filp)
+{
+	/* we only cache the result for wchan entry */
+	if (pid_entry_access(filp, PTRACE_MODE_READ))
+		filp->private_data = (void *)(unsigned long)PID_ENTRY_DENY;
+	else
+		filp->private_data = (void *)(unsigned long)PID_ENTRY_ALLOW;
+
+	return 0;
+}
+
+static int proc_pid_wchan(char *buffer,
+			  struct task_struct *task, int permitted)
 {
 	unsigned long wchan;
 	char symname[KSYM_NAME_LEN];
 
 	wchan = get_wchan(task);
 
-	if (lookup_symbol_name(wchan, symname) < 0)
-		if (!ptrace_may_access(task, PTRACE_MODE_READ))
+	if (lookup_symbol_name(wchan, symname) < 0) {
+		if (!permitted)
+			return 0;
+
+		/* Update only if access was granted during ->open */
+		if (!mutex_lock_killable(&task->signal->cred_guard_mutex)) {
+			permitted = ptrace_may_access(task, PTRACE_MODE_READ);
+			mutex_unlock(&task->signal->cred_guard_mutex);
+		}
+
+		if (!permitted)
 			return 0;
 		else
 			return sprintf(buffer, "%lu", wchan);
-	else
+	} else
 		return sprintf(buffer, "%s", symname);
 }
+
+static ssize_t wchan_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_wchan);
+	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_wchan_operations = {
+	.open   = wchan_open,
+	.read   = wchan_read,
+	.llseek = generic_file_llseek,
+};
 #endif /* CONFIG_KALLSYMS */
 
 static int lock_trace(struct task_struct *task)
@@ -2631,7 +2674,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 	DIR("attr",       S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
 #endif
 #ifdef CONFIG_KALLSYMS
-	INF("wchan",      S_IRUGO, proc_pid_wchan),
+	REG("wchan",      S_IRUGO, proc_pid_wchan_operations),
 #endif
 #ifdef CONFIG_STACKTRACE
 	ONE("stack",      S_IRUSR, proc_pid_stack),
@@ -2967,7 +3010,7 @@ static const struct pid_entry tid_base_stuff[] = {
 	DIR("attr",      S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
 #endif
 #ifdef CONFIG_KALLSYMS
-	INF("wchan",     S_IRUGO, proc_pid_wchan),
+	REG("wchan",     S_IRUGO, proc_pid_wchan_operations),
 #endif
 #ifdef CONFIG_STACKTRACE
 	ONE("stack",      S_IRUSR, proc_pid_stack),
-- 
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




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux