live-patching.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [bug report] livepatch: Initialize shadow variables safely by a custom callback
@ 2020-01-07 13:29 Dan Carpenter
  2020-01-07 15:06 ` Joe Lawrence
  0 siblings, 1 reply; 6+ messages in thread
From: Dan Carpenter @ 2020-01-07 13:29 UTC (permalink / raw)
  To: pmladek; +Cc: live-patching

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?

    86                           shadow_leak_ctor, leak);
    87  
    88          pr_info("%s: dummy @ %p, expires @ %lx\n",
    89                  __func__, d, d->jiffies_expire);
    90  
    91          return d;
    92  }

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] livepatch: Initialize shadow variables safely by a custom callback
  2020-01-07 13:29 [bug report] livepatch: Initialize shadow variables safely by a custom callback Dan Carpenter
@ 2020-01-07 15:06 ` Joe Lawrence
  2020-01-07 15:23   ` Dan Carpenter
  0 siblings, 1 reply; 6+ messages in thread
From: Joe Lawrence @ 2020-01-07 15:06 UTC (permalink / raw)
  To: Dan Carpenter, pmladek; +Cc: live-patching

On 1/7/20 8:29 AM, Dan Carpenter wrote:
> 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?  Does it expect to see the typical allocation pattern like:

   int *foo = alloc(sizeof(*foo))

and not:

   int *foo = alloc(sizeof(foo))


Thanks,

-- Joe

>      86                           shadow_leak_ctor, leak);
>      87
>      88          pr_info("%s: dummy @ %p, expires @ %lx\n",
>      89                  __func__, d, d->jiffies_expire);
>      90
>      91          return d;
>      92  }
> 
> regards,
> dan carpenter
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] livepatch: Initialize shadow variables safely by a custom callback
  2020-01-07 15:06 ` Joe Lawrence
@ 2020-01-07 15:23   ` Dan Carpenter
  2020-01-07 15:43     ` Joe Lawrence
  2020-01-09  9:29     ` Petr Mladek
  0 siblings, 2 replies; 6+ messages in thread
From: Dan Carpenter @ 2020-01-07 15:23 UTC (permalink / raw)
  To: Joe Lawrence; +Cc: pmladek, live-patching

On Tue, Jan 07, 2020 at 10:06:21AM -0500, Joe Lawrence wrote:
> On 1/7/20 8:29 AM, Dan Carpenter wrote:
> > 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?  Does it expect to see the typical allocation pattern like:
> 
>   int *foo = alloc(sizeof(*foo))
> 
> and not:
> 
>   int *foo = alloc(sizeof(foo))
> 

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.

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] livepatch: Initialize shadow variables safely by a custom callback
  2020-01-07 15:23   ` Dan Carpenter
@ 2020-01-07 15:43     ` Joe Lawrence
  2020-01-09  9:29     ` Petr Mladek
  1 sibling, 0 replies; 6+ messages in thread
From: Joe Lawrence @ 2020-01-07 15:43 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: pmladek, live-patching

On 1/7/20 10:23 AM, Dan Carpenter wrote:
> On Tue, Jan 07, 2020 at 10:06:21AM -0500, Joe Lawrence wrote:
>> On 1/7/20 8:29 AM, Dan Carpenter wrote:
>>> 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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [bug report] livepatch: Initialize shadow variables safely by a custom callback
  2020-01-07 15:23   ` Dan Carpenter
  2020-01-07 15:43     ` Joe Lawrence
@ 2020-01-09  9:29     ` Petr Mladek
  2020-01-13 15:11       ` Joe Lawrence
  1 sibling, 1 reply; 6+ messages in thread
From: Petr Mladek @ 2020-01-09  9:29 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: Joe Lawrence, live-patching

On Tue 2020-01-07 18:23:37, Dan Carpenter wrote:
> On Tue, Jan 07, 2020 at 10:06:21AM -0500, Joe Lawrence wrote:
> > On 1/7/20 8:29 AM, Dan Carpenter wrote:
> > > 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?  Does it expect to see the typical allocation pattern like:
> > 
> >   int *foo = alloc(sizeof(*foo))
> > 
> > and not:
> > 
> >   int *foo = alloc(sizeof(foo))
> > 
> 
> 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 think that this is the problem. 3rd argument is size of the
data. The last argument should be pointer to the data.

In our case, the data is pointer to the integer. We correctly
pass the size of the pointer but we pass the pointer directly.
It works because shadow_leak_ctor() is aware of this. But
it is semantically wrong.

I propose the following patch. It should probably get split
into 2 or 3 patches. In addition, we should fix
lib/livepatch/test_klp_shadow_vars.c and use the API
a clean way there as well.

I could prepare a proper patchset if you agree with
the idea. And if it actually fixes the reported error
message.

Here is a RFC patch:

From ab6cd83f6a46894c764adf9315db99ce52a9283b Mon Sep 17 00:00:00 2001
From: Petr Mladek <pmladek@suse.com>
Date: Wed, 8 Jan 2020 15:44:33 +0100
Subject: [RFC 1/1] livepatch/samples: Correctly use leak variable as a
 pointer to int

The commit e91c2518a5d2 ("livepatch: Initialize shadow variables
safely by a custom callback" 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)

It is because klp_shadow_alloc() is used a wrong way:

	int *leak;
	shadow_leak = klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
				       shadow_leak_ctor, leak);

The code is supposed to store the "leak" pointer into the shadow variable.
3rd parameter correctly passes size of the data (size if pointer). But
the 5th parameter is wrong. It should pass pointer to the data (pointer
to the pointer) but it passes the pointer directly.

It works because shadow_leak_ctor() handle "ctor_data" as the data
insted of pointer to the data. But it is semantically wrong and
confusing.

The minimal fix is to pass poiter to the poitner. Even better is
using the correct type: int pointer instead of void poiter.

In addition there should be some check of potential failures.

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
 samples/livepatch/livepatch-shadow-fix1.c | 38 +++++++++++++++++++++----------
 samples/livepatch/livepatch-shadow-fix2.c |  4 ++--
 samples/livepatch/livepatch-shadow-mod.c  |  2 +-
 3 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c
index e89ca4546114..a02371cf34d3 100644
--- a/samples/livepatch/livepatch-shadow-fix1.c
+++ b/samples/livepatch/livepatch-shadow-fix1.c
@@ -52,17 +52,21 @@ struct dummy {
  */
 static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data)
 {
-	void **shadow_leak = shadow_data;
-	void *leak = ctor_data;
+	int **shadow_leak = shadow_data;
+	int **leak = ctor_data;
 
-	*shadow_leak = leak;
+	if (!ctor_data)
+		return -EINVAL;
+
+	*shadow_leak = *leak;
 	return 0;
 }
 
 static struct dummy *livepatch_fix1_dummy_alloc(void)
 {
 	struct dummy *d;
-	void *leak;
+	int *leak;
+	int **shadow_leak;
 
 	d = kzalloc(sizeof(*d), GFP_KERNEL);
 	if (!d)
@@ -77,24 +81,34 @@ static struct dummy *livepatch_fix1_dummy_alloc(void)
 	 * pointer to handle resource release.
 	 */
 	leak = kzalloc(sizeof(int), GFP_KERNEL);
-	if (!leak) {
-		kfree(d);
-		return NULL;
-	}
+	if (!leak)
+		goto err_leak;
 
-	klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
-			 shadow_leak_ctor, leak);
+	shadow_leak = klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
+				       shadow_leak_ctor, &leak);
+
+	if (!shadow_leak) {
+		pr_err("%s: failed to allocate shadow variable for the leaking pointer: dummy @ %p, leak @ %p\n",
+		       __func__, d, leak);
+		goto err_shadow;
+	}
 
 	pr_info("%s: dummy @ %p, expires @ %lx\n",
 		__func__, d, d->jiffies_expire);
 
 	return d;
+
+err_shadow:
+	kfree(leak);
+err_leak:
+	kfree(d);
+	return NULL;
 }
 
 static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)
 {
 	void *d = obj;
-	void **shadow_leak = shadow_data;
+	int **shadow_leak = shadow_data;
 
 	kfree(*shadow_leak);
 	pr_info("%s: dummy @ %p, prevented leak @ %p\n",
@@ -103,7 +117,7 @@ static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)
 
 static void livepatch_fix1_dummy_free(struct dummy *d)
 {
-	void **shadow_leak;
+	int **shadow_leak;
 
 	/*
 	 * Patch: fetch the saved SV_LEAK shadow variable, detach and
diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c
index 50d223b82e8b..29fe5cd42047 100644
--- a/samples/livepatch/livepatch-shadow-fix2.c
+++ b/samples/livepatch/livepatch-shadow-fix2.c
@@ -59,7 +59,7 @@ static bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies)
 static void livepatch_fix2_dummy_leak_dtor(void *obj, void *shadow_data)
 {
 	void *d = obj;
-	void **shadow_leak = shadow_data;
+	int **shadow_leak = shadow_data;
 
 	kfree(*shadow_leak);
 	pr_info("%s: dummy @ %p, prevented leak @ %p\n",
@@ -68,7 +68,7 @@ static void livepatch_fix2_dummy_leak_dtor(void *obj, void *shadow_data)
 
 static void livepatch_fix2_dummy_free(struct dummy *d)
 {
-	void **shadow_leak;
+	int **shadow_leak;
 	int *shadow_count;
 
 	/* Patch: copy the memory leak patch from the fix1 module. */
diff --git a/samples/livepatch/livepatch-shadow-mod.c b/samples/livepatch/livepatch-shadow-mod.c
index ecfe83a943a7..19c3a6824b64 100644
--- a/samples/livepatch/livepatch-shadow-mod.c
+++ b/samples/livepatch/livepatch-shadow-mod.c
@@ -95,7 +95,7 @@ struct dummy {
 static __used noinline struct dummy *dummy_alloc(void)
 {
 	struct dummy *d;
-	void *leak;
+	int *leak;
 
 	d = kzalloc(sizeof(*d), GFP_KERNEL);
 	if (!d)
-- 
2.16.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [bug report] livepatch: Initialize shadow variables safely by a custom callback
  2020-01-09  9:29     ` Petr Mladek
@ 2020-01-13 15:11       ` Joe Lawrence
  0 siblings, 0 replies; 6+ messages in thread
From: Joe Lawrence @ 2020-01-13 15:11 UTC (permalink / raw)
  To: Petr Mladek; +Cc: Dan Carpenter, live-patching

On Thu, Jan 09, 2020 at 10:29:34AM +0100, Petr Mladek wrote:
> On Tue 2020-01-07 18:23:37, Dan Carpenter wrote:
> > On Tue, Jan 07, 2020 at 10:06:21AM -0500, Joe Lawrence wrote:
> > > On 1/7/20 8:29 AM, Dan Carpenter wrote:
> > > > 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?  Does it expect to see the typical allocation pattern like:
> > > 
> > >   int *foo = alloc(sizeof(*foo))
> > > 
> > > and not:
> > > 
> > >   int *foo = alloc(sizeof(foo))
> > > 
> > 
> > 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 think that this is the problem. 3rd argument is size of the
> data. The last argument should be pointer to the data.
> 
> In our case, the data is pointer to the integer. We correctly
> pass the size of the pointer but we pass the pointer directly.
> It works because shadow_leak_ctor() is aware of this. But
> it is semantically wrong.
> 
> I propose the following patch. It should probably get split
> into 2 or 3 patches. In addition, we should fix
> lib/livepatch/test_klp_shadow_vars.c and use the API
> a clean way there as well.
> 
> I could prepare a proper patchset if you agree with
> the idea. And if it actually fixes the reported error
> message.
> 
> Here is a RFC patch:
> 
> From ab6cd83f6a46894c764adf9315db99ce52a9283b Mon Sep 17 00:00:00 2001
> From: Petr Mladek <pmladek@suse.com>
> Date: Wed, 8 Jan 2020 15:44:33 +0100
> Subject: [RFC 1/1] livepatch/samples: Correctly use leak variable as a
>  pointer to int
> 
> The commit e91c2518a5d2 ("livepatch: Initialize shadow variables
> safely by a custom callback" 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)
> 
> It is because klp_shadow_alloc() is used a wrong way:
> 
> 	int *leak;
> 	shadow_leak = klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
> 				       shadow_leak_ctor, leak);
> 
> The code is supposed to store the "leak" pointer into the shadow variable.
> 3rd parameter correctly passes size of the data (size if pointer). But
                                                        ^^
nit: s/if/of
> the 5th parameter is wrong. It should pass pointer to the data (pointer
> to the pointer) but it passes the pointer directly.
> 
> It works because shadow_leak_ctor() handle "ctor_data" as the data
> insted of pointer to the data. But it is semantically wrong and
nit: s/insted/instead

> confusing.
> 
> The minimal fix is to pass poiter to the poitner. Even better is
nit: s/poiter/pointer        ^^^^^^        ^^^^^^^

> using the correct type: int pointer instead of void poiter.
nit: same                                             ^^^^^^
> 
> In addition there should be some check of potential failures.
> 
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> Signed-off-by: Petr Mladek <pmladek@suse.com>
> ---
>  samples/livepatch/livepatch-shadow-fix1.c | 38 +++++++++++++++++++++----------
>  samples/livepatch/livepatch-shadow-fix2.c |  4 ++--
>  samples/livepatch/livepatch-shadow-mod.c  |  2 +-
>  3 files changed, 29 insertions(+), 15 deletions(-)
> 
> diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c
> index e89ca4546114..a02371cf34d3 100644
> --- a/samples/livepatch/livepatch-shadow-fix1.c
> +++ b/samples/livepatch/livepatch-shadow-fix1.c
> @@ -52,17 +52,21 @@ struct dummy {
>   */
>  static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data)
>  {
> -	void **shadow_leak = shadow_data;
> -	void *leak = ctor_data;
> +	int **shadow_leak = shadow_data;
> +	int **leak = ctor_data;
>  
> -	*shadow_leak = leak;
> +	if (!ctor_data)
> +		return -EINVAL;
> +
> +	*shadow_leak = *leak;
>  	return 0;
>  }
>  
>  static struct dummy *livepatch_fix1_dummy_alloc(void)
>  {
>  	struct dummy *d;
> -	void *leak;
> +	int *leak;
> +	int **shadow_leak;
>  
>  	d = kzalloc(sizeof(*d), GFP_KERNEL);
>  	if (!d)
> @@ -77,24 +81,34 @@ static struct dummy *livepatch_fix1_dummy_alloc(void)
>  	 * pointer to handle resource release.
>  	 */
>  	leak = kzalloc(sizeof(int), GFP_KERNEL);
> -	if (!leak) {
> -		kfree(d);
> -		return NULL;
> -	}
> +	if (!leak)
> +		goto err_leak;
>  
> -	klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
> -			 shadow_leak_ctor, leak);
> +	shadow_leak = klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
> +				       shadow_leak_ctor, &leak);
> +
> +	if (!shadow_leak) {
> +		pr_err("%s: failed to allocate shadow variable for the leaking pointer: dummy @ %p, leak @ %p\n",

Perhaps in a future clean up, should we consider using %px for printing
these debug pointer values?

> +		       __func__, d, leak);
> +		goto err_shadow;
> +	}
>  
>  	pr_info("%s: dummy @ %p, expires @ %lx\n",
>  		__func__, d, d->jiffies_expire);
>  
>  	return d;
> +
> +err_shadow:
> +	kfree(leak);
> +err_leak:
> +	kfree(d);
> +	return NULL;
>  }
>  
>  static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)
>  {
>  	void *d = obj;
> -	void **shadow_leak = shadow_data;
> +	int **shadow_leak = shadow_data;
>  
>  	kfree(*shadow_leak);
>  	pr_info("%s: dummy @ %p, prevented leak @ %p\n",
> @@ -103,7 +117,7 @@ static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data)
>  
>  static void livepatch_fix1_dummy_free(struct dummy *d)
>  {
> -	void **shadow_leak;
> +	int **shadow_leak;
>  
>  	/*
>  	 * Patch: fetch the saved SV_LEAK shadow variable, detach and
> diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c
> index 50d223b82e8b..29fe5cd42047 100644
> --- a/samples/livepatch/livepatch-shadow-fix2.c
> +++ b/samples/livepatch/livepatch-shadow-fix2.c
> @@ -59,7 +59,7 @@ static bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies)
>  static void livepatch_fix2_dummy_leak_dtor(void *obj, void *shadow_data)
>  {
>  	void *d = obj;
> -	void **shadow_leak = shadow_data;
> +	int **shadow_leak = shadow_data;
>  
>  	kfree(*shadow_leak);
>  	pr_info("%s: dummy @ %p, prevented leak @ %p\n",
> @@ -68,7 +68,7 @@ static void livepatch_fix2_dummy_leak_dtor(void *obj, void *shadow_data)
>  
>  static void livepatch_fix2_dummy_free(struct dummy *d)
>  {
> -	void **shadow_leak;
> +	int **shadow_leak;
>  	int *shadow_count;
>  
>  	/* Patch: copy the memory leak patch from the fix1 module. */
> diff --git a/samples/livepatch/livepatch-shadow-mod.c b/samples/livepatch/livepatch-shadow-mod.c
> index ecfe83a943a7..19c3a6824b64 100644
> --- a/samples/livepatch/livepatch-shadow-mod.c
> +++ b/samples/livepatch/livepatch-shadow-mod.c
> @@ -95,7 +95,7 @@ struct dummy {
>  static __used noinline struct dummy *dummy_alloc(void)
>  {
>  	struct dummy *d;
> -	void *leak;
> +	int *leak;
>  
>  	d = kzalloc(sizeof(*d), GFP_KERNEL);
>  	if (!d)
> -- 
> 2.16.4
> 

Hi Petr, this clean-up looks good to me, thanks for taking care of it
and adding the additional shadow variable allocation check.  With a few
minor spelling fixes I think it would be good to go.

Acked-by: Joe Lawrence <joe.lawrence@redhat.com>

-- Joe


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-01-13 15:11 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-07 13:29 [bug report] livepatch: Initialize shadow variables safely by a custom callback Dan Carpenter
2020-01-07 15:06 ` Joe Lawrence
2020-01-07 15:23   ` Dan Carpenter
2020-01-07 15:43     ` Joe Lawrence
2020-01-09  9:29     ` Petr Mladek
2020-01-13 15:11       ` Joe Lawrence

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).