linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Oleg Drokin <green@linuxhacker.ru>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-kernel@vger.kernel.org, devel@driverdev.osuosl.org
Cc: Oleg Drokin <green@linuxhacker.ru>, Oleg Drokin <oleg.drokin@intel.com>
Subject: [PATCH 46/47] staging/lustre: Fix unsafe userspace access in many proc files
Date: Sun, 27 Apr 2014 13:07:10 -0400	[thread overview]
Message-ID: <1398618431-29757-47-git-send-email-green@linuxhacker.ru> (raw)
In-Reply-To: <1398618431-29757-1-git-send-email-green@linuxhacker.ru>

Apparently we are pretty bad about verifying our buffers passed
from userspace.

Signed-off-by: Oleg Drokin <oleg.drokin@intel.com>
Reviewed-on: http://review.whamcloud.com/9059
Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-4563
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Reviewed-by: James Simmons <uja.ornl@gmail.com>
---
 drivers/staging/lustre/lustre/fid/lproc_fid.c      | 41 +++++++---
 .../lustre/lustre/include/lustre/lustre_idl.h      |  2 +-
 drivers/staging/lustre/lustre/llite/lproc_llite.c  | 91 +++++++++++++++++-----
 .../lustre/lustre/obdclass/linux/linux-module.c    |  9 ++-
 drivers/staging/lustre/lustre/osc/lproc_osc.c      | 16 +++-
 5 files changed, 124 insertions(+), 35 deletions(-)

diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c
index ddd813c..6f5674d 100644
--- a/drivers/staging/lustre/lustre/fid/lproc_fid.c
+++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c
@@ -54,32 +54,49 @@
 #include <lustre_fid.h>
 #include "fid_internal.h"
 
+/* Format: [0x64BIT_INT - 0x64BIT_INT] + 32 bytes just in case */
+#define MAX_FID_RANGE_STRLEN (32 + 2 * 2 * sizeof(__u64))
 /*
  * Note: this function is only used for testing, it is no safe for production
  * use.
  */
-static int
-lprocfs_fid_write_common(const char *buffer, unsigned long count,
-			 struct lu_seq_range *range)
+static int lprocfs_fid_write_common(const char __user *buffer, size_t count,
+				    struct lu_seq_range *range)
 {
 	struct lu_seq_range tmp;
 	int rc;
+	char kernbuf[MAX_FID_RANGE_STRLEN];
 
 	LASSERT(range != NULL);
 
-	rc = sscanf(buffer, "[%llx - %llx]\n",
+	if (count >= sizeof(kernbuf))
+		return -EINVAL;
+
+	if (copy_from_user(kernbuf, buffer, count))
+		return -EFAULT;
+
+	kernbuf[count] = 0;
+
+	if (count == 5 && strcmp(kernbuf, "clear") == 0) {
+		memset(range, 0, sizeof(*range));
+		return count;
+	}
+
+	/* of the form "[0x0000000240000400 - 0x000000028000400]" */
+	rc = sscanf(kernbuf, "[%llx - %llx]\n",
 		    (long long unsigned *)&tmp.lsr_start,
 		    (long long unsigned *)&tmp.lsr_end);
-	if (rc != 2 || !range_is_sane(&tmp) || range_is_zero(&tmp))
+	if (!range_is_sane(&tmp) || range_is_zero(&tmp) ||
+	    tmp.lsr_start < range->lsr_start || tmp.lsr_end > range->lsr_end)
 		return -EINVAL;
 	*range = tmp;
-	return 0;
+	return count;
 }
 
 /* Client side procfs stuff */
-static ssize_t
-lprocfs_fid_space_seq_write(struct file *file, const char *buffer,
-			    size_t count, loff_t *off)
+static ssize_t lprocfs_fid_space_seq_write(struct file *file,
+					   const char __user *buffer,
+					   size_t count, loff_t *off)
 {
 	struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private;
 	int rc;
@@ -114,9 +131,9 @@ lprocfs_fid_space_seq_show(struct seq_file *m, void *unused)
 	return rc;
 }
 
-static ssize_t
-lprocfs_fid_width_seq_write(struct file *file, const char *buffer,
-			    size_t count, loff_t *off)
+static ssize_t lprocfs_fid_width_seq_write(struct file *file,
+					   const char __user *buffer,
+					   size_t count, loff_t *off)
 {
 	struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private;
 	__u64  max;
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
index abd29bf..83014c9 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
@@ -265,7 +265,7 @@ static inline __u64 range_space(const struct lu_seq_range *range)
 
 static inline void range_init(struct lu_seq_range *range)
 {
-	range->lsr_start = range->lsr_end = range->lsr_index = 0;
+	memset(range, 0, sizeof(*range));
 }
 
 /**
diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c
index 6d70c65..77ee9e5 100644
--- a/drivers/staging/lustre/lustre/llite/lproc_llite.c
+++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c
@@ -367,8 +367,9 @@ static int ll_max_cached_mb_seq_show(struct seq_file *m, void *v)
 			cache->ccc_lru_shrinkers);
 }
 
-static ssize_t ll_max_cached_mb_seq_write(struct file *file, const char *buffer,
-				      size_t count, loff_t *off)
+static ssize_t ll_max_cached_mb_seq_write(struct file *file,
+					  const char __user *buffer,
+					  size_t count, loff_t *off)
 {
 	struct super_block *sb = ((struct seq_file *)file->private_data)->private;
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
@@ -376,9 +377,18 @@ static ssize_t ll_max_cached_mb_seq_write(struct file *file, const char *buffer,
 	int mult, rc, pages_number;
 	int diff = 0;
 	int nrpages = 0;
+	char kernbuf[128];
+
+	if (count >= sizeof(kernbuf))
+		return -EINVAL;
+
+	if (copy_from_user(kernbuf, buffer, count))
+		return -EFAULT;
+	kernbuf[count] = 0;
 
 	mult = 1 << (20 - PAGE_CACHE_SHIFT);
-	buffer = lprocfs_find_named_value(buffer, "max_cached_mb:", &count);
+	buffer += lprocfs_find_named_value(kernbuf, "max_cached_mb:", &count) -
+		  kernbuf;
 	rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
 	if (rc)
 		return rc;
@@ -1163,7 +1173,8 @@ static int ll_rw_extents_stats_pp_seq_show(struct seq_file *seq, void *v)
 }
 
 static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file,
-						const char *buf, size_t len,
+						const char __user *buf,
+						size_t len,
 						loff_t *off)
 {
 	struct seq_file *seq = file->private_data;
@@ -1172,10 +1183,24 @@ static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file,
 	int i;
 	int value = 1, rc = 0;
 
+	if (len == 0)
+		return -EINVAL;
+
 	rc = lprocfs_write_helper(buf, len, &value);
-	if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
-		       strcmp(buf, "Disabled") == 0))
-		value = 0;
+	if (rc < 0 && len < 16) {
+		char kernbuf[16];
+
+		if (copy_from_user(kernbuf, buf, len))
+			return -EFAULT;
+		kernbuf[len] = 0;
+
+		if (kernbuf[len - 1] == '\n')
+			kernbuf[len - 1] = 0;
+
+		if (strcmp(kernbuf, "disabled") == 0 ||
+		    strcmp(kernbuf, "Disabled") == 0)
+			value = 0;
+	}
 
 	if (value == 0)
 		sbi->ll_rw_stats_on = 0;
@@ -1222,8 +1247,9 @@ static int ll_rw_extents_stats_seq_show(struct seq_file *seq, void *v)
 	return 0;
 }
 
-static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf,
-					size_t len, loff_t *off)
+static ssize_t ll_rw_extents_stats_seq_write(struct file *file,
+					     const char __user *buf,
+					     size_t len, loff_t *off)
 {
 	struct seq_file *seq = file->private_data;
 	struct ll_sb_info *sbi = seq->private;
@@ -1231,15 +1257,30 @@ static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf,
 	int i;
 	int value = 1, rc = 0;
 
+	if (len == 0)
+		return -EINVAL;
+
 	rc = lprocfs_write_helper(buf, len, &value);
-	if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
-		       strcmp(buf, "Disabled") == 0))
-		value = 0;
+	if (rc < 0 && len < 16) {
+		char kernbuf[16];
+
+		if (copy_from_user(kernbuf, buf, len))
+			return -EFAULT;
+		kernbuf[len] = 0;
+
+		if (kernbuf[len - 1] == '\n')
+			kernbuf[len - 1] = 0;
+
+		if (strcmp(kernbuf, "disabled") == 0 ||
+		    strcmp(kernbuf, "Disabled") == 0)
+			value = 0;
+	}
 
 	if (value == 0)
 		sbi->ll_rw_stats_on = 0;
 	else
 		sbi->ll_rw_stats_on = 1;
+
 	spin_lock(&sbi->ll_pp_extent_lock);
 	for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) {
 		io_extents->pp_extents[i].pid = 0;
@@ -1250,7 +1291,6 @@ static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf,
 
 	return len;
 }
-
 LPROC_SEQ_FOPS(ll_rw_extents_stats);
 
 void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
@@ -1410,8 +1450,9 @@ static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
 	return 0;
 }
 
-static ssize_t ll_rw_offset_stats_seq_write(struct file *file, const char *buf,
-				       size_t len, loff_t *off)
+static ssize_t ll_rw_offset_stats_seq_write(struct file *file,
+					    const char __user *buf,
+					    size_t len, loff_t *off)
 {
 	struct seq_file *seq = file->private_data;
 	struct ll_sb_info *sbi = seq->private;
@@ -1419,11 +1460,25 @@ static ssize_t ll_rw_offset_stats_seq_write(struct file *file, const char *buf,
 	struct ll_rw_process_info *offset_info = sbi->ll_rw_offset_info;
 	int value = 1, rc = 0;
 
+	if (len == 0)
+		return -EINVAL;
+
 	rc = lprocfs_write_helper(buf, len, &value);
 
-	if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
-			   strcmp(buf, "Disabled") == 0))
-		value = 0;
+	if (rc < 0 && len < 16) {
+		char kernbuf[16];
+
+		if (copy_from_user(kernbuf, buf, len))
+			return -EFAULT;
+		kernbuf[len] = 0;
+
+		if (kernbuf[len - 1] == '\n')
+			kernbuf[len - 1] = 0;
+
+		if (strcmp(kernbuf, "disabled") == 0 ||
+		    strcmp(kernbuf, "Disabled") == 0)
+			value = 0;
+	}
 
 	if (value == 0)
 		sbi->ll_rw_stats_on = 0;
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
index dec1037..0334882 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
@@ -279,8 +279,15 @@ static ssize_t obd_proc_jobid_var_seq_write(struct file *file, const char *buffe
 		return -EINVAL;
 
 	memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1);
+
+	/* This might leave the var invalid on error, which is probably fine.*/
+	if (copy_from_user(obd_jobid_var, buffer, count))
+		return -EFAULT;
+
 	/* Trim the trailing '\n' if any */
-	memcpy(obd_jobid_var, buffer, count - (buffer[count - 1] == '\n'));
+	if (obd_jobid_var[count - 1] == '\n')
+		obd_jobid_var[count - 1] = 0;
+
 	return count;
 }
 LPROC_SEQ_FOPS(obd_proc_jobid_var);
diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c
index 0b59fc1..358e32c 100644
--- a/drivers/staging/lustre/lustre/osc/lproc_osc.c
+++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c
@@ -174,15 +174,25 @@ static int osc_cached_mb_seq_show(struct seq_file *m, void *v)
 }
 
 /* shrink the number of caching pages to a specific number */
-static ssize_t osc_cached_mb_seq_write(struct file *file, const char *buffer,
-				   size_t count, loff_t *off)
+static ssize_t osc_cached_mb_seq_write(struct file *file,
+				       const char __user *buffer,
+				       size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct client_obd *cli = &dev->u.cli;
 	int pages_number, mult, rc;
+	char kernbuf[128];
+
+	if (count >= sizeof(kernbuf))
+		return -EINVAL;
+
+	if (copy_from_user(kernbuf, buffer, count))
+		return -EFAULT;
+	kernbuf[count] = 0;
 
 	mult = 1 << (20 - PAGE_CACHE_SHIFT);
-	buffer = lprocfs_find_named_value(buffer, "used_mb:", &count);
+	buffer += lprocfs_find_named_value(kernbuf, "used_mb:", &count) -
+		  kernbuf;
 	rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
 	if (rc)
 		return rc;
-- 
1.8.5.3


  parent reply	other threads:[~2014-04-27 17:09 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-27 17:06 [PATCH 00/47] Lustre fixes and cleanups Oleg Drokin
2014-04-27 17:06 ` [PATCH 01/47] staging/lustre/ptlrpc: Fix assertion failure of null_alloc_rs() Oleg Drokin
2014-04-27 17:06 ` [PATCH 02/47] staging/lustre/ptlrpc: Remove log message about export timer update Oleg Drokin
2014-04-27 17:06 ` [PATCH 03/47] staging/lustre/gss: gssnull security flavor Oleg Drokin
2014-04-27 17:06 ` [PATCH 04/47] staging/lustre/gss: Shared key mechanism & flavors Oleg Drokin
2014-04-27 17:20   ` Greg Kroah-Hartman
2014-04-27 17:06 ` [PATCH 05/47] staging/lustre/osc: don't activate deactivated obd_import Oleg Drokin
2014-04-27 17:06 ` [PATCH 06/47] staging/lustre/lnet: Dropped messages are not accounted correctly Oleg Drokin
2014-04-27 17:06 ` [PATCH 07/47] staging/lustre/ldlm: Hold lock when clearing flag Oleg Drokin
2014-04-27 17:06 ` [PATCH 08/47] staging/lustre/clio: clear nowait flag agl lock re-enqueue Oleg Drokin
2014-04-27 17:06 ` [PATCH 09/47] staging/lustre/ptlrpc: don't try to recover no_recov connection Oleg Drokin
2014-04-27 17:06 ` [PATCH 10/47] staging/lustre/gss: fix few issues found by Klocwork Insight tool Oleg Drokin
2014-04-27 17:06 ` [PATCH 11/47] staging/lustre/ptlrpc: add rpc_cache Oleg Drokin
2014-04-29  9:46   ` Dan Carpenter
2014-04-30  3:22     ` Oleg Drokin
2014-04-27 17:06 ` [PATCH 12/47] staging/lustre: restore __GFP_WAIT flag to memalloc calls Oleg Drokin
2014-04-27 17:06 ` [PATCH 13/47] staging/lustre/gss: fix uninitialized variable Oleg Drokin
2014-04-27 17:06 ` [PATCH 14/47] staging/lustre: quiet console permission error messages Oleg Drokin
2014-04-27 17:06 ` [PATCH 15/47] staging/lustre/lov: remove unused lov llog code Oleg Drokin
2014-04-27 17:06 ` [PATCH 16/47] staging/lustre/obdclass: remove uses of lov_stripe_md Oleg Drokin
2014-04-27 17:06 ` [PATCH 17/47] staging/lustre/hsm: count NULL terminator in hai_zero/hal_size Oleg Drokin
2014-04-27 17:06 ` [PATCH 18/47] staging/lustre/hsm: HSM requests not delivered Oleg Drokin
2014-04-29  9:08   ` Dan Carpenter
2014-04-30  3:31     ` Oleg Drokin
2014-04-27 17:06 ` [PATCH 19/47] staging/lustre: fix permission problem of setfacl Oleg Drokin
2014-04-27 17:06 ` [PATCH 20/47] staging/lustre/llite: issue OST_SYNC for fsync() Oleg Drokin
2014-04-27 17:06 ` [PATCH 21/47] staging/lustre/llite: deadlock taking lli_trunc_sem during file write Oleg Drokin
2014-04-27 17:06 ` [PATCH 22/47] staging/lustre/lov: to not hold sub locks at initialization Oleg Drokin
2014-04-27 17:06 ` [PATCH 23/47] staging/lustre: Limit reply buffer size Oleg Drokin
2014-04-27 17:06 ` [PATCH 24/47] staging/lustre/llite: Avoid statahead thread start/stop deadlocks Oleg Drokin
2014-04-27 17:06 ` [PATCH 25/47] stagaing/lustre: Improve statahead debug messages Oleg Drokin
2014-04-27 17:06 ` [PATCH 26/47] staging/lustre/llite: access layout version under a lock Oleg Drokin
2014-04-27 17:06 ` [PATCH 27/47] staging/lustre: shrink lu_object_header by 8 bytes on x86_64 Oleg Drokin
2014-04-27 17:06 ` [PATCH 28/47] staging/lustre/ldlm: fix NULL pointer dereference Oleg Drokin
2014-04-27 17:06 ` [PATCH 29/47] staging/lustre/lnet: lnet: fix issues found by Klocwork Insight tool Oleg Drokin
2014-04-27 17:25   ` Greg Kroah-Hartman
2014-04-27 17:06 ` [PATCH 30/47] staging/lustre/mdc: fix issue " Oleg Drokin
2014-04-29 10:20   ` Dan Carpenter
2014-04-27 17:06 ` [PATCH 31/47] staging/lustre/libcfs: fix issues " Oleg Drokin
2014-04-27 17:06 ` [PATCH 32/47] staging/lustre/lnet: NI shutdown may loop forever Oleg Drokin
2014-04-27 17:06 ` [PATCH 33/47] staging/lustre: remove lustre/include/ioctl.h Oleg Drokin
2014-04-27 17:06 ` [PATCH 34/47] staging/lustre/libcfs: add CPU table functions for uniprocessor Oleg Drokin
2014-04-29 10:35   ` Dan Carpenter
2014-04-27 17:06 ` [PATCH 35/47] staging/lustre: replace semaphores with mutexes Oleg Drokin
2014-04-27 17:07 ` [PATCH 36/47] staging/lustre/clio: replace semaphore with mutex Oleg Drokin
2014-04-27 17:07 ` [PATCH 37/47] staging/lustre/llite: Do not rate limit dirty page discard warning Oleg Drokin
2014-04-27 17:07 ` [PATCH 38/47] staging/lustre/lloop: avoid panic during blockdev_info Oleg Drokin
2014-04-27 17:07 ` [PATCH 39/47] staging/lustre/clio: Solve a race in cl_lock_put Oleg Drokin
2014-04-27 17:07 ` [PATCH 40/47] staging/lustre/mdc: use cl_max_mds_md to pack getattr RPC Oleg Drokin
2014-04-27 17:07 ` [PATCH 41/47] staging/lustre/llite: remove dead code Oleg Drokin
2014-04-29 11:02   ` Dan Carpenter
2014-04-29 19:16     ` Hammond, John
2014-04-29 20:17       ` Dan Carpenter
2014-04-30  3:21     ` Oleg Drokin
2014-04-30  8:01       ` Dan Carpenter
2014-04-29 11:12   ` Richard Weinberger
2014-04-27 17:07 ` [PATCH 42/47] staging/lustre: remove assertion of spin_is_locked() Oleg Drokin
2014-04-27 17:07 ` [PATCH 43/47] staging/lustre/osc: Update inode timestamp for lockless IO as well Oleg Drokin
2014-04-27 17:07 ` [PATCH 44/47] staging/lustre: Always clamp cdls_delay between min and max Oleg Drokin
2014-04-27 17:07 ` [PATCH 45/47] staging/lustre: pass fsync() range through RPC/IO stack Oleg Drokin
2014-04-27 17:07 ` Oleg Drokin [this message]
2014-04-27 17:30   ` [PATCH 46/47] staging/lustre: Fix unsafe userspace access in many proc files Greg Kroah-Hartman
2014-04-27 17:07 ` [PATCH 47/47] staging/lustre/llite: prevent buffer overflow in fiemap Oleg Drokin
2014-04-27 17:33 ` [PATCH 00/47] Lustre fixes and cleanups Greg Kroah-Hartman
2014-04-27 18:28   ` Oleg Drokin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1398618431-29757-47-git-send-email-green@linuxhacker.ru \
    --to=green@linuxhacker.ru \
    --cc=devel@driverdev.osuosl.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=oleg.drokin@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).