Re: [PATCH v2] fs/nilfs2: Integer overflow in nilfs_ioctl_wrap_copy()

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

 



Hi Andrew,
On Fri, 3 Jan 2014 16:10:15 -0800, Andrew Morton wrote:
> On Fri,  3 Jan 2014 14:10:54 +0800 Wenliang Fan <fanwlexca@xxxxxxxxx> wrote:
> 
>> v1->v2
>> *Check on every iteration is removed because the check before cycle is enough.
>> 
>> Check before entering into cycle.
>> 
>> The local variable 'pos' comes from userspace. If a large number was
>> passed, there would be an integer overflow in the following line:
>>         pos += n;
>> 
>> Signed-off-by: Wenliang Fan <fanwlexca@xxxxxxxxx>
>> ---
>>  fs/nilfs2/ioctl.c | 3 +++
>>  1 file changed, 3 insertions(+)
>> 
>> diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
>> index b44bdb2..231c945 100644
>> --- a/fs/nilfs2/ioctl.c
>> +++ b/fs/nilfs2/ioctl.c
>> @@ -57,6 +57,9 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
>>  	if (argv->v_size > PAGE_SIZE)
>>  		return -EINVAL;
>>  
>> +	if (argv->v_index > (~(__u64)0 - argv->v_nmembs))
>> +		return -EINVAL;
>> +
>>  	buf = (void *)__get_free_pages(GFP_NOFS, 0);
>>  	if (unlikely(!buf))
>>  		return -ENOMEM;
> 
> Geeze, that function is really hard to understand.  The poor
> documentation for nilfs_argv.v_index is hurting here.
> 
> Why doesn't this patch do
> 
> 	if (argv->v_index >= argv->v_nmembs)
> 		return -EINVAL;
> 
> ?
> 
> That's what one would *expect* to see, so something weird must be going
> on?

Sorry for the poor documentation of nilfs_argv struct and
nilfs_ioctl_wrap_copy function.

argv->v_index is not an index of argv->v_base[] array but gives a
start position of the data items that userland programs want to get
information about.

For instance, a segment number is given in case to get segment
information, a checkpoint number is given for checkpoint information,
or virtual block address is given for disk block information.

argv->v_nmembs gives the number of the items that userland programs
want to get information about.

The inserted check ensures that (argv->v_index + argv->v_nmembs)
doesn't exceed the maximum value of __u64 type integer, and prevents
overflow of the position variable 'pos'.


I modified the commit log and also added a few comment lines to
clarify the address of the patch.  The modified patch is attached
below.

I think this patch is a minor fix and is not urgent since the overflow
looks not to cause security issue nor kernel panic.

Thanks,
Ryusuke Konishi

----
From: Wenliang Fan <fanwlexca@xxxxxxxxx>

nilfs2: prevent integer overflow in nilfs_ioctl_wrap_copy()

The local variable 'pos' in nilfs_ioctl_wrap_copy function can
overflow if a large number was passed to argv->v_index from userspace
and the sum of argv->v_index and argv->v_nmembs exceeds the maximum
value of __u64 type integer (= ~(__u64)0 = 18446744073709551615).

Here, argv->v_index is a 64-bit width argument to specify the start
position of target data items (such as segment number, checkpoint
number, or virtual block address of nilfs), and argv->v_nmembs gives
the total number of the items that userland programs (such as lssu,
lscp, or cleanerd) want to get information about, which also gives the
maximum element count of argv->v_base[] array.

nilfs_ioctl_wrap_copy() calls dofunc() repeatedly and increments the
position variable 'pos' at the end of each iteration if dofunc()
itself didn't update 'pos':

      if (pos == ppos)
              pos += n;

This patch prevents the overflow here by rejecting pairs of a start
position (argv->v_index) and a total count (argv->v_nmembs) which
leads to the overflow.

v1->v2:
* Check on every iteration is removed because the check before
  cycle is enough.

Signed-off-by: Wenliang Fan <fanwlexca@xxxxxxxxx>
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx>
---
 fs/nilfs2/ioctl.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index b44bdb2..d22281d 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -57,6 +57,14 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
 	if (argv->v_size > PAGE_SIZE)
 		return -EINVAL;
 
+	/*
+	 * Reject pairs of a start item position (argv->v_index) and a
+	 * total count (argv->v_nmembs) which leads position 'pos' to
+	 * overflow by the increment at the end of the loop.
+	 */
+	if (argv->v_index > ~(__u64)0 - argv->v_nmembs)
+		return -EINVAL;
+
 	buf = (void *)__get_free_pages(GFP_NOFS, 0);
 	if (unlikely(!buf))
 		return -ENOMEM;
-- 
1.7.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux BTRFS]     [Linux CIFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux