Re: [bug report] livepatch: Initialize shadow variables safely by a custom callback
From: Joe Lawrence <joe.lawrence@redhat.com>
Date: 2020-01-07 15:43:19
On 1/7/20 10:23 AM, Dan Carpenter wrote:
On Tue, Jan 07, 2020 at 10:06:21AM -0500, Joe Lawrence wrote:quoted
On 1/7/20 8:29 AM, Dan Carpenter wrote:quoted
Hello Petr Mladek, The patch e91c2518a5d2: "livepatch: Initialize shadow variables safely by a custom callback" from Apr 16, 2018, leads to the following static checker warning: samples/livepatch/livepatch-shadow-fix1.c:86 livepatch_fix1_dummy_alloc() error: 'klp_shadow_alloc()' 'leak' too small (4 vs 8) samples/livepatch/livepatch-shadow-fix1.c 53 static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data) 54 { 55 void **shadow_leak = shadow_data; 56 void *leak = ctor_data; 57 58 *shadow_leak = leak; 59 return 0; 60 } 61 62 static struct dummy *livepatch_fix1_dummy_alloc(void) 63 { 64 struct dummy *d; 65 void *leak; 66 67 d = kzalloc(sizeof(*d), GFP_KERNEL); 68 if (!d) 69 return NULL; 70 71 d->jiffies_expire = jiffies + 72 msecs_to_jiffies(1000 * EXPIRE_PERIOD); 73 74 /* 75 * Patch: save the extra memory location into a SV_LEAK shadow 76 * variable. A patched dummy_free routine can later fetch this 77 * pointer to handle resource release. 78 */ 79 leak = kzalloc(sizeof(int), GFP_KERNEL); 80 if (!leak) { 81 kfree(d); 82 return NULL; 83 } 84 85 klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL, ^^^^^^^^^^^^ This doesn't seem right at all? Leak is a pointer. Why is leak a void pointer instead of an int pointer?Hi Dan, If I remember this code correctly, the shadow variable is tracking the pointer value itself and not its contents, so sizeof(leak) should be correct for the shadow variable data size. (For kernel/livepatch/shadow.c :: __klp_shadow_get_or_alloc() creates new struct klp_shadow with .data[size] to accommodate its meta-data plus the desired data). Why isn't leak an int pointer? I don't remember why, according to git history it's been that way since the beginning. I think it was coded to say, "Give me some storage, any size an int will do. I'm not going to touch it, but I want to demonstrate a memory leak". Would modifying the pointer type satisfy the static code complaint? Since the warning is about a size mismatch, what are the parameters that it is keying on? [ ... snip ... ]It looks at places which call klp_shadow_alloc() and says that sometimes the third argument is the size of the last argument. Then it complains when a caller doesn't match. I could just make klp_shadow_alloc() an exception.
Ah, I see. It must also be checking that the last two arguments (ctor, ctor_data) are non-null, as that's the simplified calling sequence. /me runs cscope to find an example ... Well that's interesting, there really aren't any other klp_shadow_alloc() callers aside from lib/livepatch/test_klp_shadow_vars.c, which hides it in a wrapper routine that probably dodges the static code check. For a typical out-of-tree example [1], we do a lot of this: newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, NULL, NULL); if (newpid) *newpid = ctr++; as we don't always need the constructor / destructor callbacks for simple shadow variables. Since the ctor/dtor callback part of the API was provided by Petr, I'll let him chime in what the code checker should be warning about here. I think it may be more complicated than it's worth, but maybe he has another idea. Regards, -- Joe [1] https://github.com/dynup/kpatch/blob/master/test/integration/centos-7/shadow-newpid.patch