diff mbox

net/rds: using strlcpy instead of strncpy

Message ID 512F1534.9020404@asianux.com
State Rejected, archived
Delegated to: David Miller
Headers show

Commit Message

Chen Gang Feb. 28, 2013, 8:28 a.m. UTC
when src strlen is sizeof(ctr.name) - 1, the dest str is not '\0' end.
  better use strlcpy instead.

Signed-off-by: Chen Gang <gang.chen@asianux.com>
---
 net/rds/stats.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Comments

David Laight Feb. 28, 2013, 9:36 a.m. UTC | #1
>   when src strlen is sizeof(ctr.name) - 1, the dest str is not '\0' end.
>   better use strlcpy instead.
> 
> Signed-off-by: Chen Gang <gang.chen@asianux.com>
> ---
>  net/rds/stats.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/net/rds/stats.c b/net/rds/stats.c
> index 7be790d..b9ac1df 100644
> --- a/net/rds/stats.c
> +++ b/net/rds/stats.c
> @@ -86,7 +86,7 @@ void rds_stats_info_copy(struct rds_info_iterator *iter,
> 
>  	for (i = 0; i < nr; i++) {
>  		BUG_ON(strlen(names[i]) >= sizeof(ctr.name));
> -		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
> +		strlcpy(ctr.name, names[i], sizeof(ctr.name));
>  		ctr.value = values[i];
> 

If the target buffer ends up being copied to userspace that
might lead to random kernel memory being leaked.

	David




--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chen Gang Feb. 28, 2013, 10:26 a.m. UTC | #2
于 2013年02月28日 17:36, David Laight 写道:
>> > diff --git a/net/rds/stats.c b/net/rds/stats.c
>> > index 7be790d..b9ac1df 100644
>> > --- a/net/rds/stats.c
>> > +++ b/net/rds/stats.c
>> > @@ -86,7 +86,7 @@ void rds_stats_info_copy(struct rds_info_iterator *iter,
>> > 
>> >  	for (i = 0; i < nr; i++) {
>> >  		BUG_ON(strlen(names[i]) >= sizeof(ctr.name));
>> > -		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
>> > +		strlcpy(ctr.name, names[i], sizeof(ctr.name));
>> >  		ctr.value = values[i];
>> > 
> If the target buffer ends up being copied to userspace that
> might lead to random kernel memory being leaked.

  excuse me, I do not quite understand what your meaning.

  I guess what you said is:
    if crt.name is not ended by '\0', it will cause issue.
    the issue is:
      "If the target buffer ends up being copied to userspace that
       might lead to random kernel memory being leaked."

  is it correct ?
    if it is correct, need I add them as patch comments, too ?
    else (incorrect), please give more descriptions, thanks.


  :-)
Ben Hutchings March 4, 2013, 6:32 p.m. UTC | #3
On Thu, 2013-02-28 at 09:36 +0000, David Laight wrote:
> >   when src strlen is sizeof(ctr.name) - 1, the dest str is not '\0' end.
> >   better use strlcpy instead.
> > 
> > Signed-off-by: Chen Gang <gang.chen@asianux.com>
> > ---
> >  net/rds/stats.c |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> > 
> > diff --git a/net/rds/stats.c b/net/rds/stats.c
> > index 7be790d..b9ac1df 100644
> > --- a/net/rds/stats.c
> > +++ b/net/rds/stats.c
> > @@ -86,7 +86,7 @@ void rds_stats_info_copy(struct rds_info_iterator *iter,
> > 
> >  	for (i = 0; i < nr; i++) {
> >  		BUG_ON(strlen(names[i]) >= sizeof(ctr.name));
> > -		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
> > +		strlcpy(ctr.name, names[i], sizeof(ctr.name));
> >  		ctr.value = values[i];
> > 
> 
> If the target buffer ends up being copied to userspace that
> might lead to random kernel memory being leaked.

Seems it is.  The last byte of 'name' is not currently initialised and
therefore is already leaked to userland.

But it's OK because rds_info_copy() uses memcpy() not __copy_to_user(),
so SMAP will block this leak. :-)

Ben.
Ben Hutchings March 4, 2013, 6:34 p.m. UTC | #4
On Mon, 2013-03-04 at 18:32 +0000, Ben Hutchings wrote:
> On Thu, 2013-02-28 at 09:36 +0000, David Laight wrote:
> > >   when src strlen is sizeof(ctr.name) - 1, the dest str is not '\0' end.
> > >   better use strlcpy instead.
> > > 
> > > Signed-off-by: Chen Gang <gang.chen@asianux.com>
> > > ---
> > >  net/rds/stats.c |    2 +-
> > >  1 files changed, 1 insertions(+), 1 deletions(-)
> > > 
> > > diff --git a/net/rds/stats.c b/net/rds/stats.c
> > > index 7be790d..b9ac1df 100644
> > > --- a/net/rds/stats.c
> > > +++ b/net/rds/stats.c
> > > @@ -86,7 +86,7 @@ void rds_stats_info_copy(struct rds_info_iterator *iter,
> > > 
> > >  	for (i = 0; i < nr; i++) {
> > >  		BUG_ON(strlen(names[i]) >= sizeof(ctr.name));
> > > -		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
> > > +		strlcpy(ctr.name, names[i], sizeof(ctr.name));
> > >  		ctr.value = values[i];
> > > 
> > 
> > If the target buffer ends up being copied to userspace that
> > might lead to random kernel memory being leaked.
> 
> Seems it is.  The last byte of 'name' is not currently initialised and
> therefore is already leaked to userland.
> 
> But it's OK because rds_info_copy() uses memcpy() not __copy_to_user(),
> so SMAP will block this leak. :-)

Or not, as kmap() presumably evades that.

Ben.
Chen Gang March 5, 2013, 2:32 a.m. UTC | #5
于 2013年03月05日 02:34, Ben Hutchings 写道:
> On Mon, 2013-03-04 at 18:32 +0000, Ben Hutchings wrote:
>> > On Thu, 2013-02-28 at 09:36 +0000, David Laight wrote:
>>> > > 
>>> > > If the target buffer ends up being copied to userspace that
>>> > > might lead to random kernel memory being leaked.
>> > 
>> > Seems it is.  The last byte of 'name' is not currently initialised and
>> > therefore is already leaked to userland.
>> > 
>> > But it's OK because rds_info_copy() uses memcpy() not __copy_to_user(),
>> > so SMAP will block this leak. :-)
> Or not, as kmap() presumably evades that.

 is this patch ok, or need improving ?

BTW:
  excuse me, maybe my reply will be late during this week.
  the reason:
    my father had a serious heart disease, and is in hospital.
    during these days, most of my time has to be in hospital.
      (God Bless, and thank Jesus Christ, my father is safe, now).
    within my company (Asianux), I also have something to do.


 :-)
Ben Hutchings March 5, 2013, 3:16 a.m. UTC | #6
On Tue, 2013-03-05 at 10:32 +0800, Chen Gang wrote:
> 于 2013年03月05日 02:34, Ben Hutchings 写道:
> > On Mon, 2013-03-04 at 18:32 +0000, Ben Hutchings wrote:
> >> > On Thu, 2013-02-28 at 09:36 +0000, David Laight wrote:
> >>> > > 
> >>> > > If the target buffer ends up being copied to userspace that
> >>> > > might lead to random kernel memory being leaked.
> >> > 
> >> > Seems it is.  The last byte of 'name' is not currently initialised and
> >> > therefore is already leaked to userland.
> >> > 
> >> > But it's OK because rds_info_copy() uses memcpy() not __copy_to_user(),
> >> > so SMAP will block this leak. :-)
> > Or not, as kmap() presumably evades that.
> 
>  is this patch ok, or need improving ?

I think it is wrong, and the code should be changed to do either:

1. Zero-initialise the whole of the name, then use strlcpy().
2. Keep using strncpy(), and also set the last byte of name to 0.

> BTW:
>   excuse me, maybe my reply will be late during this week.
>   the reason:
>     my father had a serious heart disease, and is in hospital.
>     during these days, most of my time has to be in hospital.
>       (God Bless, and thank Jesus Christ, my father is safe, now).
>     within my company (Asianux), I also have something to do.

Best wishes to you both.

Ben.
Chen Gang March 5, 2013, 3:32 a.m. UTC | #7
于 2013年03月05日 11:16, Ben Hutchings 写道:
> I think it is wrong, and the code should be changed to do either:
> 
> 1. Zero-initialise the whole of the name, then use strlcpy().
> 2. Keep using strncpy(), and also set the last byte of name to 0.
> 

  I think what I have done is just like your choice "2."
  for me, I think they are equal:

-		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
+		strlcpy(ctr.name, names[i], sizeof(ctr.name));


		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
+ 		ctr.name[sizeof(ctr.name) - 1] = '\0';



>> > BTW:
>> >   excuse me, maybe my reply will be late during this week.
>> >   the reason:
>> >     my father had a serious heart disease, and is in hospital.
>> >     during these days, most of my time has to be in hospital.
>> >       (God Bless, and thank Jesus Christ, my father is safe, now).
>> >     within my company (Asianux), I also have something to do.
> Best wishes to you both.

  thank you.

  :-)
Ben Hutchings March 5, 2013, 3:37 a.m. UTC | #8
On Tue, 2013-03-05 at 11:32 +0800, Chen Gang wrote:
> 于 2013年03月05日 11:16, Ben Hutchings 写道:
> > I think it is wrong, and the code should be changed to do either:
> > 
> > 1. Zero-initialise the whole of the name, then use strlcpy().
> > 2. Keep using strncpy(), and also set the last byte of name to 0.
> > 
> 
>   I think what I have done is just like your choice "2."
>   for me, I think they are equal:
> 
> -		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
> +		strlcpy(ctr.name, names[i], sizeof(ctr.name));
> 
> 
> 		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
> + 		ctr.name[sizeof(ctr.name) - 1] = '\0';

They are not.  strncpy() pads with zeroes to the end of the given buffer
whereas strlcpy() adds only a single zero byte (and truncates if
necessary to fit the zero byte).

Ben.
Chen Gang March 5, 2013, 4:09 a.m. UTC | #9
于 2013年03月05日 11:37, Ben Hutchings 写道:
>>   I think what I have done is just like your choice "2."
>> >   for me, I think they are equal:
>> > 
>> > -		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
>> > +		strlcpy(ctr.name, names[i], sizeof(ctr.name));
>> > 
>> > 
>> > 		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
>> > + 		ctr.name[sizeof(ctr.name) - 1] = '\0';
> They are not.  strncpy() pads with zeroes to the end of the given buffer
> whereas strlcpy() adds only a single zero byte (and truncates if
> necessary to fit the zero byte).

  ok, thank you. they are really not the same (originally, I did not
notice it)

  could you supply the reason:
    why need we zero all of ctr.name ?
    (for me, I think, keeping ctr.name just a zero-based string is ok)

  thanks.

  :-)
Ben Hutchings March 5, 2013, 5 p.m. UTC | #10
On Tue, 2013-03-05 at 12:09 +0800, Chen Gang wrote:
> 于 2013年03月05日 11:37, Ben Hutchings 写道:
> >>   I think what I have done is just like your choice "2."
> >> >   for me, I think they are equal:
> >> > 
> >> > -		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
> >> > +		strlcpy(ctr.name, names[i], sizeof(ctr.name));
> >> > 
> >> > 
> >> > 		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
> >> > + 		ctr.name[sizeof(ctr.name) - 1] = '\0';
> > They are not.  strncpy() pads with zeroes to the end of the given buffer
> > whereas strlcpy() adds only a single zero byte (and truncates if
> > necessary to fit the zero byte).
> 
>   ok, thank you. they are really not the same (originally, I did not
> notice it)
> 
>   could you supply the reason:
>     why need we zero all of ctr.name ?
>     (for me, I think, keeping ctr.name just a zero-based string is ok)

This function calls rds_copy_info() to copy the whole of ctr into
userland.

If ctr is not completely initialised, then the values of the
uninitialised bytes are left over from the local variables of an earlier
system call.  If an attacker knows enough about the stack layout (easy
if this is a distribution kernel), they can make a series of system
calls that leak information about heap-allocated objects.  That can help
them to exploit other kernel bugs for privilege escalation.  So we
should initialise every bit of memory that is going to be copied to
userland.

(In fact, in general it's not even enough to initialise all fields of
the structure, because there may be padding bytes between them.  In this
case we know there isn't, because it's declared as packed.)

Ben.
Chen Gang March 7, 2013, 4:03 a.m. UTC | #11
于 2013年03月06日 01:00, Ben Hutchings 写道:
> This function calls rds_copy_info() to copy the whole of ctr into
> userland.
> 
> If ctr is not completely initialised, then the values of the
> uninitialised bytes are left over from the local variables of an earlier
> system call.  If an attacker knows enough about the stack layout (easy
> if this is a distribution kernel), they can make a series of system
> calls that leak information about heap-allocated objects.  That can help
> them to exploit other kernel bugs for privilege escalation.  So we
> should initialise every bit of memory that is going to be copied to
> userland.
> 
> (In fact, in general it's not even enough to initialise all fields of
> the structure, because there may be padding bytes between them.  In this
> case we know there isn't, because it's declared as packed.)
> 
> Ben.

  thank you for your information.

  I should send patch v2 for it.

  :-)
diff mbox

Patch

diff --git a/net/rds/stats.c b/net/rds/stats.c
index 7be790d..b9ac1df 100644
--- a/net/rds/stats.c
+++ b/net/rds/stats.c
@@ -86,7 +86,7 @@  void rds_stats_info_copy(struct rds_info_iterator *iter,
 
 	for (i = 0; i < nr; i++) {
 		BUG_ON(strlen(names[i]) >= sizeof(ctr.name));
-		strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
+		strlcpy(ctr.name, names[i], sizeof(ctr.name));
 		ctr.value = values[i];
 
 		rds_info_copy(iter, &ctr, sizeof(ctr));