lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 26 May 2014 14:27:24 +0100
From:	Djalal Harouni <tixxdz@...ndz.org>
To:	Kees Cook <keescook@...omium.org>,
	Andrew Morton <akpm@...ux-foundation.org>,
	Alexey Dobriyan <adobriyan@...il.com>,
	"Eric W. Biederman" <ebiederm@...ssion.com>,
	Al Viro <viro@...iv.linux.org.uk>,
	Linus Torvalds <torvalds@...ux-foundation.org>,
	Ingo Molnar <mingo@...nel.org>,
	Oleg Nesterov <oleg@...hat.com>,
	Peter Zijlstra <peterz@...radead.org>,
	Andy Lutomirski <luto@...capital.net>
Cc:	LKML <linux-kernel@...r.kernel.org>, linux-fsdevel@...r.kernel.org,
	Djalal Harouni <tixxdz@...ndz.org>
Subject: [PATCH 3/9] procfs: add proc_read_from_buffer() and pid_entry_read() helpers

This patch is preparation, it adds a couple of helpers to read data and
to get the cached permission checks during that ->read().

Currently INF entries share the same code, they do not implement
specific ->open(), only ->read() coupled with callback calls. Doing
permission checks during ->open() will not work and will only disturb
the INF entries that do not need permission checks. Yes not all the INF
entries need checks, the ones that need protections are listed below:
/proc/<pid>/wchan
/proc/<pid>/syscall
/proc/<pid>/{auxv,io}  (will be handled in next patches).

So to have proper permission checks convert this INF entries to REG
entries and use their open() and read() handlers to implement these
checks. To achieve this we add the following helpers:

* proc_read_from_buffer() a wrapper around simple_read_from_buffer(), it
  makes sure that count <= PROC_BLOCK_SIZE (3*1024)

* pid_entry_read(): it will get a free page and pass it to the specific
  /proc/<pid>/$entry handler (callback). The handler is of the same
  types of the previous INF handlers, it will only receive an extra
  "permitted" argument that contains the cached permission check that
  was performed during ->open().

  The handler is of type:
  typedef int (*proc_read_fn_t)(char *page,
                               struct task_struct *task, int permitted);

So the converted code for example: /proc/pid/wchan will be:

  Before:
  static int proc_pid_wchan(struct task_struct *task, char *buffer)

  After:
  static int proc_pid_wchan(char *buffer,
			    struct task_struct *task, int permitted)

The extra "permitted" can be used by the handler to allow/deny reads.

And the whole read() of /proc/pid/wchan will be:

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;
}

Signed-off-by: Djalal Harouni <tixxdz@...ndz.org>
---
 fs/proc/base.c     | 53 +++++++++++++++++++++++++++++++++++++++++++++++------
 fs/proc/internal.h |  3 +++
 2 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index e442784..efe2a11 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -139,6 +139,50 @@ struct pid_entry {
 		NULL, &proc_single_file_operations,	\
 		{ .proc_show = show } )
 
+/* 4K page size but our output routines use some slack for overruns */
+#define PROC_BLOCK_SIZE	(3*1024)
+
+static ssize_t proc_read_from_buffer(void __user *to, size_t count,
+				     loff_t *ppos, const void *from,
+				     size_t available)
+{
+	if (count > PROC_BLOCK_SIZE)
+		count = PROC_BLOCK_SIZE;
+
+	return simple_read_from_buffer(to, count, ppos, from, available);
+}
+
+static ssize_t pid_entry_read(struct file *file, unsigned long *page,
+			      proc_read_fn_t proc_read)
+{
+	unsigned long addr;
+	ssize_t length = -ESRCH;
+	struct task_struct *task;
+	struct inode *inode = file_inode(file);
+	int permitted = (unsigned long)(void *)file->private_data;
+
+	task = get_proc_task(inode);
+	if (!task)
+		goto out_no_task;
+
+	length = -ENOMEM;
+	addr = __get_free_page(GFP_TEMPORARY);
+	if (!addr)
+		goto out;
+
+	length = proc_read((char *)addr, task, permitted);
+	if (length < 0) {
+		free_page(addr);
+		goto out;
+	}
+
+	*page = addr;
+out:
+	put_task_struct(task);
+out_no_task:
+	return length;
+}
+
 /*
  * Count the number of hardlinks for the pid_entry table, excluding the .
  * and .. links.
@@ -598,8 +642,6 @@ static const struct inode_operations proc_def_inode_operations = {
 	.setattr	= proc_setattr,
 };
 
-#define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
-
 static ssize_t proc_info_read(struct file * file, char __user * buf,
 			  size_t count, loff_t *ppos)
 {
@@ -612,9 +654,6 @@ static ssize_t proc_info_read(struct file * file, char __user * buf,
 	if (!task)
 		goto out_no_task;
 
-	if (count > PROC_BLOCK_SIZE)
-		count = PROC_BLOCK_SIZE;
-
 	length = -ENOMEM;
 	if (!(page = __get_free_page(GFP_TEMPORARY)))
 		goto out;
@@ -622,7 +661,9 @@ static ssize_t proc_info_read(struct file * file, char __user * buf,
 	length = PROC_I(inode)->op.proc_read(task, (char*)page);
 
 	if (length >= 0)
-		length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
+		length = proc_read_from_buffer(buf, count, ppos,
+					       (char *)page, length);
+
 	free_page(page);
 out:
 	put_task_struct(task);
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 4f828fa..f5c452c 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -78,6 +78,9 @@ struct proc_inode {
 	struct inode vfs_inode;
 };
 
+typedef int (*proc_read_fn_t)(char *page,
+			      struct task_struct *task, int permitted);
+
 /*
  * General functions
  */
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ