Re: [PATCH] fs: make sure we do not read beyond allocation

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

 



On Fri, Oct 11, 2013 at 3:26 PM, Dmitry Vyukov <dvyukov@xxxxxxxxxx> wrote:
> On Fri, Oct 4, 2013 at 5:53 PM, Richard Weinberger <richard@xxxxxx> wrote:
>> Am 04.10.2013 12:53, schrieb Dmitry Vyukov:
>>> On Fri, Oct 4, 2013 at 2:38 PM, Richard Weinberger
>>> <richard.weinberger@xxxxxxxxx> wrote:
>>>>>>>> ...
>>>>>>>> [1] yes, yes, I know - the mere mention of security should've prevented such
>>>>>>>> arrogant requests.  It's an imperfect universe.
>>>>>>>
>>>>>>> I want to attempt to disassemble what you've communicating here:
>>>>>>>
>>>>>>> a) I'm not thinking.
>>>>>>> b) Requesting that someone think when they mention security is arrogant.
>>>>>>
>>>>>> Not really.
>>>>>>
>>>>>> It's just that all too often completely pointless changes are touted
>>>>>> as security hardening.  With replies along the lines of "it doesn't
>>>>>> really buy you anything" countered with indignant "but what if
>>>>>> <impossible situation>" and/or references to "defense in depth" (used
>>>>>> as a magical incantation), etc.
>>>>>>
>>>>>> You've posted a provably pointless patch.  Happens to all of us.  And in
>>>>>> reply to "it's pointless for the following reasons" (with moderate
>>>>>> level of sarcasm) you responded pretty much with "but what if allocator
>>>>>> changes?  It's more robust that way".  OK, but if you go for that
>>>>>> kind of arguments (and they can be valid), you'd better be correct.
>>>>>> You were not, and for very obvious reasons.  Let me repeat, this
>>>>>> time with sarcasm level down to zero:
>>>>>>
>>>>>> Let n be some integer between 32 and 4096 and N be equal to n rounded up
>>>>>> to word size.  If kmalloc(n) returns a pointer such that fetch from
>>>>>> (char *)p[N - 1] triggers an exception, we have a badly broken kernel.
>>>>>> It can happen only if there is a page boundary between p[n-1] and p[N-1],
>>>>>> which means that p is not word-aligned.
>>>>>> Consider the following code:
>>>>>>         struct foo {
>>>>>>                 unsigned long n;
>>>>>>                 char a[];
>>>>>>         } *p = kmalloc(offsetof(struct foo, a) + 33);
>>>>>>         if (p)
>>>>>>                 p->n = 1;
>>>>>> and note that it will result in an exception on any architecture that prohibits
>>>>>> unaligned accesses in the kernel.  Even on architectures where those are
>>>>>> allowed, misaligned structures mean serious correctness problems (atomicity of
>>>>>> stores, etc.)
>>>>>>
>>>>>> In other words, kmalloc() (or, indeed, userland malloc()) demonstrating
>>>>>> such behaviour would need immediate fixing.  The only exception I can
>>>>>> think of is something with byte granularity of memory protection; in such
>>>>>> case we can have that without unaligned return values returned by allocator.
>>>>>> Which would require a lot of changes in mm/*, at the very least, and probably
>>>>>> would violate a lot of assumptions elsewhere in the kernel (starting with
>>>>>> sizeof(void *) == sizeof(unsigned long)).
>>>>>>
>>>>>>> What the patch does help with, though, is dynamic analysis tools that
>>>>>>> are looking for out-of-bound reads, which this clearly is. It should
>>>>>>> be considered a violation of the API to attempt to access a range
>>>>>>> beyond what was requested for the allocation. Fixing this means lots
>>>>>>> of noise vanishes from such analysis of the allocation API, letting
>>>>>>> other tools besides just KASAN do work to find other more serious
>>>>>>> problems in heap usage.
>>>>>>>
>>>>>>> Does fixing this to help dynamic analysis tools somehow make the
>>>>>>> kernel worse? I think that fixing this makes it easier to find further
>>>>>>> bugs that might be much more serious.
>>>>>>
>>>>>> Possibly true.  But then I'd suggest wrapping that into a different ifdef;
>>>>>> grep for ifdef __CHECKER__, with comment along the lines of "to simplify
>>>>>> analysis of potential out-of-bounds accesses".
>>>>>
>>>>>
>>>>> Hi,
>>>>>
>>>>> Any single reason to not just fix the code?
>>>>>
>>>>> With this patch:
>>>>> + sticks with "do not access beyond request size", which is a good
>>>>> thing all others equal
>>>>> + makes static and dynamic verification tools happy
>>>>> - ???
>>>>
>>>> - It does not fix anything, it only shuts up the checker
>>>> - It adds another ifdef where it is not obvious why it's needed
>>>>
>>>> Therefore it makes more sense to add a ifdef __CHECKER__ such that
>>>> everyone immediately knows that the issue is only false positive.
>>>
>>>
>>> OK, is it explicitly documented somewhere that it's legal to access
>>> memory blocks beyond requested size? Is it a deliberate decision made
>>> by community? Or just an ad-hoc argument based on details of current
>>> implementation?
>>
>> Al explained already why it is legal.
>>
>>> If it's the former then we will need to teach the tools to understand
>>> it. But IMVHO it's a very unfortunate decision, because it will hide
>>> real harmful bugs. And this is the only place where I observed such
>>> out-of-bounds access after months of stress testing, so we are not
>>> talking about hundreds and thousands of precedents. We are talking
>>> about this particular case vs ability of tools to catch harmful
>>> off-by-one accesses to variable-length strings and buffers.
>>
>> Have you ever used valgrind (or any other checkers in userspace)?
>> They all suffer from such issues.
>> If a checker reports a violation it is not always a real one and
>> you have to review it carefully.
>
> I am not sure why you call it not a real one. Both C and C++ standards
> are pretty clear on this: it is undefined behavior.
> That said, Valgrind/memcheck indeed has other false positives, because
> it tries to reason about source code looking only at the binary. This
> can not possibly work.
> AddressSanitizer
> (https://sites.google.com/a/google.com/dynamic-tools/addresssanitizer)
> does not have known false positives.


What about the following patch?

-               dname = kmalloc(name->len + 1, GFP_KERNEL);
+               // We are going to access it as array of long's.
+               dname = kmalloc(round_up(name->len + 1,
sizeof(unsigned long)), GFP_KERNEL);
--
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