Re: [PATCH 2/2 V2] livepatch: handle kzalloc failure properly
From: Joe Lawrence
Date: Thu Dec 13 2018 - 15:39:25 EST
On 12/13/2018 01:51 PM, Nicholas Mc Guire wrote:
> On Thu, Dec 13, 2018 at 11:39:25AM -0500, Joe Lawrence wrote:
>> On 12/13/2018 10:39 AM, Nicholas Mc Guire wrote:
>>> On Thu, Dec 13, 2018 at 09:14:18AM -0500, Joe Lawrence wrote:
>>>> On 12/13/2018 09:05 AM, Nicholas Mc Guire wrote:
>>>>> kzalloc() return should be checked. On dummy_alloc() failing
>>>>> in kzalloc() NULL should be returned.
>>>>>
>>>>> Signed-off-by: Nicholas Mc Guire <hofrat@xxxxxxxxx>
>>>>> ---
>>>>>
>>>>> Problem was located with an experimental coccinelle script
>>>>>
>>>>> V2: returning NULL is ok but not without cleanup - thanks to
>>>>> Petr Mladek <pmladek@xxxxxxxx> for catching this.
>>>>>
>>>>> Patch was compile tested with: x86_64_defconfig + FTRACE=y
>>>>> FUNCTION_TRACER=y, EXPERT=y, LATENCYTOP=y, SAMPLES=y, SAMPLE_LIVEPATCH=y
>>>>> (with a number of unrelated sparse warnings on symbols not being static)
>>>>>
>>>>> Patch is against 4.20-rc6 (localversion-next is next-20181213)
>>>>>
>>>>> samples/livepatch/livepatch-shadow-mod.c | 4 ++++
>>>>> 1 file changed, 4 insertions(+)
>>>>>
>>>>> diff --git a/samples/livepatch/livepatch-shadow-mod.c b/samples/livepatch/livepatch-shadow-mod.c
>>>>> index 4c54b25..4aa8a88 100644
>>>>> --- a/samples/livepatch/livepatch-shadow-mod.c
>>>>> +++ b/samples/livepatch/livepatch-shadow-mod.c
>>>>> @@ -118,6 +118,10 @@ noinline struct dummy *dummy_alloc(void)
>>>>>
>>>>> /* Oops, forgot to save leak! */
>>>>> leak = kzalloc(sizeof(int), GFP_KERNEL);
>>>>> + if (!leak) {
>>>>> + kfree(d);
>>>>> + return NULL;
>>>>> + }
>>>>>
>>>>> pr_info("%s: dummy @ %p, expires @ %lx\n",
>>>>> __func__, d, d->jiffies_expire);
>>>>>
>>>>
>>>> Hi Nicholas,
>>>>
>>>> Thanks for finding and fixing these up... can we either squash these two
>>>> patches into a single commit or give them unique subject lines? Code
>>>> looks good (including Petr's suggested fix) otherwise.
>>>>
>>> yup - makes sense to pop it into a single patch - I assumed that this
>>> would not be acceptable - so I actually split it up :)
>>> IÂll send a V3 then.
>>
>> I don't know if there is a hard rule, but I always thought that unique
>> subject lines were desired to avoid grep/search confusion.
>>
> the duplicated subjectline was my mistake
>
>> As far as one or two commits, I'd prefer a single commit since these are
>> so small. Personal preference, you could just say that you're fixing
>> samples/livepatch as a whole.
>>
>>>
>>> BTW: wanted to fix up the sparse warnings but I think thats not going
>>> to be that simple as the functions/structs sparse complains about
>>> are actually being shared:
>>
>> Ok, these are welcome too, separate commit...
>>
>>> CHECK samples/livepatch/livepatch-shadow-fix1.c
>>> samples/livepatch/livepatch-shadow-fix1.c:74:14: warning: symbol 'livepatch_fix1_dummy
>>> alloc' was not declared. Should it be static?
>>> samples/livepatch/livepatch-shadow-fix1.c:116:6: warning: symbol 'livepatch_fix1_dummy
>>> free' was not declared. Should it be static?
>>>
>>> CHECK samples/livepatch/livepatch-shadow-mod.c
>>> samples/livepatch/livepatch-shadow-mod.c:99:1: warning: symbol 'dummy_list' was not declared. Should it be static?
>>> samples/livepatch/livepatch-shadow-mod.c:100:1: warning: symbol 'dummy_list_mutex' was not declared. Should it be static?
>>> samples/livepatch/livepatch-shadow-mod.c:107:23: warning: symbol 'dummy_alloc' was not declared. Should it be static?
>>> samples/livepatch/livepatch-shadow-mod.c:132:15: warning: symbol 'dummy_free' was not declared. Should it be static?
>>> samples/livepatch/livepatch-shadow-mod.c:140:15: warning: symbol 'dummy_check' was not declared. Should it be static?
>>>
>>> so to clean that appropriate declarations should probably
>>> go into a .h file. Technically its maybe not important as this
>>> is not production code - it would though be nice if sample
>>> code is sparse/smatch/cocci clean.
>>>
>>> would it be acceptable to clean this up with an additional
>>> livepatch-shadow-mod.h ?
>>
>> I'm not a C language expert, but as I understand it: static functions
>> are only a namespacing game for the compiler. So I think it is safe to
>> pass around and call function pointers to static functions between
>> compilation units. At least I see this throughout the kernel, so that
>> is my assumption :)
>>
> IÂm not into the details of livepatch but if I declare e.g. dummy_check
> static as proposed by sparse and then check the relocs I no longer see
> it:
>
> Without the changes sparse proposes dummy_check is visible
> hofrat@debian:~/linux-next/samples/livepatch# readelf --relocs livepatch-shadow-mod.ko | grep dummy_check
> 000000000193 002f00000002 R_X86_64_PC32 0000000000000110 dummy_check - 4
>
> When I then try to load livepatch-shadow-fix1.ko which does not have
> dummy_check in its klp_func array its ok but livepatch-shadow-fix2.ko
> wich has an entry will fail to load. So while this may work with other modules
> I think in the live-patch case its not that simple due to the inner workings
> of resolving symbols via klp_object and klp_func array.
>
> So IÂll leave that sparse cleanup to someone who understand the inner
> workinsgs of livepatch - before I make a mess of it....
>
> thx!
> hofrat
>
Ahh, I understand the question now. Yeah, by making those routines local
static, the compiler applied optimizations that renamed the symbols:
noinline static
% readelf --syms samples/livepatch/livepatch-shadow-mod.o | grep dummy_
5: 0000000000000000 20 FUNC LOCAL DEFAULT 1 dummy_check.isra.0
7: 0000000000000020 52 FUNC LOCAL DEFAULT 1 dummy_free.constprop.1
12: 00000000000000c0 32 OBJECT LOCAL DEFAULT 3 dummy_list_mutex
13: 00000000000000e0 16 OBJECT LOCAL DEFAULT 3 dummy_list
15: 0000000000000160 115 FUNC LOCAL DEFAULT 1 dummy_alloc
I can avoid that optimization (and successfully load all the modules)
by using either:
__attribute__((optimize("O0"))) noinline static
% readelf --syms samples/livepatch/livepatch-shadow-mod.o | grep dummy_
6: 0000000000000000 6016 FUNC LOCAL DEFAULT 1 dummy_alloc
11: 00000000000000c0 32 OBJECT LOCAL DEFAULT 3 dummy_list_mutex
12: 00000000000000e0 16 OBJECT LOCAL DEFAULT 3 dummy_list
14: 0000000000001810 73 FUNC LOCAL DEFAULT 1 dummy_free
16: 0000000000001860 108 FUNC LOCAL DEFAULT 1 dummy_check
or:
__noclone noinline static
% readelf --syms samples/livepatch/livepatch-shadow-mod.o | grep dummy_
5: 0000000000000000 22 FUNC LOCAL DEFAULT 1 dummy_check
7: 0000000000000020 51 FUNC LOCAL DEFAULT 1 dummy_free
12: 00000000000000c0 32 OBJECT LOCAL DEFAULT 3 dummy_list_mutex
13: 00000000000000e0 16 OBJECT LOCAL DEFAULT 3 dummy_list
15: 0000000000000160 115 FUNC LOCAL DEFAULT 1 dummy_alloc
but I'm not sure if either is the definitive way to avoid such
optimization. Anyone know for sure?
-- Joe