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-next>] [day] [month] [year] [list]
Date:	Tue, 30 Oct 2012 21:02:33 +0000
From:	Arvid Brodin <Arvid.Brodin@...n.com>
To:	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
CC:	Andrew Morton <akpm@...ux-foundation.org>,
	Al Viro <viro@...iv.linux.org.uk>,
	Cyrill Gorcunov <gorcunov@...nvz.org>,
	"David Rientjes" <rientjes@...gle.com>,
	"Eric W. Biederman" <ebiederm@...ssion.com>
Subject: fs/proc/base.c: text md5sums; tgid vs tid; and INF vs ONE?

Hi,

Below is a patch that adds a file /proc/PID/text_md5sum which when read returns the md5
checksum of a process' text segment. (This would be used e.g. to make sure a process'
code hasn't been tampered with.)

However, I have a few questions:

* What's the difference between the tgid_base_stuff and tid_base_stuff arrays? (One for
processes and one for the process' threads? I haven't been able to find any info about
this so I'm guessing.)

* When should I use the INF ("read") vs the ONE ("show") macro?

* Any other comments about the code?

Thanks!

---

diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 15af622..317ad92 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -67,3 +67,13 @@ config PROC_PAGE_MONITOR
 	  /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
 	  /proc/kpagecount, and /proc/kpageflags. Disabling these
           interfaces will reduce the size of the kernel by approximately 4kb.
+
+config PROC_TEXT_MD5SUM
+	bool "/proc/<pid>/text_md5sum support"
+	depends on PROC_FS
+	select CRYPTO
+	select CRYPTO_MD5
+	help
+	  Read /proc/<pid>/text_md5sum to get the kernel to perform an MD5
+	  checksum over the process' text segment and print the result. Can be
+	  used to make sure a process' code has not been tampered with.
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 91da78c..14a825f 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -85,6 +85,10 @@
 #include <linux/fs_struct.h>
 #include <linux/slab.h>
 #include <linux/flex_array.h>
+#ifdef CONFIG_PROC_TEXT_MD5SUM
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#endif
 #ifdef CONFIG_HARDWALL
 #include <asm/hardwall.h>
 #endif
@@ -2526,6 +2530,107 @@ static int proc_pid_personality(struct seq_file *m, struct
pid_namespace *ns,
 	return err;
 }

+#ifdef CONFIG_PROC_TEXT_MD5SUM
+#define MD5_DIGEST_SIZE 16
+static int proc_get_text_md5sum(struct seq_file *m, struct pid_namespace *ns,
+				struct pid *pid, struct task_struct *task)
+{
+	int retval;
+	int text_size;
+	int nr_pages, nr_pages_mapped;
+	int i;
+	struct page **pages;
+	struct scatterlist *sgl, *sg;
+	u8 result[MD5_DIGEST_SIZE + 2];
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
+
+	retval = 0;
+
+	if (!task->mm)
+		return -EINVAL;
+
+	text_size = task->mm->end_code - task->mm->start_code;
+	nr_pages = (text_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+
+	/**** User page code ****/
+
+	pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
+	if (!pages) {
+		retval = -ENOMEM;
+		goto err_pages;
+	}
+
+	down_read(&task->mm->mmap_sem);
+	nr_pages_mapped = get_user_pages(current, task->mm,
+			task->mm->start_code, nr_pages, 0, 0, pages, NULL);
+	up_read(&task->mm->mmap_sem);
+	if (nr_pages_mapped < 0) {
+		retval = nr_pages_mapped;
+		goto err_mapped;
+	}
+	if (nr_pages_mapped < nr_pages) {
+		retval = -EBUSY; /* Weird error code for this,
+				    but couldn't find any better */
+		goto err_not_all_pages;
+	}
+
+
+	/**** Scatterlist code ****/
+
+	sgl = kmalloc(nr_pages_mapped * sizeof(*sgl), GFP_KERNEL);
+	if (!sgl) {
+		retval = -ENOMEM;
+		goto err_sg;
+	}
+
+	sg_init_table(sgl, nr_pages_mapped);
+	for_each_sg(sgl, sg, nr_pages_mapped, i)
+		sg_set_page(sg, pages[i], (i < nr_pages_mapped) ? PAGE_SIZE :
+						text_size & ~PAGE_MASK, 0);
+
+
+	/**** Crypto code ****/
+
+	tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		retval = -ENOMEM;
+		goto err_crypto;
+	}
+
+	desc.tfm = tfm;
+	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	memset(result, 0, MD5_DIGEST_SIZE + 2);
+	retval = crypto_hash_digest(&desc, sgl, text_size, result);
+	if (retval)
+		goto err_digest;
+
+	for (i = 0; i < MD5_DIGEST_SIZE; i++)
+		seq_printf(m, "%02x", result[i]);
+	seq_printf(m, "\n");
+
+
+err_digest:
+	crypto_free_hash(tfm);
+
+err_crypto:
+	kfree(sgl);
+
+err_sg:
+err_not_all_pages:
+	for (i = 0; i < nr_pages_mapped; i++)
+		put_page(pages[i]);
+
+err_mapped:
+	kfree(pages);
+
+err_pages:
+	return retval;
+}
+#endif /* CONFIG_PROC_TEXT_MD5SUM */
+
 /*
  * Thread groups
  */
@@ -2621,6 +2726,9 @@ static const struct pid_entry tgid_base_stuff[] = {
 	REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
 	REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
 #endif
+#ifdef CONFIG_PROC_TEXT_MD5SUM
+	ONE("text_md5sum", S_IRUGO, proc_get_text_md5sum),
+#endif
 };

 static int proc_tgid_base_readdir(struct file * filp,


-- 
Arvid Brodin | Consultant (Linux)
XDIN AB | Knarrarnäsgatan 7 | SE-164 40 Kista | Sweden | xdin.com

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ