linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
@ 2015-04-28  3:48 Al Viro
  2015-04-28  5:35 ` Fabian Frederick
  0 siblings, 1 reply; 35+ messages in thread
From: Al Viro @ 2015-04-28  3:48 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Fabian Frederick, linux-kernel

commit 39d7a29f867bd5a4a551fad6bb3812ceddb0bce1
Author: Fabian Frederick <fabf@skynet.be>
Date:   Fri Jun 6 14:36:15 2014 -0700

    fs/befs/linuxvfs.c: replace strncpy by strlcpy
    
    strncpy + end of string assignment replaced by strlcpy

replaces perfectly safe code with undefined behaviour.  All in the name
of "security hardening", presumably.  Folks, seeing the words "designed to be
safer, more consistent, and less error prone replacement" in a manpage does
*NOT* mean "OK, quit reading it - no need to go further, not even to the end
of the paragraph".  Because in the end of that paragraph it says "This means
that for strlcpy() src must be NUL-terminated".  And sure enough, our
implementation relies on that - it starts with strlen().

strncpy() is guaranteed not to look further than size.  strlcpy() is *NOT*.
strncpy() on unvalidated source is safe, provided that you sanitize the copy;
strlcpy() on anything like that is an invitation for nasal daemons.

Sure, we can (and probably should) make strlcpy(dst, src, n) never access
memory beyond src + n - 1, but this kind of cargo-culting is a Bad Thing(tm);
mindless "security improvements" without so much as bothering to RTFM are
asking for trouble.  And in userland code anything like that _can't_ be
papered over afterwards - not unless you can patch every libc implementation
out there.

This particular code is completely pointless - if anything, it should've been
memcpy() + nd_terminate_link()...

Al, very unhappy about the prospect of looking through ~2000 calls of strlcpy()
we have in the tree...

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28  3:48 revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy" Al Viro
@ 2015-04-28  5:35 ` Fabian Frederick
  2015-04-28 16:05   ` Al Viro
  0 siblings, 1 reply; 35+ messages in thread
From: Fabian Frederick @ 2015-04-28  5:35 UTC (permalink / raw)
  To: Al Viro, Linus Torvalds; +Cc: linux-kernel



> On 28 April 2015 at 05:48 Al Viro <viro@ZenIV.linux.org.uk> wrote:
>
>
> commit 39d7a29f867bd5a4a551fad6bb3812ceddb0bce1
> Author: Fabian Frederick <fabf@skynet.be>
> Date:   Fri Jun 6 14:36:15 2014 -0700
>
>     fs/befs/linuxvfs.c: replace strncpy by strlcpy
>     
>     strncpy + end of string assignment replaced by strlcpy
>
> replaces perfectly safe code with undefined behaviour.  All in the name
> of "security hardening", presumably.  Folks, seeing the words "designed to be
> safer, more consistent, and less error prone replacement" in a manpage does
> *NOT* mean "OK, quit reading it - no need to go further, not even to the end
> of the paragraph".  Because in the end of that paragraph it says "This means
> that for strlcpy() src must be NUL-terminated".  And sure enough, our
> implementation relies on that - it starts with strlen().
>
> strncpy() is guaranteed not to look further than size.  strlcpy() is *NOT*.
> strncpy() on unvalidated source is safe, provided that you sanitize the copy;
> strlcpy() on anything like that is an invitation for nasal daemons.
>
> Sure, we can (and probably should) make strlcpy(dst, src, n) never access
> memory beyond src + n - 1, but this kind of cargo-culting is a Bad Thing(tm);
> mindless "security improvements" without so much as bothering to RTFM are
> asking for trouble.  And in userland code anything like that _can't_ be
> papered over afterwards - not unless you can patch every libc implementation
> out there.
>
> This particular code is completely pointless - if anything, it should've been
> memcpy() + nd_terminate_link()...
>
> Al, very unhappy about the prospect of looking through ~2000 calls of
> strlcpy()
> we have in the tree...

Sorry Al, I thought it was more secure.
I guess the 2 following patches should be reversed as well :

6cb103b6f45a
"fs/befs/btree.c: replace strncpy by strlcpy + coding style fixing"

69201bb11327
"fs/ocfs2/super.c: use OCFS2_MAX_VOL_LABEL_LEN and strlcpy"

Regards,
Fabian

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28  5:35 ` Fabian Frederick
@ 2015-04-28 16:05   ` Al Viro
  2015-04-28 16:42     ` Fabian Frederick
  2015-04-28 16:42     ` Linus Torvalds
  0 siblings, 2 replies; 35+ messages in thread
From: Al Viro @ 2015-04-28 16:05 UTC (permalink / raw)
  To: Fabian Frederick; +Cc: Linus Torvalds, linux-kernel

On Tue, Apr 28, 2015 at 07:35:10AM +0200, Fabian Frederick wrote:

> > Al, very unhappy about the prospect of looking through ~2000 calls of
> > strlcpy()
> > we have in the tree...
> 
> Sorry Al, I thought it was more secure.

It's not just you, unfortunately, and dumping all that annoyance on you
as a proxy for everyone who does that kind of thing had been unfair.
My apologies...

> I guess the 2 following patches should be reversed as well :
> 
> 6cb103b6f45a
> "fs/befs/btree.c: replace strncpy by strlcpy + coding style fixing"
> 
> 69201bb11327
> "fs/ocfs2/super.c: use OCFS2_MAX_VOL_LABEL_LEN and strlcpy"

AFAICS, they should.

Unfortunately, we _can't_ make strlcpy() never look past src + size - 1 -
not without changing its semantics.  Its callers expect it to return
the length of source; one of the intended uses is
	wanted = strlcpy(dst, src, dst_size);
	if (wanted >= dst_size) {
		p = realloc(dst, wanted + 1);
		if (!p) {
			// too bad
		} else {
			dst = p;
			memcpy(dst, src, wanted + 1);
		}
	}
and that really wants the accurate length.  Now, the absolute majority of
strlcpy() users in the kernel completely ignore the return value, i.e. go for
silent truncation.  About 1% do not.

Out of those, some are correctly implemented "fail if truncated" uses.
The rest...  Some are weirdly open-coded snprintf() (series of strlcpy and
strlcat) and some are _very_ dubious.  Either they really never get
truncated, or we have a problem.  For example, this
kernel/module.c:2349:			s += strlcpy(s, &mod->strtab[src[i].st_name],
smells really bad.  We are truncating a bunch of strings dowsn to KSYM_NAME_LEN
there and storing them in a buffer, with spacing that matches _untruncated_
strings.

drivers/s390/scsi/zfcp_fc.c:825:	len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
also looks fishy - what happens there is
        len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
                      FC_SYMBOLIC_NAME_SIZE);
        rspn_req->rspn.fr_name_len = len;

drivers/usb/gadget/function/f_midi.c:976:	result = strlcpy(page, opts->id, PAGE_SIZE);
drivers/usb/gadget/function/f_printer.c:1172:	result = strlcpy(page, opts->pnp_string + 2, PNP_STRING_LEN - 2);
drivers/usb/gadget/function/f_printer.c:1184:	result = strlcpy(opts->pnp_string + 2, page, PNP_STRING_LEN - 2);

are also strange...

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 16:05   ` Al Viro
@ 2015-04-28 16:42     ` Fabian Frederick
  2015-04-28 17:39       ` Al Viro
  2015-04-28 16:42     ` Linus Torvalds
  1 sibling, 1 reply; 35+ messages in thread
From: Fabian Frederick @ 2015-04-28 16:42 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-kernel, Linus Torvalds



> On 28 April 2015 at 18:05 Al Viro <viro@ZenIV.linux.org.uk> wrote:
>
>
> On Tue, Apr 28, 2015 at 07:35:10AM +0200, Fabian Frederick wrote:
>
> > > Al, very unhappy about the prospect of looking through ~2000 calls of
> > > strlcpy()
> > > we have in the tree...
> >
> > Sorry Al, I thought it was more secure.
>
> It's not just you, unfortunately, and dumping all that annoyance on you
> as a proxy for everyone who does that kind of thing had been unfair.
> My apologies...

No problem Al :) but why can't we harden strlcpy at first with
something like a strlen limited to max char.
(I don't know if it's already in kernel libs).

size_t strlenl(const char *s, size_t maxlen)
{
        const char *sc = s;
        size_t i = 0;

        while (*sc != '\0' && (i < maxlen)) {
                i++;
                sc++;
        }
        return sc - s;
}

Then we could solve problems downstream ...

Regards,
Fabian

>
> > I guess the 2 following patches should be reversed as well :
> >
> > 6cb103b6f45a
> > "fs/befs/btree.c: replace strncpy by strlcpy + coding style fixing"
> >
> > 69201bb11327
> > "fs/ocfs2/super.c: use OCFS2_MAX_VOL_LABEL_LEN and strlcpy"
>
> AFAICS, they should.
>
> Unfortunately, we _can't_ make strlcpy() never look past src + size - 1 -
> not without changing its semantics.  Its callers expect it to return
> the length of source; one of the intended uses is
>       wanted = strlcpy(dst, src, dst_size);
>       if (wanted >= dst_size) {
>               p = realloc(dst, wanted + 1);
>               if (!p) {
>                       // too bad
>               } else {
>                       dst = p;
>                       memcpy(dst, src, wanted + 1);
>               }
>       }
> and that really wants the accurate length.  Now, the absolute majority of
> strlcpy() users in the kernel completely ignore the return value, i.e. go for
> silent truncation.  About 1% do not.
>
> Out of those, some are correctly implemented "fail if truncated" uses.
> The rest...  Some are weirdly open-coded snprintf() (series of strlcpy and
> strlcat) and some are _very_ dubious.  Either they really never get
> truncated, or we have a problem.  For example, this
> kernel/module.c:2349:                 s += strlcpy(s,
> &mod->strtab[src[i].st_name],
> smells really bad.  We are truncating a bunch of strings dowsn to
> KSYM_NAME_LEN
> there and storing them in a buffer, with spacing that matches _untruncated_
> strings.
>
> drivers/s390/scsi/zfcp_fc.c:825:      len = strlcpy(rspn_req->rspn.fr_name,
> fc_host_symbolic_name(shost),
> also looks fishy - what happens there is
>         len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
>                       FC_SYMBOLIC_NAME_SIZE);
>         rspn_req->rspn.fr_name_len = len;
>
> drivers/usb/gadget/function/f_midi.c:976:     result = strlcpy(page, opts->id,
> PAGE_SIZE);
> drivers/usb/gadget/function/f_printer.c:1172: result = strlcpy(page,
> opts->pnp_string + 2, PNP_STRING_LEN - 2);
> drivers/usb/gadget/function/f_printer.c:1184: result =
> strlcpy(opts->pnp_string + 2, page, PNP_STRING_LEN - 2);
>
> are also strange...

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 16:05   ` Al Viro
  2015-04-28 16:42     ` Fabian Frederick
@ 2015-04-28 16:42     ` Linus Torvalds
  2015-04-28 19:48       ` Chris Metcalf
  1 sibling, 1 reply; 35+ messages in thread
From: Linus Torvalds @ 2015-04-28 16:42 UTC (permalink / raw)
  To: Al Viro; +Cc: Fabian Frederick, Linux Kernel Mailing List

On Tue, Apr 28, 2015 at 9:05 AM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> Unfortunately, we _can't_ make strlcpy() never look past src + size - 1 -
> not without changing its semantics.

Yeah, strlcpy is actually nasty. I don't understand why people like it
so much. It's a crap interface, and completely unsuitable for
untrusted sources because of the overrun issue.

Now, strncpy is nasty too, because of the two main flaws:
 - no guaranteed NUL at the end
 - crazy "fill with NUL" at the end

the first of which causes security issues, and the second of which
causes performance issues when you have small strings and size your
buffers generously.

Generally, what we want is "strncpy()" that forces a _single_ NUL at
the end. Basically, what we want is that

     good_strncpy(dst, src, n);
     assert(strlen(dst) < n);

always just works, but it doesn't try to pad the 'dst' to zero.

Alternatively, the return value should be really obvious and
unambiguous. That's what our "strncpy_from_user()" does: it is a but
more complex because it needs to show three cases (ok, too long, and
EFAULT), so the semantics for 'strncpy_from_user() is that you have to
just always check the return value, but at least it's simple:

 - negative means error
 - >= n means "too long"
 - 0..n-1 means "ok" and is the size of the string.

for a normal in-kernel strncpy(), we'd likely be better off just
returing "we truncated" as an error.

Then you could just do

    mystrncpy(dst, src, sizeof(dst));

and the result would be a valid string (possibly truncated), and if
you care about truncation you just do

   if (good_strncpy(dst, src, sizeof(dst)) < 0)
       return -ETOOLONG;

both of which are just very *obvious* things, and neither of which
leans a possibly unsafe string in "dst", nor look past the end of
'src'.

Oh well.

I can certainly imagine other more complex forms too (max length of
destination _and_ separately max length of source). But strncpy and
strlcpy are both horrible nasty error-prone crap.

                               Linus

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 16:42     ` Fabian Frederick
@ 2015-04-28 17:39       ` Al Viro
  2015-04-28 20:16         ` Fabian Frederick
  0 siblings, 1 reply; 35+ messages in thread
From: Al Viro @ 2015-04-28 17:39 UTC (permalink / raw)
  To: Fabian Frederick; +Cc: linux-kernel, Linus Torvalds

On Tue, Apr 28, 2015 at 06:42:10PM +0200, Fabian Frederick wrote:
> 
> 
> > On 28 April 2015 at 18:05 Al Viro <viro@ZenIV.linux.org.uk> wrote:
> >
> >
> > On Tue, Apr 28, 2015 at 07:35:10AM +0200, Fabian Frederick wrote:
> >
> > > > Al, very unhappy about the prospect of looking through ~2000 calls of
> > > > strlcpy()
> > > > we have in the tree...
> > >
> > > Sorry Al, I thought it was more secure.
> >
> > It's not just you, unfortunately, and dumping all that annoyance on you
> > as a proxy for everyone who does that kind of thing had been unfair.
> > My apologies...
> 
> No problem Al :) but why can't we harden strlcpy at first with
> something like a strlen limited to max char.
> (I don't know if it's already in kernel libs).
> 
> size_t strlenl(const char *s, size_t maxlen)

aka strnlen()

>         const char *sc = s;
>         size_t i = 0;
> 
>         while (*sc != '\0' && (i < maxlen)) {
>                 i++;
>                 sc++;
>         }
>         return sc - s;
> }
> 
> Then we could solve problems downstream ...

Can't.  Seriously, look what strlcpy() is supposed to return; it's pretty
much a microoptimized snprintf(dst, size, "%s", src).  It's certainly
been patterned after snprintf(3) - "don't exceed that size, NUL-terminate
unless the size is zero, return the number of characters (excluding NUL)
that would've been written if the size had been large enough".

The following is a legitimate use of strlcpy():

int foo(char *);	/* modifies string */

int const_foo(const char *s)
{
	int res;
	char buf[32], *p = buf;
	size_t wanted = strlcpy(buf, sizeof(buf), s);
	if (wanted >= sizeof(buf)) {
		p = malloc(wanted + 1);
		if (!p)
			return -ENOMEM;
		memcpy(p, s, wanted + 1);
	}
	res = foo(p);
	if (p != buf)
		free(p);
	return res;
}

None of the kernel callers are of exactly that form (and most ignore the
return value completely), but if we make that sucker return something
different from what strlcpy(3) would return, we'd damn better _not_ keep
the name; there's enough confusion in that area as it is.

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 16:42     ` Linus Torvalds
@ 2015-04-28 19:48       ` Chris Metcalf
  2015-04-28 20:51         ` Linus Torvalds
  0 siblings, 1 reply; 35+ messages in thread
From: Chris Metcalf @ 2015-04-28 19:48 UTC (permalink / raw)
  To: Linus Torvalds, Al Viro
  Cc: Fabian Frederick, Linux Kernel Mailing List, Randy Dunlap,
	Rickard Strandqvist

On 04/28/2015 12:42 PM, Linus Torvalds wrote:
> On Tue, Apr 28, 2015 at 9:05 AM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>>
>> Unfortunately, we _can't_ make strlcpy() never look past src + size - 1 -
>> not without changing its semantics.
>
> Yeah, strlcpy is actually nasty. I don't understand why people like it
> so much. It's a crap interface, and completely unsuitable for
> untrusted sources because of the overrun issue.

FWIW, I wanted to deal with some strncpy/strlcpy API issues last year
and just put a "strscpy()" function in arch/tile/gxio/mpipe.c,
with a comment saying it might be worth making it global at a later
date, but at the time only the reviewers seemed interested in making
it happen, so I let that possibility die on the vine.

I argue that truncated strings are often pretty nasty, so you don't
want to just silently say "Sure, I made it fit!" but instead make that
be a failure case.  In principle you could keep the return code of
my proposed strscpy() and still do the truncated-string copy, but
I think it's a mistake in almost every case, and if you really want
that semantics, you should be forced to use something harder (e.g.
some combination of explicit strlen and memcpy) so it's clear you
know what you're doing.

commit bceb7efa6a7e656bfaa67b6f54925e7db75bcd52
Author: Chris Metcalf <cmetcalf@tilera.com>
Date:   Tue Sep 2 16:25:22 2014 -0400

     tile gxio: use better string copy primitive

     Both strncpy and strlcpy suffer from the fact that they do
     partial copies of strings into the destination when the target
     buffer is too small.  This is frequently pointless since an
     overflow of the target buffer may make the result invalid.

     strncpy() makes it relatively hard to even detect the error
     condition, and with strlcpy() you have to duplicate the buffer
     size parameter to test to see if the result exceeds it.
     By returning zero in the failure case, we both make testing
     for it easy, and by simply not copying anything in that case,
     we make it mandatory for callers to test the error code.

     To catch lazy programmers who don't check, we also place a NUL at
     the start of the destination buffer (if there is space) to
     ensure that the result is an invalid string.

     At some point it may make sense to promote strscpy() to
     a global platform-independent function, but other than the
     reviewers, no one was interested on LKML, so for now leave
     the strscpy() function as file-static.

     Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
     Reviewed-by: Rickard Strandqvist 
<rickard_strandqvist@spectrumdigital.se>
     Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>


-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 17:39       ` Al Viro
@ 2015-04-28 20:16         ` Fabian Frederick
  0 siblings, 0 replies; 35+ messages in thread
From: Fabian Frederick @ 2015-04-28 20:16 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-kernel, Linus Torvalds



> On 28 April 2015 at 19:39 Al Viro <viro@ZenIV.linux.org.uk> wrote:
>
>
> On Tue, Apr 28, 2015 at 06:42:10PM +0200, Fabian Frederick wrote:
> >
> >
> > > On 28 April 2015 at 18:05 Al Viro <viro@ZenIV.linux.org.uk> wrote:
> > >
> > >
> > > On Tue, Apr 28, 2015 at 07:35:10AM +0200, Fabian Frederick wrote:
> > >
> > > > > Al, very unhappy about the prospect of looking through ~2000 calls of
> > > > > strlcpy()
> > > > > we have in the tree...
> > > >
> > > > Sorry Al, I thought it was more secure.
> > >
> > > It's not just you, unfortunately, and dumping all that annoyance on you
> > > as a proxy for everyone who does that kind of thing had been unfair.
> > > My apologies...
> >
> > No problem Al :) but why can't we harden strlcpy at first with
> > something like a strlen limited to max char.
> > (I don't know if it's already in kernel libs).
> >
> > size_t strlenl(const char *s, size_t maxlen)
>
> aka strnlen()
>
> >         const char *sc = s;
> >         size_t i = 0;
> >
> >         while (*sc != '\0' && (i < maxlen)) {
> >                 i++;
> >                 sc++;
> >         }
> >         return sc - s;
> > }
> >
> > Then we could solve problems downstream ...
>
> Can't.  Seriously, look what strlcpy() is supposed to return; it's pretty
> much a microoptimized snprintf(dst, size, "%s", src).  It's certainly
> been patterned after snprintf(3) - "don't exceed that size, NUL-terminate
> unless the size is zero, return the number of characters (excluding NUL)
> that would've been written if the size had been large enough".
>
> The following is a legitimate use of strlcpy():
>
> int foo(char *);      /* modifies string */
>
> int const_foo(const char *s)
> {
>       int res;
>       char buf[32], *p = buf;
>       size_t wanted = strlcpy(buf, sizeof(buf), s);
>       if (wanted >= sizeof(buf)) {
>               p = malloc(wanted + 1);
>               if (!p)
>                       return -ENOMEM;
>               memcpy(p, s, wanted + 1);
>       }
>       res = foo(p);
>       if (p != buf)
>               free(p);
>       return res;
> }
>
> None of the kernel callers are of exactly that form (and most ignore the
> return value completely), but if we make that sucker return something
> different from what strlcpy(3) would return, we'd damn better _not_ keep
> the name; there's enough confusion in that area as it is.
Of course with another function name. There's no other way to do it ...
strlncpy/strlncat ? :)

Regards,
Fabian

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 19:48       ` Chris Metcalf
@ 2015-04-28 20:51         ` Linus Torvalds
  2015-04-28 21:38           ` Chris Metcalf
  0 siblings, 1 reply; 35+ messages in thread
From: Linus Torvalds @ 2015-04-28 20:51 UTC (permalink / raw)
  To: Chris Metcalf
  Cc: Al Viro, Fabian Frederick, Linux Kernel Mailing List,
	Randy Dunlap, Rickard Strandqvist

On Tue, Apr 28, 2015 at 12:48 PM, Chris Metcalf <cmetcalf@ezchip.com> wrote:
>
> FWIW, I wanted to deal with some strncpy/strlcpy API issues last year
> and just put a "strscpy()" function in arch/tile/gxio/mpipe.c,

So quite frankly, I don't like that one either.

Some people really *do* want truncation, and your strscpy() makes that
impossible.

Also, your strscpy() implementation is actually not thread-safe: it
can return an non-terminated string if the source string isn't stable.
That can certainly be a design issue ("don't do that then"), but it
*can* be a possible source of security issues, so it's a bad idea in
something that is supposed to be secure.

And quite frankly, I think that the *only* valid reason to add another
random string copy function is that you actually get it right. We
don't need yet another half-arsed routine that can be easily misused.
We have too many of those.

                          Linus

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 20:51         ` Linus Torvalds
@ 2015-04-28 21:38           ` Chris Metcalf
  2015-04-28 21:48             ` Linus Torvalds
  0 siblings, 1 reply; 35+ messages in thread
From: Chris Metcalf @ 2015-04-28 21:38 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Al Viro, Fabian Frederick, Linux Kernel Mailing List,
	Randy Dunlap, Rickard Strandqvist

On 04/28/2015 04:51 PM, Linus Torvalds wrote:
> On Tue, Apr 28, 2015 at 12:48 PM, Chris Metcalf <cmetcalf@ezchip.com> wrote:
>> FWIW, I wanted to deal with some strncpy/strlcpy API issues last year
>> and just put a "strscpy()" function in arch/tile/gxio/mpipe.c,
> So quite frankly, I don't like that one either.
>
> Some people really *do* want truncation, and your strscpy() makes that
> impossible.

Perhaps the answer is to provide a strscpy() and a separate
strscpy_truncate() that explicitly enables truncation semantics.
I remain skeptical of providing a handy function with an error
return that people are free to ignore.  If one wants truncating
semantics, one should be obliged to say so.

> Also, your strscpy() implementation is actually not thread-safe: it
> can return an non-terminated string if the source string isn't stable.
> That can certainly be a design issue ("don't do that then"), but it
> *can* be a possible source of security issues, so it's a bad idea in
> something that is supposed to be secure.

To do that we'd probably want to provide a generic version that
just copied byte-by-byte, and encourage architecture variants
that were more efficient.  This would leave it less efficient in
general than strncpy/strlcpy (the former typically has efficient
arch versions already, and the latter, although not thread-safe
by your definition, is built on strlen/memcpy, which typically
have efficient arch versions).

I don't see a way to leverage existing efficient implementations,
since only strncpy likely has pre-existing efficient implementations,
and then we'd have to call strlen() on the destination just to
return the total length (after already calling strnlen() on the
source to figure out how long we thought it was).

I suppose if we want to just return a boolean saying "it fit" or
"it didn't fit" we could leverage strncpy, though if the buffer
changed out from under us to be just a single NUL instead of
a long string, we'd still do the silly NUL-fill behavior.  So maybe
it's not worth the contortions.

> And quite frankly, I think that the *only* valid reason to add another
> random string copy function is that you actually get it right. We
> don't need yet another half-arsed routine that can be easily misused.
> We have too many of those.

For sure.  Something like this untested code in lib/string.c, to be 
concrete?

#ifndef __HAVE_ARCH_STRSCPY
/**
  * strscpy_truncate - Copy a C-string into a sized buffer and return whether it fit
  * @dest: Where to copy the string to
  * @src: Where to copy the string from
  * @count: Size of destination buffer
  *
  * Copy the string, or as much of it as fits, into the dest buffer.
  * The routine returns the total number of bytes copied
  * (including the trailing NUL) or zero if the buffer wasn't
  * big enough.  The dest buffer is always NUL-terminated.
  */
static size_t strscpy_truncate(char *dest, const char *src, size_t count)
{
	char *tmp = dest;

	if (count == 0)
		return 0;  /* no NUL-termination possible */

	while ((*tmp++ = *src++) != '\0') {
		if (--count == 0) {
			*--tmp = '\0';
			return 0;
		}
	}

	return tmp - dest;
}
EXPORT_SYMBOL(strscpy_truncate);

/**
  * strscpy - Copy a C-string into a sized buffer, but only if it fits
  * @dest: Where to copy the string to
  * @src: Where to copy the string from
  * @count: Size of destination buffer
  *
  * Use this routine to avoid copying too-long strings.
  * The routine returns the total number of bytes copied
  * (including the trailing NUL) or zero if the buffer wasn't
  * big enough.  To ensure that programmers pay attention
  * to the return code, the destination has a single NUL
  * written at the front (if count is non-zero) when the
  * buffer is not big enough.
  */
static size_t strscpy(char *dest, const char *src, size_t count)
{
	size_t res = strscpy_truncate(dest, src, count);

	if (res == 0 && count != 0)
		dest[0] = '\0';
	return res;
}
EXPORT_SYMBOL(strscpy);
#endif

-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com


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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 21:38           ` Chris Metcalf
@ 2015-04-28 21:48             ` Linus Torvalds
  2015-04-29  0:35               ` Al Viro
  2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
  0 siblings, 2 replies; 35+ messages in thread
From: Linus Torvalds @ 2015-04-28 21:48 UTC (permalink / raw)
  To: Chris Metcalf
  Cc: Al Viro, Fabian Frederick, Linux Kernel Mailing List,
	Randy Dunlap, Rickard Strandqvist

On Tue, Apr 28, 2015 at 2:38 PM, Chris Metcalf <cmetcalf@ezchip.com> wrote:
>
> To do that we'd probably want to provide a generic version that
> just copied byte-by-byte, and encourage architecture variants
> that were more efficient.

Our generic "strncpy_from_user()" is actually fairly efficient, and
reasonably portable. It almost has to be, since this is actually a
much more common - and much more critical - load than any regular
strncpy I know of in the kernel.

I suspect you could take that lib/strncpy_from_user.c and massage it
reasonably trivially to be a good function.

That said, I can't think of a single strncpy (or strlcpy) in kernel
space that is actually worth even optimizing for. They just don't tend
to be in the critical path. So correctness is likely *much* more
important than worrying about performance.

                           Linus

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-28 21:48             ` Linus Torvalds
@ 2015-04-29  0:35               ` Al Viro
  2015-04-29  8:24                 ` Geert Uytterhoeven
  2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
  1 sibling, 1 reply; 35+ messages in thread
From: Al Viro @ 2015-04-29  0:35 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Fabian Frederick, Linux Kernel Mailing List,
	Randy Dunlap, Rickard Strandqvist

On Tue, Apr 28, 2015 at 02:48:45PM -0700, Linus Torvalds wrote:

> I suspect you could take that lib/strncpy_from_user.c and massage it
> reasonably trivially to be a good function.
> 
> That said, I can't think of a single strncpy (or strlcpy) in kernel
> space that is actually worth even optimizing for. They just don't tend
> to be in the critical path. So correctness is likely *much* more
> important than worrying about performance.

Indeed.  As it is, I suspect that strlcpy() use should be uniformly
discouraged; if nothing else, snprintf() gives the same semantics,
is less likely to cause confusion regardling the expected return
value and none of those paths are performance-critical.

strncpy() has another use, though, and it can't be replaced by strlcpy() -
see the commits that had started this thread.  IMO they (and anything
else of the same nature) really need to be reverted; using strlcpy() on
something that isn't guaranteed to be NUL-terminated is a serious bug.

And catching all such places is going to be quite a work - there are too
many strlcpy() callers out there.

Frankly, looking through call sites in fs...
* two callers in fs/9p - strlcpy() + sscanf(), both should've been
plain sscanf() (and the second should've been "HARDLINKCOUNT%u" instead
of "%13s %u" + comparison of string with "HARDLINKCOUNT" - sscanf() is
quite capable of matching explicit string literals)
* affs one: match_strdup + strlcpy + kfree.  Should just use match_strlcpy
instead (BTW, despite the name, it does *not* use strclpy() internally).
* afs: might be correct.
* two in befs: both broken.
* binfmt_misc: fishy; load_misc_binary() finds an object under rwlock, copies
one of its fields (->interpreter), drops rwlock and proceeds to do various
blocking operations (including open_exec()).  Using another field of the
same object (->interp_flags) all along.  If it gets freed and reused, well...
let's hope we won't fuck up too badly.  IMO we'd be better off if we added
a refcount to that sucker and used it to control the freeing.
* btrfs: undefined behaviour - potentially overlapping source and destination.
* another btrfs one:
                char b[BDEVNAME_SIZE];
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
complete garbage; might as well do bdevname(bdev, s->s_id) and be done with
that.

... and so on; this stuff is misused more often than not.

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

* Re: revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy"
  2015-04-29  0:35               ` Al Viro
@ 2015-04-29  8:24                 ` Geert Uytterhoeven
  0 siblings, 0 replies; 35+ messages in thread
From: Geert Uytterhoeven @ 2015-04-29  8:24 UTC (permalink / raw)
  To: Al Viro
  Cc: Linus Torvalds, Chris Metcalf, Fabian Frederick,
	Linux Kernel Mailing List, Randy Dunlap, Rickard Strandqvist

On Wed, Apr 29, 2015 at 2:35 AM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> strncpy() has another use, though, and it can't be replaced by strlcpy() -
> see the commits that had started this thread.  IMO they (and anything
> else of the same nature) really need to be reverted; using strlcpy() on
> something that isn't guaranteed to be NUL-terminated is a serious bug.

To be honest, I never considered the "source is not NUL-terminated" case.
Strings in C (if they are strings, and not "buffers"; with buffers you
should know how many bytes are valid anyway) are always terminated ;-)

The other case we sometimes do want strncpy() for is the "crazy "fill with
NUL" at the end" feature, to avoid leaking sensitive data. The alternative
is to clear the target first, or the remainder afterwards.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* [PATCH 0/3] add new strscpy() API for string copy
  2015-04-28 21:48             ` Linus Torvalds
  2015-04-29  0:35               ` Al Viro
@ 2015-04-30 16:01               ` Chris Metcalf
  2015-04-30 16:01                 ` [PATCH 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
                                   ` (4 more replies)
  1 sibling, 5 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-04-30 16:01 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

This patch series addresses limitations in strncpy() and strlcpy();
both the old APIs are unpleasant, as Linus nicely summarized here
a couple of days ago:

  https://lkml.org/lkml/2015/4/28/570

and of course as other folks (Greg K-H and Linus again) said last year:

  https://plus.google.com/+gregkroahhartman/posts/1amLbuhWbh5

The proposed new API (strscpy(), for "s"afe string copy) has an
easy-to-use API for detecting buffer overflow, avoids unsafe truncation
by default, and isn't subject to thread-safety attacks like the current
strlcpy implementation.  See patch 2/3 for more on why strscpy() is a
good thing.

To make strscpy() work more efficiently I did the minimum tweaking
necessary to allow <asm/word-at-a-time.h> to work on all architectures,
though of course individual maintainers can still make their versions
more efficient as needed.

It's likely not necessary for per-architecture implementations of
strscpy() to be written, but I stuck with the standard __HAVE_ARCH_XXX
model just for consistency with the rest of <linux/string.h>.

I tested the implementation with a simple user-space harness, so I
believe it is correct for the corner cases I could think of.  In
particular I pairwise-tested all the unaligned values of source and
dest, and tested the restriction on src page-crossing at all
unaligned offsets approaching the page boundary.

This builds on an earlier version of strscpy() submitted as
a file-static method in the arch/tile/gxio tree last year, after
an attempt to gather interest in a new generic strscpy failed:

  https://lkml.org/lkml/2014/8/7/368

The patch series is available to be pulled from

  git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git strscpy

Chris Metcalf (3):
  Make asm/word-at-a-time.h available on all architectures
  string: provide strscpy() and strscpy_truncate()
  tile: use global strscpy() rather than private copy

 arch/arc/include/asm/Kbuild          |   1 +
 arch/avr32/include/asm/Kbuild        |   1 +
 arch/blackfin/include/asm/Kbuild     |   1 +
 arch/c6x/include/asm/Kbuild          |   1 +
 arch/cris/include/asm/Kbuild         |   1 +
 arch/frv/include/asm/Kbuild          |   1 +
 arch/hexagon/include/asm/Kbuild      |   1 +
 arch/ia64/include/asm/Kbuild         |   1 +
 arch/m32r/include/asm/Kbuild         |   1 +
 arch/metag/include/asm/Kbuild        |   1 +
 arch/microblaze/include/asm/Kbuild   |   1 +
 arch/mips/include/asm/Kbuild         |   1 +
 arch/mn10300/include/asm/Kbuild      |   1 +
 arch/nios2/include/asm/Kbuild        |   1 +
 arch/powerpc/include/asm/Kbuild      |   1 +
 arch/s390/include/asm/Kbuild         |   1 +
 arch/score/include/asm/Kbuild        |   1 +
 arch/tile/gxio/mpipe.c               |  33 ++---------
 arch/tile/include/asm/Kbuild         |   1 +
 arch/um/include/asm/Kbuild           |   1 +
 arch/unicore32/include/asm/Kbuild    |   1 +
 arch/xtensa/include/asm/Kbuild       |   1 +
 include/asm-generic/word-at-a-time.h |  80 ++++++++++++++++++++++---
 include/linux/string.h               |   6 ++
 lib/string.c                         | 109 +++++++++++++++++++++++++++++++++++
 25 files changed, 212 insertions(+), 37 deletions(-)

-- 
2.1.2


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

* [PATCH 1/3] Make asm/word-at-a-time.h available on all architectures
  2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
@ 2015-04-30 16:01                 ` Chris Metcalf
  2015-04-30 16:01                 ` [PATCH 2/3] string: provide strscpy() and strscpy_truncate() Chris Metcalf
                                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-04-30 16:01 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

Added the x86 implementation of word-at-a-time to the
generic version, which previously only supported big-endian.

Omitted the x86-specific load_unaligned_zeropad(), which in
any case is also not present for the existing BE-only
implementation of a word-at-a-time, and is only used under
CONFIG_DCACHE_WORD_ACCESS.

Added as a "generic-y" to the Kbuilds of all architectures
that didn't previously have it.

Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
---
 arch/arc/include/asm/Kbuild          |  1 +
 arch/avr32/include/asm/Kbuild        |  1 +
 arch/blackfin/include/asm/Kbuild     |  1 +
 arch/c6x/include/asm/Kbuild          |  1 +
 arch/cris/include/asm/Kbuild         |  1 +
 arch/frv/include/asm/Kbuild          |  1 +
 arch/hexagon/include/asm/Kbuild      |  1 +
 arch/ia64/include/asm/Kbuild         |  1 +
 arch/m32r/include/asm/Kbuild         |  1 +
 arch/metag/include/asm/Kbuild        |  1 +
 arch/microblaze/include/asm/Kbuild   |  1 +
 arch/mips/include/asm/Kbuild         |  1 +
 arch/mn10300/include/asm/Kbuild      |  1 +
 arch/nios2/include/asm/Kbuild        |  1 +
 arch/powerpc/include/asm/Kbuild      |  1 +
 arch/s390/include/asm/Kbuild         |  1 +
 arch/score/include/asm/Kbuild        |  1 +
 arch/tile/include/asm/Kbuild         |  1 +
 arch/um/include/asm/Kbuild           |  1 +
 arch/unicore32/include/asm/Kbuild    |  1 +
 arch/xtensa/include/asm/Kbuild       |  1 +
 include/asm-generic/word-at-a-time.h | 80 ++++++++++++++++++++++++++++++++----
 22 files changed, 93 insertions(+), 8 deletions(-)

diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index be0c39e76f7c..be895ef03a51 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -49,4 +49,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild
index 528d70d47a54..10dd6e8470bd 100644
--- a/arch/avr32/include/asm/Kbuild
+++ b/arch/avr32/include/asm/Kbuild
@@ -20,4 +20,5 @@ generic-y += sections.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/blackfin/include/asm/Kbuild b/arch/blackfin/include/asm/Kbuild
index 4bd3c3cfc9ab..9705a527b7b0 100644
--- a/arch/blackfin/include/asm/Kbuild
+++ b/arch/blackfin/include/asm/Kbuild
@@ -46,4 +46,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index ae0a51f5376c..535efdb0692d 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -59,4 +59,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index 057e51859b0a..4991539a25f6 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -26,4 +26,5 @@ generic-y += sections.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/frv/include/asm/Kbuild b/arch/frv/include/asm/Kbuild
index e3f81b53578e..ca34d1cf2cdf 100644
--- a/arch/frv/include/asm/Kbuild
+++ b/arch/frv/include/asm/Kbuild
@@ -7,3 +7,4 @@ generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild
index c7a99f860b40..872920fba0a6 100644
--- a/arch/hexagon/include/asm/Kbuild
+++ b/arch/hexagon/include/asm/Kbuild
@@ -58,4 +58,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 9b41b4bcc073..614579fa1e49 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -8,3 +8,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
 generic-y += vtime.h
+generic-y += word-at-a-time.h
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index 2edc793372fc..36f850dd4a1e 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -9,3 +9,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/metag/include/asm/Kbuild b/arch/metag/include/asm/Kbuild
index 0bf5d525b945..a291b3b2529e 100644
--- a/arch/metag/include/asm/Kbuild
+++ b/arch/metag/include/asm/Kbuild
@@ -54,4 +54,5 @@ generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index ab564a6db5c3..966f221b2d67 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -10,3 +10,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += syscalls.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 526539cbc99f..c3cfb83aca1d 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -18,4 +18,5 @@ generic-y += serial.h
 generic-y += trace_clock.h
 generic-y += ucontext.h
 generic-y += user.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/mn10300/include/asm/Kbuild b/arch/mn10300/include/asm/Kbuild
index f892d9de47d9..30a06e2d6e42 100644
--- a/arch/mn10300/include/asm/Kbuild
+++ b/arch/mn10300/include/asm/Kbuild
@@ -9,3 +9,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild
index 24b3d8999ac7..bc87081c0669 100644
--- a/arch/nios2/include/asm/Kbuild
+++ b/arch/nios2/include/asm/Kbuild
@@ -61,4 +61,5 @@ generic-y += types.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 4b87205c230c..dfc61a151890 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -9,3 +9,4 @@ generic-y += rwsem.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
 generic-y += vtime.h
+generic-y += word-at-a-time.h
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index c631f98fd524..27c37b3d1dad 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -6,3 +6,4 @@ generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/score/include/asm/Kbuild b/arch/score/include/asm/Kbuild
index 83ed116d414c..16958f529aa7 100644
--- a/arch/score/include/asm/Kbuild
+++ b/arch/score/include/asm/Kbuild
@@ -13,3 +13,4 @@ generic-y += sections.h
 generic-y += trace_clock.h
 generic-y += xor.h
 generic-y += serial.h
+generic-y += word-at-a-time.h
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index f5433e0e34e0..0804122e579a 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -39,4 +39,5 @@ generic-y += termbits.h
 generic-y += termios.h
 generic-y += trace_clock.h
 generic-y += types.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild
index 9176fa11d49b..ee02364d8922 100644
--- a/arch/um/include/asm/Kbuild
+++ b/arch/um/include/asm/Kbuild
@@ -26,4 +26,5 @@ generic-y += sections.h
 generic-y += switch_to.h
 generic-y += topology.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index 3e0c19d0f4c5..f456bfa1dd54 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -62,4 +62,5 @@ generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index 86a9ab2e2ca9..6ac0a9ab3ea3 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -29,4 +29,5 @@ generic-y += statfs.h
 generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
index 94f9ea8abcae..011dde083f23 100644
--- a/include/asm-generic/word-at-a-time.h
+++ b/include/asm-generic/word-at-a-time.h
@@ -1,15 +1,10 @@
 #ifndef _ASM_WORD_AT_A_TIME_H
 #define _ASM_WORD_AT_A_TIME_H
 
-/*
- * This says "generic", but it's actually big-endian only.
- * Little-endian can use more efficient versions of these
- * interfaces, see for example
- *	 arch/x86/include/asm/word-at-a-time.h
- * for those.
- */
-
 #include <linux/kernel.h>
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
 
 struct word_at_a_time {
 	const unsigned long high_bits, low_bits;
@@ -53,4 +48,73 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
 #define zero_bytemask(mask) (~1ul << __fls(mask))
 #endif
 
+#else
+
+/*
+ * The optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+struct word_at_a_time {
+	const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+	return mask*0x0001020304050608ul >> 56;
+}
+
+#else	/* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+	/* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+	long a = (0x0ff0001+mask) >> 23;
+	/* Fix the 1 for 00 case */
+	return a & mask;
+}
+
+#endif
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+	unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+	*bits = mask;
+	return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+	return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+	bits = (bits - 1) & ~bits;
+	return bits >> 7;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+	return count_masked_bytes(mask);
+}
+
+#endif /* __BIG_ENDIAN */
+
 #endif /* _ASM_WORD_AT_A_TIME_H */
-- 
2.1.2


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

* [PATCH 2/3] string: provide strscpy() and strscpy_truncate()
  2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
  2015-04-30 16:01                 ` [PATCH 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
@ 2015-04-30 16:01                 ` Chris Metcalf
  2015-05-06 15:01                   ` Dan Carpenter
  2015-04-30 16:01                 ` [PATCH 3/3] tile: use global strscpy() rather than private copy Chris Metcalf
                                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 35+ messages in thread
From: Chris Metcalf @ 2015-04-30 16:01 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

The strscpy() API is intended to be used instead of strlcpy(),
and instead of most uses of strncpy().

- The API provides an easy way to check for destination buffer overflow:
  a -E2BIG error return value.

- By default, truncation causes the destination buffer to be the
  empty string, so users don't blindly assume a truncated string is
  valid.  If you know a truncated string still has valid semantics,
  you can use the provided strscpy_truncate(), which has the same
  return value semantics but does not make the destination an empty
  string on error.

- The provided implementation is robust in the face of the source
  buffer being asynchronously changed during the copy, unlike the
  current implementation of strlcpy().

- The implementation should be reasonably performant on all
  platforms since it uses the asm/word-at-a-time.h API rather than
  simple byte copy.  Kernel-to-kernel string copy is not considered
  to be performance critical in any case.

- If the remainder of the destination buffer must be zeroed for some
  reason, strscpy() + error check + memset() is probably the easiest
  pattern, but using strncpy() in a pattern where the last byte of
  the buffer is first set non-NUL, then tested for NUL afterwards,
  can also be safely used.

Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
---
 include/linux/string.h |   6 +++
 lib/string.c           | 109 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index e40099e585c9..7942944f3abb 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -25,6 +25,12 @@ extern char * strncpy(char *,const char *, __kernel_size_t);
 #ifndef __HAVE_ARCH_STRLCPY
 size_t strlcpy(char *, const char *, size_t);
 #endif
+#ifndef __HAVE_ARCH_STRSCPY
+ssize_t strscpy(char *, const char *, size_t);
+#endif
+#ifndef __HAVE_ARCH_STRSCPY_TRUNCATE
+ssize_t strscpy_truncate(char *, const char *, size_t);
+#endif
 #ifndef __HAVE_ARCH_STRCAT
 extern char * strcat(char *, const char *);
 #endif
diff --git a/lib/string.c b/lib/string.c
index a5792019193c..84d5b6eceb74 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -27,6 +27,9 @@
 #include <linux/bug.h>
 #include <linux/errno.h>
 
+#include <asm/byteorder.h>
+#include <asm/word-at-a-time.h>
+
 #ifndef __HAVE_ARCH_STRNCASECMP
 /**
  * strncasecmp - Case insensitive, length-limited string comparison
@@ -146,6 +149,112 @@ size_t strlcpy(char *dest, const char *src, size_t size)
 EXPORT_SYMBOL(strlcpy);
 #endif
 
+#ifndef __HAVE_ARCH_STRSCPY_TRUNCATE
+/**
+ * strscpy_truncate - Copy a C-string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: Size of destination buffer
+ *
+ * Copy the string, or as much of it as fits, into the dest buffer.
+ * The routine returns the number of characters copied (not including
+ * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough.
+ * The behavior is undefined if the string buffers overlap.
+ *
+ * Note that the implementation is robust to the string changing out
+ * from underneath it, unlike the current strlcpy() implementation,
+ * and it is easier to check overflow than with strlcpy()'s API.
+ *
+ * strscpy() is preferred over this function unless a truncated string
+ * provides some valid semantics in the destination buffer.
+ */
+ssize_t strscpy_truncate(char *dest, const char *src, size_t count)
+{
+	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+	size_t max = count;
+	long res = 0;
+
+	if (count == 0)
+		return -E2BIG;
+
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	/*
+	 * If src is unaligned, don't cross a page boundary,
+	 * since we don't know if the next page is mapped.
+	 */
+	if ((long)src & (sizeof(long) - 1)) {
+		size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1));
+		if (limit < max)
+			max = limit;
+	}
+#else
+	/* If src or dest is unaligned, don't do word-at-a-time. */
+	if (((long) dest | (long) src) & (sizeof(long) - 1))
+		max = 0;
+#endif
+
+	while (max >= sizeof(unsigned long)) {
+		unsigned long c, data;
+
+		c = *(unsigned long *)(src+res);
+		*(unsigned long *)(dest+res) = c;
+		if (has_zero(c, &data, &constants)) {
+			data = prep_zero_mask(c, data, &constants);
+			data = create_zero_mask(data);
+			return res + find_zero(data);
+		}
+		res += sizeof(unsigned long);
+		count -= sizeof(unsigned long);
+		max -= sizeof(unsigned long);
+	}
+
+	while (count) {
+		char c;
+
+		c = src[res];
+		dest[res] = c;
+		if (!c)
+			return res;
+		res++;
+		count--;
+	}
+
+	/* Hit buffer length without finding a NUL; force NUL-termination. */
+	if (res)
+		dest[res-1] = '\0';
+
+	return -E2BIG;
+}
+EXPORT_SYMBOL(strscpy_truncate);
+#endif
+
+#ifndef __HAVE_ARCH_STRSCPY
+/**
+ * strscpy - Copy a C-string into a sized buffer, but only if it fits
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: Size of destination buffer
+ *
+ * Copy the string into the dest buffer.  The routine returns the
+ * number of characters copied (not including the trailing NUL) or
+ * -E2BIG if the destination buffer wasn't big enough.  The behavior
+ * is undefined if the string buffers overlap.  The destination buffer
+ * is set to the empty string if the buffer is not big enough.
+ *
+ * Preferred over strlcpy() in all cases, and over strncpy() unless
+ * the latter's zero-fill behavior is desired and truncation of the
+ * source string is known not to be an issue.
+ */
+ssize_t strscpy(char *dest, const char *src, size_t count)
+{
+	ssize_t res = strscpy_truncate(dest, src, count);
+	if (res < 0 && count != 0)
+		dest[0] = '\0';
+	return res;
+}
+EXPORT_SYMBOL(strscpy);
+#endif
+
 #ifndef __HAVE_ARCH_STRCAT
 /**
  * strcat - Append one %NUL-terminated string to another
-- 
2.1.2


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

* [PATCH 3/3] tile: use global strscpy() rather than private copy
  2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
  2015-04-30 16:01                 ` [PATCH 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
  2015-04-30 16:01                 ` [PATCH 2/3] string: provide strscpy() and strscpy_truncate() Chris Metcalf
@ 2015-04-30 16:01                 ` Chris Metcalf
  2015-05-11 15:37                 ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
  2015-05-14 23:10                 ` Michael Ellerman
  4 siblings, 0 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-04-30 16:01 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

Now that strscpy() is a standard API, remove the local copy.

Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
---
 arch/tile/gxio/mpipe.c | 33 ++++-----------------------------
 1 file changed, 4 insertions(+), 29 deletions(-)

diff --git a/arch/tile/gxio/mpipe.c b/arch/tile/gxio/mpipe.c
index ee186e13dfe6..f102048d9c0e 100644
--- a/arch/tile/gxio/mpipe.c
+++ b/arch/tile/gxio/mpipe.c
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/string.h>
 
 #include <gxio/iorpc_globals.h>
 #include <gxio/iorpc_mpipe.h>
@@ -29,32 +30,6 @@
 /* HACK: Avoid pointless "shadow" warnings. */
 #define link link_shadow
 
-/**
- * strscpy - Copy a C-string into a sized buffer, but only if it fits
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
- * @size: size of destination buffer
- *
- * Use this routine to avoid copying too-long strings.
- * The routine returns the total number of bytes copied
- * (including the trailing NUL) or zero if the buffer wasn't
- * big enough.  To ensure that programmers pay attention
- * to the return code, the destination has a single NUL
- * written at the front (if size is non-zero) when the
- * buffer is not big enough.
- */
-static size_t strscpy(char *dest, const char *src, size_t size)
-{
-	size_t len = strnlen(src, size) + 1;
-	if (len > size) {
-		if (size)
-			dest[0] = '\0';
-		return 0;
-	}
-	memcpy(dest, src, len);
-	return len;
-}
-
 int gxio_mpipe_init(gxio_mpipe_context_t *context, unsigned int mpipe_index)
 {
 	char file[32];
@@ -540,7 +515,7 @@ int gxio_mpipe_link_instance(const char *link_name)
 	if (!context)
 		return GXIO_ERR_NO_DEVICE;
 
-	if (strscpy(name.name, link_name, sizeof(name.name)) == 0)
+	if (strscpy(name.name, link_name, sizeof(name.name)) < 0)
 		return GXIO_ERR_NO_DEVICE;
 
 	return gxio_mpipe_info_instance_aux(context, name);
@@ -559,7 +534,7 @@ int gxio_mpipe_link_enumerate_mac(int idx, char *link_name, uint8_t *link_mac)
 
 	rv = gxio_mpipe_info_enumerate_aux(context, idx, &name, &mac);
 	if (rv >= 0) {
-		if (strscpy(link_name, name.name, sizeof(name.name)) == 0)
+		if (strscpy(link_name, name.name, sizeof(name.name)) < 0)
 			return GXIO_ERR_INVAL_MEMORY_SIZE;
 		memcpy(link_mac, mac.mac, sizeof(mac.mac));
 	}
@@ -576,7 +551,7 @@ int gxio_mpipe_link_open(gxio_mpipe_link_t *link,
 	_gxio_mpipe_link_name_t name;
 	int rv;
 
-	if (strscpy(name.name, link_name, sizeof(name.name)) == 0)
+	if (strscpy(name.name, link_name, sizeof(name.name)) < 0)
 		return GXIO_ERR_NO_DEVICE;
 
 	rv = gxio_mpipe_link_open_aux(context, name, flags);
-- 
2.1.2


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

* Re: [PATCH 2/3] string: provide strscpy() and strscpy_truncate()
  2015-04-30 16:01                 ` [PATCH 2/3] string: provide strscpy() and strscpy_truncate() Chris Metcalf
@ 2015-05-06 15:01                   ` Dan Carpenter
  2015-05-06 15:21                     ` Chris Metcalf
  0 siblings, 1 reply; 35+ messages in thread
From: Dan Carpenter @ 2015-05-06 15:01 UTC (permalink / raw)
  To: Chris Metcalf
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

On Thu, Apr 30, 2015 at 12:01:16PM -0400, Chris Metcalf wrote:
> +ssize_t strscpy(char *dest, const char *src, size_t count)
> +{
> +	ssize_t res = strscpy_truncate(dest, src, count);
> +	if (res < 0 && count != 0)
> +		dest[0] = '\0';

How is this better than returning a truncated string?  Is it just
because the caller was naughty so we give them a spanking?

> +	return res;
> +}

regards,
dan carpenter

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

* Re: [PATCH 2/3] string: provide strscpy() and strscpy_truncate()
  2015-05-06 15:01                   ` Dan Carpenter
@ 2015-05-06 15:21                     ` Chris Metcalf
  2015-05-06 15:59                       ` Dan Carpenter
  0 siblings, 1 reply; 35+ messages in thread
From: Chris Metcalf @ 2015-05-06 15:21 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

On 5/6/2015 11:01 AM, Dan Carpenter wrote:
> On Thu, Apr 30, 2015 at 12:01:16PM -0400, Chris Metcalf wrote:
>> >+ssize_t strscpy(char *dest, const char *src, size_t count)
>> >+{
>> >+	ssize_t res = strscpy_truncate(dest, src, count);
>> >+	if (res < 0 && count != 0)
>> >+		dest[0] = '\0';
> How is this better than returning a truncated string?  Is it just
> because the caller was naughty so we give them a spanking?

There are basically two issues here:

1. A truncated string with an error return may still cause program errors,
even if the caller checks for the error return, if the buffer is later interpreted
as a valid string due to some other program error.  It's defensive programming.

2. Programmers are fond of ignoring error returns.  My experience with
truncated strings is that in too many cases, truncation causes program
errors down the line.  It's better to ensure that no partial string is returned
in this case.

In a perfect world, all error returns would be checked, and there would be
no need for this, but we definitely don't live in that world :-)

That said, although I think my approach is correct, I'm open to a consensus
that having strscpy() leave a truncated string in the dest buffer is better.

-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com


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

* Re: [PATCH 2/3] string: provide strscpy() and strscpy_truncate()
  2015-05-06 15:21                     ` Chris Metcalf
@ 2015-05-06 15:59                       ` Dan Carpenter
  2015-05-06 16:45                         ` Geert Uytterhoeven
  0 siblings, 1 reply; 35+ messages in thread
From: Dan Carpenter @ 2015-05-06 15:59 UTC (permalink / raw)
  To: Chris Metcalf
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

We actually do have a __must_check tag so it's easy enough to force
people to check.  A different option is we could make it trigger a
WARN_ONCE().

#define strXcpy(dest, src, len) (({				\
	ssize_t __ret = strscpy_truncate(dest, src, len);	\
	WARN_ONCE(__ret < 0, "strXcpy trancates\n");		\
	__ret; }))

I have never really cared about truncation, though.  I think not caring
is the common case.

regards,
dan carpenter


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

* Re: [PATCH 2/3] string: provide strscpy() and strscpy_truncate()
  2015-05-06 15:59                       ` Dan Carpenter
@ 2015-05-06 16:45                         ` Geert Uytterhoeven
  2015-05-07  9:00                           ` Dan Carpenter
  0 siblings, 1 reply; 35+ messages in thread
From: Geert Uytterhoeven @ 2015-05-06 16:45 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Chris Metcalf, Linus Torvalds, Al Viro, Fabian Frederick,
	Randy Dunlap, Rickard Strandqvist, Greg KH, Peter Zijlstra,
	David S. Miller, Frederic Weisbecker, Andrew Morton,
	Sam Ravnborg, Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, Linux-Arch

On Wed, May 6, 2015 at 5:59 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> We actually do have a __must_check tag so it's easy enough to force
> people to check.  A different option is we could make it trigger a

People tend to ignore compiler warnings...

> WARN_ONCE().
>
> #define strXcpy(dest, src, len) (({                             \
>         ssize_t __ret = strscpy_truncate(dest, src, len);       \
>         WARN_ONCE(__ret < 0, "strXcpy trancates\n");            \
>         __ret; }))

Which will probably trigger only in extreme cases in the wild, not during
development.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH 2/3] string: provide strscpy() and strscpy_truncate()
  2015-05-06 16:45                         ` Geert Uytterhoeven
@ 2015-05-07  9:00                           ` Dan Carpenter
  2015-05-07 15:10                             ` Chris Metcalf
  0 siblings, 1 reply; 35+ messages in thread
From: Dan Carpenter @ 2015-05-07  9:00 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Chris Metcalf, Linus Torvalds, Al Viro, Fabian Frederick,
	Randy Dunlap, Rickard Strandqvist, Greg KH, Peter Zijlstra,
	David S. Miller, Frederic Weisbecker, Andrew Morton,
	Sam Ravnborg, Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, Linux-Arch

On Wed, May 06, 2015 at 06:45:56PM +0200, Geert Uytterhoeven wrote:
> On Wed, May 6, 2015 at 5:59 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> > We actually do have a __must_check tag so it's easy enough to force
> > people to check.  A different option is we could make it trigger a
> 
> People tend to ignore compiler warnings...

We're doing a lot better these days with zero day build testing.  There
is not even one ignored __must_check return in my allmodconfig.

> 
> > WARN_ONCE().
> >
> > #define strXcpy(dest, src, len) (({                             \
> >         ssize_t __ret = strscpy_truncate(dest, src, len);       \
> >         WARN_ONCE(__ret < 0, "strXcpy trancates\n");            \
> >         __ret; }))
> 
> Which will probably trigger only in extreme cases in the wild, not during
> development.

It's less subtle than just putting an empty string there so we're more
likely to get bug reports than with the original code.

regards,
dan carpenter

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

* Re: [PATCH 2/3] string: provide strscpy() and strscpy_truncate()
  2015-05-07  9:00                           ` Dan Carpenter
@ 2015-05-07 15:10                             ` Chris Metcalf
  0 siblings, 0 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-05-07 15:10 UTC (permalink / raw)
  To: Dan Carpenter, Geert Uytterhoeven
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, Greg KH, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, Linux-Arch

On 05/07/2015 05:00 AM, Dan Carpenter wrote:
> On Wed, May 06, 2015 at 06:45:56PM +0200, Geert Uytterhoeven wrote:
>> On Wed, May 6, 2015 at 5:59 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote:
>>> We actually do have a __must_check tag so it's easy enough to force
>>> people to check.  A different option is we could make it trigger a
>> People tend to ignore compiler warnings...
> We're doing a lot better these days with zero day build testing.  There
> is not even one ignored __must_check return in my allmodconfig.

If we keep the strscpy/strscpy_truncate distinction, I agree that having
__must_check on strscpy seems like a good idea.

>>> WARN_ONCE().
>>>
>>> #define strXcpy(dest, src, len) (({                             \
>>>          ssize_t __ret = strscpy_truncate(dest, src, len);       \
>>>          WARN_ONCE(__ret < 0, "strXcpy trancates\n");            \
>>>          __ret; }))
>> Which will probably trigger only in extreme cases in the wild, not during
>> development.
> It's less subtle than just putting an empty string there so we're more
> likely to get bug reports than with the original code.

The problem with WARN_ONCE() here is that we may be using strscpy()
to take user input of some kind.  If so, we don't want to warn if we
are truncating the string - we just want to return a suitable error up
the call stack.

-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com


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

* Re: [PATCH 0/3] add new strscpy() API for string copy
  2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
                                   ` (2 preceding siblings ...)
  2015-04-30 16:01                 ` [PATCH 3/3] tile: use global strscpy() rather than private copy Chris Metcalf
@ 2015-05-11 15:37                 ` Chris Metcalf
  2015-05-14 23:10                 ` Michael Ellerman
  4 siblings, 0 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-05-11 15:37 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Al Viro, Fabian Frederick, Randy Dunlap, Rickard Strandqvist,
	gregkh, Peter Zijlstra, David S. Miller, Frederic Weisbecker,
	Andrew Morton, Sam Ravnborg, Stephen Rothwell, Theodore Ts'o,
	Grant Likely, Linux Kernel Mailing List, linux-arch

Ping!  There was a little feedback on the strscpy() patch series,
but I think at this point it boiled down to adding a __must_check
on strscpy(), which I've done.  Any further opinions?  Would
anyone like to volunteer to take this into their tree?  Or Linus,
are you ready to pull it directly when the merge window opens?

git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git 
strscpy

Thanks!

On 04/30/2015 12:01 PM, Chris Metcalf wrote:
> This patch series addresses limitations in strncpy() and strlcpy();
> both the old APIs are unpleasant, as Linus nicely summarized here
> a couple of days ago:
>
>    https://lkml.org/lkml/2015/4/28/570
>
> and of course as other folks (Greg K-H and Linus again) said last year:
>
>    https://plus.google.com/+gregkroahhartman/posts/1amLbuhWbh5
>
> The proposed new API (strscpy(), for "s"afe string copy) has an
> easy-to-use API for detecting buffer overflow, avoids unsafe truncation
> by default, and isn't subject to thread-safety attacks like the current
> strlcpy implementation.  See patch 2/3 for more on why strscpy() is a
> good thing.
>
> To make strscpy() work more efficiently I did the minimum tweaking
> necessary to allow <asm/word-at-a-time.h> to work on all architectures,
> though of course individual maintainers can still make their versions
> more efficient as needed.
>
> It's likely not necessary for per-architecture implementations of
> strscpy() to be written, but I stuck with the standard __HAVE_ARCH_XXX
> model just for consistency with the rest of <linux/string.h>.
>
> I tested the implementation with a simple user-space harness, so I
> believe it is correct for the corner cases I could think of.  In
> particular I pairwise-tested all the unaligned values of source and
> dest, and tested the restriction on src page-crossing at all
> unaligned offsets approaching the page boundary.
>
> This builds on an earlier version of strscpy() submitted as
> a file-static method in the arch/tile/gxio tree last year, after
> an attempt to gather interest in a new generic strscpy failed:
>
>    https://lkml.org/lkml/2014/8/7/368
>
> The patch series is available to be pulled from
>
>    git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git strscpy
>
> Chris Metcalf (3):
>    Make asm/word-at-a-time.h available on all architectures
>    string: provide strscpy() and strscpy_truncate()
>    tile: use global strscpy() rather than private copy
>
>   arch/arc/include/asm/Kbuild          |   1 +
>   arch/avr32/include/asm/Kbuild        |   1 +
>   arch/blackfin/include/asm/Kbuild     |   1 +
>   arch/c6x/include/asm/Kbuild          |   1 +
>   arch/cris/include/asm/Kbuild         |   1 +
>   arch/frv/include/asm/Kbuild          |   1 +
>   arch/hexagon/include/asm/Kbuild      |   1 +
>   arch/ia64/include/asm/Kbuild         |   1 +
>   arch/m32r/include/asm/Kbuild         |   1 +
>   arch/metag/include/asm/Kbuild        |   1 +
>   arch/microblaze/include/asm/Kbuild   |   1 +
>   arch/mips/include/asm/Kbuild         |   1 +
>   arch/mn10300/include/asm/Kbuild      |   1 +
>   arch/nios2/include/asm/Kbuild        |   1 +
>   arch/powerpc/include/asm/Kbuild      |   1 +
>   arch/s390/include/asm/Kbuild         |   1 +
>   arch/score/include/asm/Kbuild        |   1 +
>   arch/tile/gxio/mpipe.c               |  33 ++---------
>   arch/tile/include/asm/Kbuild         |   1 +
>   arch/um/include/asm/Kbuild           |   1 +
>   arch/unicore32/include/asm/Kbuild    |   1 +
>   arch/xtensa/include/asm/Kbuild       |   1 +
>   include/asm-generic/word-at-a-time.h |  80 ++++++++++++++++++++++---
>   include/linux/string.h               |   6 ++
>   lib/string.c                         | 109 +++++++++++++++++++++++++++++++++++
>   25 files changed, 212 insertions(+), 37 deletions(-)
>

-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com


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

* Re: [PATCH 0/3] add new strscpy() API for string copy
  2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
                                   ` (3 preceding siblings ...)
  2015-05-11 15:37                 ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
@ 2015-05-14 23:10                 ` Michael Ellerman
  2015-05-15 15:15                   ` Chris Metcalf
  4 siblings, 1 reply; 35+ messages in thread
From: Michael Ellerman @ 2015-05-14 23:10 UTC (permalink / raw)
  To: Chris Metcalf
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

On Thu, 2015-04-30 at 12:01 -0400, Chris Metcalf wrote:
> This patch series addresses limitations in strncpy() and strlcpy();
> both the old APIs are unpleasant, as Linus nicely summarized here
> a couple of days ago:
> 
>   https://lkml.org/lkml/2015/4/28/570
> 
> and of course as other folks (Greg K-H and Linus again) said last year:
> 
>   https://plus.google.com/+gregkroahhartman/posts/1amLbuhWbh5
> 
> The proposed new API (strscpy(), for "s"afe string copy) has an
> easy-to-use API for detecting buffer overflow, avoids unsafe truncation
> by default, and isn't subject to thread-safety attacks like the current
> strlcpy implementation.  See patch 2/3 for more on why strscpy() is a
> good thing.

+1 on the concept.

> To make strscpy() work more efficiently I did the minimum tweaking
> necessary to allow <asm/word-at-a-time.h> to work on all architectures,
> though of course individual maintainers can still make their versions
> more efficient as needed.
> 
> It's likely not necessary for per-architecture implementations of
> strscpy() to be written, but I stuck with the standard __HAVE_ARCH_XXX
> model just for consistency with the rest of <linux/string.h>.
> 
> I tested the implementation with a simple user-space harness, so I
> believe it is correct for the corner cases I could think of.  In
> particular I pairwise-tested all the unaligned values of source and
> dest, and tested the restriction on src page-crossing at all
> unaligned offsets approaching the page boundary.

Can you please put that in tools/testing/selftests and merge it as part of the
series? That way I can run the tests and be confident it works on powerpc.

cheers



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

* Re: [PATCH 0/3] add new strscpy() API for string copy
  2015-05-14 23:10                 ` Michael Ellerman
@ 2015-05-15 15:15                   ` Chris Metcalf
  2015-05-18  1:13                     ` Michael Ellerman
  0 siblings, 1 reply; 35+ messages in thread
From: Chris Metcalf @ 2015-05-15 15:15 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

On 05/14/2015 07:10 PM, Michael Ellerman wrote:
> On Thu, 2015-04-30 at 12:01 -0400, Chris Metcalf wrote:
>> This patch series addresses limitations in strncpy() and strlcpy();
>> both the old APIs are unpleasant, as Linus nicely summarized here
>> a couple of days ago:
>>
>>    https://lkml.org/lkml/2015/4/28/570
>>
>> and of course as other folks (Greg K-H and Linus again) said last year:
>>
>>    https://plus.google.com/+gregkroahhartman/posts/1amLbuhWbh5
>>
>> The proposed new API (strscpy(), for "s"afe string copy) has an
>> easy-to-use API for detecting buffer overflow, avoids unsafe truncation
>> by default, and isn't subject to thread-safety attacks like the current
>> strlcpy implementation.  See patch 2/3 for more on why strscpy() is a
>> good thing.
> +1 on the concept.

Thanks.

>> To make strscpy() work more efficiently I did the minimum tweaking
>> necessary to allow <asm/word-at-a-time.h> to work on all architectures,
>> though of course individual maintainers can still make their versions
>> more efficient as needed.
>>
>> It's likely not necessary for per-architecture implementations of
>> strscpy() to be written, but I stuck with the standard __HAVE_ARCH_XXX
>> model just for consistency with the rest of <linux/string.h>.
>>
>> I tested the implementation with a simple user-space harness, so I
>> believe it is correct for the corner cases I could think of.  In
>> particular I pairwise-tested all the unaligned values of source and
>> dest, and tested the restriction on src page-crossing at all
>> unaligned offsets approaching the page boundary.
> Can you please put that in tools/testing/selftests and merge it as part of the
> series? That way I can run the tests and be confident it works on powerpc.

Unfortunately, the strscpy patch series only changes the one previous
user of the API, which is a tile-architecture-only driver piece, not
particularly useful for anyone else for testing.

The testing I did pulled strscpy() and word-at-a-time out into a
separate, standalone userspace implementation, and tested it there,
rather than doing tests through the syscall API like 
tools/testing/selftests.
So I don't really see a way of committing my test framework, other
than as a real Kconfig-enabled boot-time self-test or some such;
I can certainly do that but I don't know how excited people are to
have that additional level of source-code and Kconfig bloat.

-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com


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

* Re: [PATCH 0/3] add new strscpy() API for string copy
  2015-05-15 15:15                   ` Chris Metcalf
@ 2015-05-18  1:13                     ` Michael Ellerman
  2015-05-26 19:33                       ` Chris Metcalf
  0 siblings, 1 reply; 35+ messages in thread
From: Michael Ellerman @ 2015-05-18  1:13 UTC (permalink / raw)
  To: Chris Metcalf
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

On Fri, 2015-05-15 at 11:15 -0400, Chris Metcalf wrote:
> On 05/14/2015 07:10 PM, Michael Ellerman wrote:
> > On Thu, 2015-04-30 at 12:01 -0400, Chris Metcalf wrote:
> >>
> >> I tested the implementation with a simple user-space harness, so I
> >> believe it is correct for the corner cases I could think of.  In
> >> particular I pairwise-tested all the unaligned values of source and
> >> dest, and tested the restriction on src page-crossing at all
> >> unaligned offsets approaching the page boundary.
> > Can you please put that in tools/testing/selftests and merge it as part of the
> > series? That way I can run the tests and be confident it works on powerpc.
> 
> Unfortunately, the strscpy patch series only changes the one previous
> user of the API, which is a tile-architecture-only driver piece, not
> particularly useful for anyone else for testing.
> 
> The testing I did pulled strscpy() and word-at-a-time out into a
> separate, standalone userspace implementation, and tested it there,
> rather than doing tests through the syscall API like 
> tools/testing/selftests.

Not everything in selftests has to or does go through the syscall API.

We (powerpc) have tests of our memcpy/memcmp/load_unaligned_zeropad that are
built as standalone test programs.

Doing that for stuff in lib/string.c does look a bit complicated, because you'd
need to pull in a bunch of kernel headers.

Do you mind posting your test code somewhere so I can run it, and maybe I can
work out how to fold it into a selftest.

cheers



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

* Re: [PATCH 0/3] add new strscpy() API for string copy
  2015-05-18  1:13                     ` Michael Ellerman
@ 2015-05-26 19:33                       ` Chris Metcalf
  0 siblings, 0 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-05-26 19:33 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely,
	Linux Kernel Mailing List, linux-arch

On 05/17/2015 09:13 PM, Michael Ellerman wrote:
> On Fri, 2015-05-15 at 11:15 -0400, Chris Metcalf wrote:
>> On 05/14/2015 07:10 PM, Michael Ellerman wrote:
>>> On Thu, 2015-04-30 at 12:01 -0400, Chris Metcalf wrote:
>>>>
>>>> I tested the implementation with a simple user-space harness, so I
>>>> believe it is correct for the corner cases I could think of.  In
>>>> particular I pairwise-tested all the unaligned values of source and
>>>> dest, and tested the restriction on src page-crossing at all
>>>> unaligned offsets approaching the page boundary.
>>> Can you please put that in tools/testing/selftests and merge it as part of the
>>> series? That way I can run the tests and be confident it works on powerpc.
>>
>> Unfortunately, the strscpy patch series only changes the one previous
>> user of the API, which is a tile-architecture-only driver piece, not
>> particularly useful for anyone else for testing.
>>
>> The testing I did pulled strscpy() and word-at-a-time out into a
>> separate, standalone userspace implementation, and tested it there,
>> rather than doing tests through the syscall API like 
>> tools/testing/selftests.
>
> Not everything in selftests has to or does go through the syscall API.
>
> We (powerpc) have tests of our memcpy/memcmp/load_unaligned_zeropad that are
> built as standalone test programs.
>
> Doing that for stuff in lib/string.c does look a bit complicated, because you'd
> need to pull in a bunch of kernel headers.
>
> Do you mind posting your test code somewhere so I can run it, and maybe I can
> work out how to fold it into a selftest.

Seems easiest to just post it to LKML so anyone else who wants to can
take a look at it.  Trying to post a collection of files without
violating the "no MIME parts" rule for LKML made me dust off my
Usenet memories and track down a version of shar to use to bundle up
the test.c harness, the strscpy.c code (excerpted from lib/string.c with
suitable #defines and #includes so it builds in userspace), and a
version of word-at-a-time.h that works for the two environments I
tested it in (x86_64 and tile).
-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com


#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# existing files WILL be overwritten
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   2294 -rw-r--r-- test.c
#   3321 -rw-r--r-- strscpy.c
#   2905 -rw-r--r-- word-at-a-time.h
#
echo=echo
if mkdir _sh15429; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= test.c ==============
  $echo 'x -' extracting 'test.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'test.c' &&
/* Compile "gcc -O -o test test.c strscpy.c" and run "./test" */
X
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
X
size_t strscpy_truncate(char *dest, const char *src, size_t count);
size_t strscpy(char *dest, const char *src, size_t count);
X
char dest[1024] __attribute__((aligned(8)));
char src[1024] __attribute__((aligned(8)));
X
#define assert(check) do {                                              \
X  if (!(check)) {                                                       \
X    printf("%s: %d: %d: %s @%zd: %d => %d\n", #check, i, j, s, count, rc, ret); \
X    exit(1);                                                            \
X  } } while (0)
X
void test(int i, int j, char *s, size_t count, int ret)
{
X  int rc;
X
X  if (ret == -1)
X    ret = strlen(s);
X
X  memset(dest, 0, sizeof(dest));
X  memset(src, 0, sizeof(src));
X  strcpy(&src[i], s);
X  rc = strscpy(&dest[j], &src[i], count);
X  assert(rc == ret);
X  if (rc > 0)
X    assert(strcmp(&dest[j], s) == 0);
X  else if (count > 0)
X    assert(dest[j] == '\0');
X
X  memset(dest, 0, sizeof(dest));
X  memset(src, 0, sizeof(src));
X  strcpy(&src[i], s);
X  rc = strscpy_truncate(&dest[j], &src[i], count);
X  assert(rc == ret);
X  if (rc > 0)
X    assert(strcmp(&dest[j], s) == 0);
X  else if (count > 0) {
X    assert(strncmp(&dest[j], s, count-1) == 0);
X    assert(dest[j+count-1] == '\0');
X  }
}
X
int main()
{
X  int i, j;
X
X  for (i = 0; i < 15; ++i) {
X    for (j = 0; j < 15; ++j) {
X      test(i, j, "Hello, world", sizeof(src) - i, -1);
X      test(i, j, "Hello, world", 12, -E2BIG);
X      test(i, j, "foo", 0, -E2BIG);
X      test(i, j, "foo", 1, -E2BIG);
X    }
X  }
X
X  /* Check we never walk across a page boundary past the source. */
X  char *p = mmap(NULL, 2*getpagesize(), PROT_READ|PROT_WRITE,
X                 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
X  mprotect(p+getpagesize(), getpagesize(), PROT_NONE);
X  char *base = p + getpagesize() - 16;
X  strcpy(base, "This is some ra");
X  for (i = 0; i < 15; ++i) {
X    memset(dest, 0, 16);
X    int rc = strscpy_truncate(dest, base + i, sizeof(dest));
X    if (rc != 16 - i - 1 || strcmp(dest, base + i) != 0) {
X      printf("Badness at %d %d\n", i, rc);
X      exit(1);
X    }
X  }
X
X  printf("OK!\n");
X  return 0;
}
SHAR_EOF
  chmod 0644 'test.c' ||
  $echo 'restore of' 'test.c' 'failed'
# ============= strscpy.c ==============
  $echo 'x -' extracting 'strscpy.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'strscpy.c' &&
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "word-at-a-time.h"
#ifndef __tile__
#define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
#endif
#define PAGE_SIZE getpagesize()
#define EXPORT_SYMBOL(sym)
X
#ifndef __HAVE_ARCH_STRSCPY_TRUNCATE
/**
X * strscpy_truncate - Copy a C-string into a sized buffer
X * @dest: Where to copy the string to
X * @src: Where to copy the string from
X * @count: Size of destination buffer
X *
X * Copy the string, or as much of it as fits, into the dest buffer.
X * The routine returns the number of characters copied (not including
X * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough.
X * The behavior is undefined if the string buffers overlap.
X *
X * Note that the implementation is robust to the string changing out
X * from underneath it, unlike the current strlcpy() implementation,
X * and it is easier to check overflow than with strlcpy()'s API.
X *
X * strscpy() is preferred over this function unless a truncated string
X * provides some valid semantics in the destination buffer.
X */
ssize_t strscpy_truncate(char *dest, const char *src, size_t count)
{
X	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
X	size_t max = count;
X	long res = 0;
X
X	if (count == 0)
X		return -E2BIG;
X
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
X	/*
X	 * If src is unaligned, don't cross a page boundary,
X	 * since we don't know if the next page is mapped.
X	 */
X	if ((long)src & (sizeof(long) - 1)) {
X		size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1));
X		if (limit < max)
X			max = limit;
X	}
#else
X	/* If src or dest is unaligned, don't do word-at-a-time. */
X	if (((long) dest | (long) src) & (sizeof(long) - 1))
X		max = 0;
#endif
X
X	while (max >= sizeof(unsigned long)) {
X		unsigned long c, data;
X
X		c = *(unsigned long *)(src+res);
X		*(unsigned long *)(dest+res) = c;
X		if (has_zero(c, &data, &constants)) {
X			data = prep_zero_mask(c, data, &constants);
X			data = create_zero_mask(data);
X			return res + find_zero(data);
X		}
X		res += sizeof(unsigned long);
X		count -= sizeof(unsigned long);
X		max -= sizeof(unsigned long);
X	}
X
X	while (count) {
X		char c;
X
X		c = src[res];
X		dest[res] = c;
X		if (!c)
X			return res;
X		res++;
X		count--;
X	}
X
X	/* Hit buffer length without finding a NUL; force NUL-termination. */
X	if (res)
X		dest[res-1] = '\0';
X
X	return -E2BIG;
}
EXPORT_SYMBOL(strscpy_truncate);
#endif
X
#ifndef __HAVE_ARCH_STRSCPY
/**
X * strscpy - Copy a C-string into a sized buffer, but only if it fits
X * @dest: Where to copy the string to
X * @src: Where to copy the string from
X * @count: Size of destination buffer
X *
X * Copy the string into the dest buffer.  The routine returns the
X * number of characters copied (not including the trailing NUL) or
X * -E2BIG if the destination buffer wasn't big enough.  The behavior
X * is undefined if the string buffers overlap.  The destination buffer
X * is set to the empty string if the buffer is not big enough.
X *
X * Preferred over strlcpy() in all cases, and over strncpy() unless
X * the latter's zero-fill behavior is desired and truncation of the
X * source string is known not to be an issue.
X */
ssize_t strscpy(char *dest, const char *src, size_t count)
{
X	ssize_t res = strscpy_truncate(dest, src, count);
X	if (res < 0 && count != 0)
X		dest[0] = '\0';
X	return res;
}
EXPORT_SYMBOL(strscpy);
#endif
SHAR_EOF
  chmod 0644 'strscpy.c' ||
  $echo 'restore of' 'strscpy.c' 'failed'
# ============= word-at-a-time.h ==============
  $echo 'x -' extracting 'word-at-a-time.h' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'word-at-a-time.h' &&
#ifndef _ASM_WORD_AT_A_TIME_H
#define _ASM_WORD_AT_A_TIME_H
X
#define REPEAT_BYTE(x)	((~0ul / 0xff) * (x))
X
#ifndef __tile__
#define IS_UNALIGNED(src, dst)	0
#else
#define IS_UNALIGNED(src, dst)	\
X	(((long) dst | (long) src) & (sizeof(long) - 1))
#endif
X
#ifdef __BIG_ENDIAN__
X
struct word_at_a_time {
X	const unsigned long high_bits, low_bits;
};
X
#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) }
X
/* Bit set in the bytes that have a zero */
static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c)
{
X	unsigned long mask = (val & c->low_bits) + c->low_bits;
X	return ~(mask | rhs);
}
X
#define create_zero_mask(mask) (mask)
X
static inline long find_zero(unsigned long mask)
{
X	long byte = 0;
#ifdef _LP64
X	if (mask >> 32)
X		mask >>= 32;
X	else
X		byte = 4;
#endif
X	if (mask >> 16)
X		mask >>= 16;
X	else
X		byte += 2;
X	return (mask >> 8) ? byte : byte + 1;
}
X
static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
{
X	unsigned long rhs = val | c->low_bits;
X	*data = rhs;
X	return (val + c->high_bits) & ~rhs;
}
X
#ifndef zero_bytemask
#define zero_bytemask(mask) (~1ul << __fls(mask))
#endif
X
#else
X
/*
X * The optimal byte mask counting is probably going to be something
X * that is architecture-specific. If you have a reliably fast
X * bit count instruction, that might be better than the multiply
X * and shift, for example.
X */
struct word_at_a_time {
X	const unsigned long one_bits, high_bits;
};
X
#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
X
#ifdef _LP64
X
/*
X * Jan Achrenius on G+: microoptimized version of
X * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
X * that works for the bytemasks without having to
X * mask them first.
X */
static inline long count_masked_bytes(unsigned long mask)
{
X	return mask*0x0001020304050608ul >> 56;
}
X
#else	/* 32-bit case */
X
/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
static inline long count_masked_bytes(long mask)
{
X	/* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
X	long a = (0x0ff0001+mask) >> 23;
X	/* Fix the 1 for 00 case */
X	return a & mask;
}
X
#endif
X
/* Return nonzero if it has a zero */
static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
{
X	unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
X	*bits = mask;
X	return mask;
}
X
static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
{
X	return bits;
}
X
static inline unsigned long create_zero_mask(unsigned long bits)
{
X	bits = (bits - 1) & ~bits;
X	return bits >> 7;
}
X
/* The mask we created is directly usable as a bytemask */
#define zero_bytemask(mask) (mask)
X
static inline unsigned long find_zero(unsigned long mask)
{
X	return count_masked_bytes(mask);
}
X
#endif /* __BIG_ENDIAN */
X
#endif /* _ASM_WORD_AT_A_TIME_H */
SHAR_EOF
  chmod 0644 'word-at-a-time.h' ||
  $echo 'restore of' 'word-at-a-time.h' 'failed'
rm -fr _sh15429
exit 0

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

* [GIT PULL] strscpy string copy function
@ 2015-06-30 18:01 Chris Metcalf
  2015-07-01 16:11 ` Linus Torvalds
  0 siblings, 1 reply; 35+ messages in thread
From: Chris Metcalf @ 2015-06-30 18:01 UTC (permalink / raw)
  To: Linus Torvalds, open list

Linus,

Please pull the following changes for 4.2 from:

   git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git strscpy

The discussion on this died down on LKML [1], so either (a) everybody loved it and
it was obviously correct, or (b) everybody lost interest.  I'm optimistically
assuming (a), but willing to hear otherwise!

[1] https://lwn.net/Articles/643140/

Chris Metcalf (3):
       Make asm/word-at-a-time.h available on all architectures
       string: provide strscpy() and strscpy_truncate()
       tile: use global strscpy() rather than private copy

  arch/arc/include/asm/Kbuild          |   1 +
  arch/avr32/include/asm/Kbuild        |   1 +
  arch/blackfin/include/asm/Kbuild     |   1 +
  arch/c6x/include/asm/Kbuild          |   1 +
  arch/cris/include/asm/Kbuild         |   1 +
  arch/frv/include/asm/Kbuild          |   1 +
  arch/hexagon/include/asm/Kbuild      |   1 +
  arch/ia64/include/asm/Kbuild         |   1 +
  arch/m32r/include/asm/Kbuild         |   1 +
  arch/metag/include/asm/Kbuild        |   1 +
  arch/microblaze/include/asm/Kbuild   |   1 +
  arch/mips/include/asm/Kbuild         |   1 +
  arch/mn10300/include/asm/Kbuild      |   1 +
  arch/nios2/include/asm/Kbuild        |   1 +
  arch/powerpc/include/asm/Kbuild      |   1 +
  arch/s390/include/asm/Kbuild         |   1 +
  arch/score/include/asm/Kbuild        |   1 +
  arch/tile/gxio/mpipe.c               |  33 ++---------
  arch/tile/include/asm/Kbuild         |   1 +
  arch/um/include/asm/Kbuild           |   1 +
  arch/unicore32/include/asm/Kbuild    |   1 +
  arch/xtensa/include/asm/Kbuild       |   1 +
  include/asm-generic/word-at-a-time.h |  80 ++++++++++++++++++++++---
  include/linux/string.h               |   6 ++
  lib/string.c                         | 110 +++++++++++++++++++++++++++++++++++
  25 files changed, 213 insertions(+), 37 deletions(-)

-- 
Chris Metcalf, EZChip Semiconductor
http://www.ezchip.com


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

* Re: [GIT PULL] strscpy string copy function
  2015-06-30 18:01 [GIT PULL] strscpy string copy function Chris Metcalf
@ 2015-07-01 16:11 ` Linus Torvalds
  2015-07-08 20:20   ` [PATCH v2 0/3] add new strscpy() API for string copy Chris Metcalf
  0 siblings, 1 reply; 35+ messages in thread
From: Linus Torvalds @ 2015-07-01 16:11 UTC (permalink / raw)
  To: Chris Metcalf; +Cc: open list

On Tue, Jun 30, 2015 at 11:01 AM, Chris Metcalf <cmetcalf@ezchip.com> wrote:
> Linus,
>
> The discussion on this died down on LKML [1], so either (a) everybody loved
> it and
> it was obviously correct, or (b) everybody lost interest.  I'm
> optimistically
> assuming (a), but willing to hear otherwise!
>
> [1] https://lwn.net/Articles/643140/

Ugh. I thought we agreed to not have the odd "make it zero-sized"
thing be the default.

Let's just make something that is a sane version of strncpy/strlcpy,
not introduce yet another "str*cpy with really odd semantics for the
corner case"

              Linus

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

* [PATCH v2 0/3] add new strscpy() API for string copy
  2015-07-01 16:11 ` Linus Torvalds
@ 2015-07-08 20:20   ` Chris Metcalf
  2015-07-08 20:20     ` [PATCH v2 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
                       ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-07-08 20:20 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely, Dan Carpenter,
	Geert Uytterhoeven, Michael Ellerman, Linux Kernel Mailing List,
	linux-arch

v2: eliminate strscpy_truncate(); the single strscpy() API in v2
  just tolerates a truncated string (while returning an error value)
  Also, improve some of the comparison language with strlcpy/strncpy.

This patch series addresses limitations in strncpy() and strlcpy();
both the old APIs are unpleasant, as Linus nicely summarized here:

  https://lkml.org/lkml/2015/4/28/570

and of course as other folks (Greg K-H and Linus again) said last year:

  https://plus.google.com/+gregkroahhartman/posts/1amLbuhWbh5

The proposed new API (strscpy(), for "s"afe string copy) has an
easy-to-use API for detecting buffer overflow, doesn't walk past the
requested copy size on the source string, and isn't subject to
thread-safety attacks like the current strlcpy implementation.  See
patch 2/3 for more on why strscpy() is a good thing.

To make strscpy() work more efficiently I did the minimum tweaking
necessary to allow <asm/word-at-a-time.h> to work on all architectures,
though of course individual maintainers can still make their versions
more efficient as needed.

It's likely not necessary for per-architecture implementations of
strscpy() to be written, but I stuck with the standard __HAVE_ARCH_XXX
model just for consistency with the rest of <linux/string.h>.

I tested the implementation with a simple user-space harness, so I
believe it is correct for the corner cases I could think of.  In
particular I pairwise-tested all the unaligned values of source and
dest, and tested the restriction on src page-crossing at all
unaligned offsets approaching the page boundary.

The patch series is available to be pulled from

  git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git strscpy

Chris Metcalf (3):
  Make asm/word-at-a-time.h available on all architectures
  string: provide strscpy()
  tile: use global strscpy() rather than private copy

 arch/arc/include/asm/Kbuild          |  1 +
 arch/avr32/include/asm/Kbuild        |  1 +
 arch/blackfin/include/asm/Kbuild     |  1 +
 arch/c6x/include/asm/Kbuild          |  1 +
 arch/cris/include/asm/Kbuild         |  1 +
 arch/frv/include/asm/Kbuild          |  1 +
 arch/hexagon/include/asm/Kbuild      |  1 +
 arch/ia64/include/asm/Kbuild         |  1 +
 arch/m32r/include/asm/Kbuild         |  1 +
 arch/metag/include/asm/Kbuild        |  1 +
 arch/microblaze/include/asm/Kbuild   |  1 +
 arch/mips/include/asm/Kbuild         |  1 +
 arch/mn10300/include/asm/Kbuild      |  1 +
 arch/nios2/include/asm/Kbuild        |  1 +
 arch/powerpc/include/asm/Kbuild      |  1 +
 arch/s390/include/asm/Kbuild         |  1 +
 arch/score/include/asm/Kbuild        |  1 +
 arch/tile/gxio/mpipe.c               | 33 ++------------
 arch/tile/include/asm/Kbuild         |  1 +
 arch/um/include/asm/Kbuild           |  1 +
 arch/unicore32/include/asm/Kbuild    |  1 +
 arch/xtensa/include/asm/Kbuild       |  1 +
 include/asm-generic/word-at-a-time.h | 80 ++++++++++++++++++++++++++++----
 include/linux/string.h               |  3 ++
 lib/string.c                         | 88 ++++++++++++++++++++++++++++++++++++
 25 files changed, 188 insertions(+), 37 deletions(-)

-- 
2.1.2


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

* [PATCH v2 1/3] Make asm/word-at-a-time.h available on all architectures
  2015-07-08 20:20   ` [PATCH v2 0/3] add new strscpy() API for string copy Chris Metcalf
@ 2015-07-08 20:20     ` Chris Metcalf
  2015-07-08 20:20     ` [PATCH v2 2/3] string: provide strscpy() Chris Metcalf
  2015-07-08 20:20     ` [PATCH v2 3/3] tile: use global strscpy() rather than private copy Chris Metcalf
  2 siblings, 0 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-07-08 20:20 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely, Dan Carpenter,
	Geert Uytterhoeven, Michael Ellerman, Linux Kernel Mailing List,
	linux-arch

Added the x86 implementation of word-at-a-time to the
generic version, which previously only supported big-endian.

Omitted the x86-specific load_unaligned_zeropad(), which in
any case is also not present for the existing BE-only
implementation of a word-at-a-time, and is only used under
CONFIG_DCACHE_WORD_ACCESS.

Added as a "generic-y" to the Kbuilds of all architectures
that didn't previously have it.

Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
---
 arch/arc/include/asm/Kbuild          |  1 +
 arch/avr32/include/asm/Kbuild        |  1 +
 arch/blackfin/include/asm/Kbuild     |  1 +
 arch/c6x/include/asm/Kbuild          |  1 +
 arch/cris/include/asm/Kbuild         |  1 +
 arch/frv/include/asm/Kbuild          |  1 +
 arch/hexagon/include/asm/Kbuild      |  1 +
 arch/ia64/include/asm/Kbuild         |  1 +
 arch/m32r/include/asm/Kbuild         |  1 +
 arch/metag/include/asm/Kbuild        |  1 +
 arch/microblaze/include/asm/Kbuild   |  1 +
 arch/mips/include/asm/Kbuild         |  1 +
 arch/mn10300/include/asm/Kbuild      |  1 +
 arch/nios2/include/asm/Kbuild        |  1 +
 arch/powerpc/include/asm/Kbuild      |  1 +
 arch/s390/include/asm/Kbuild         |  1 +
 arch/score/include/asm/Kbuild        |  1 +
 arch/tile/include/asm/Kbuild         |  1 +
 arch/um/include/asm/Kbuild           |  1 +
 arch/unicore32/include/asm/Kbuild    |  1 +
 arch/xtensa/include/asm/Kbuild       |  1 +
 include/asm-generic/word-at-a-time.h | 80 ++++++++++++++++++++++++++++++++----
 22 files changed, 93 insertions(+), 8 deletions(-)

diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index be0c39e76f7c..be895ef03a51 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -49,4 +49,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild
index 528d70d47a54..10dd6e8470bd 100644
--- a/arch/avr32/include/asm/Kbuild
+++ b/arch/avr32/include/asm/Kbuild
@@ -20,4 +20,5 @@ generic-y += sections.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/blackfin/include/asm/Kbuild b/arch/blackfin/include/asm/Kbuild
index 4bd3c3cfc9ab..9705a527b7b0 100644
--- a/arch/blackfin/include/asm/Kbuild
+++ b/arch/blackfin/include/asm/Kbuild
@@ -46,4 +46,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index ae0a51f5376c..535efdb0692d 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -59,4 +59,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index 057e51859b0a..4991539a25f6 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -26,4 +26,5 @@ generic-y += sections.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/frv/include/asm/Kbuild b/arch/frv/include/asm/Kbuild
index e3f81b53578e..ca34d1cf2cdf 100644
--- a/arch/frv/include/asm/Kbuild
+++ b/arch/frv/include/asm/Kbuild
@@ -7,3 +7,4 @@ generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild
index c7a99f860b40..872920fba0a6 100644
--- a/arch/hexagon/include/asm/Kbuild
+++ b/arch/hexagon/include/asm/Kbuild
@@ -58,4 +58,5 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 9b41b4bcc073..614579fa1e49 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -8,3 +8,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
 generic-y += vtime.h
+generic-y += word-at-a-time.h
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index 2edc793372fc..36f850dd4a1e 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -9,3 +9,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/metag/include/asm/Kbuild b/arch/metag/include/asm/Kbuild
index 0bf5d525b945..a291b3b2529e 100644
--- a/arch/metag/include/asm/Kbuild
+++ b/arch/metag/include/asm/Kbuild
@@ -54,4 +54,5 @@ generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index ab564a6db5c3..966f221b2d67 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -10,3 +10,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += syscalls.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 526539cbc99f..c3cfb83aca1d 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -18,4 +18,5 @@ generic-y += serial.h
 generic-y += trace_clock.h
 generic-y += ucontext.h
 generic-y += user.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/mn10300/include/asm/Kbuild b/arch/mn10300/include/asm/Kbuild
index f892d9de47d9..30a06e2d6e42 100644
--- a/arch/mn10300/include/asm/Kbuild
+++ b/arch/mn10300/include/asm/Kbuild
@@ -9,3 +9,4 @@ generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild
index 24b3d8999ac7..bc87081c0669 100644
--- a/arch/nios2/include/asm/Kbuild
+++ b/arch/nios2/include/asm/Kbuild
@@ -61,4 +61,5 @@ generic-y += types.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 4b87205c230c..dfc61a151890 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -9,3 +9,4 @@ generic-y += rwsem.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
 generic-y += vtime.h
+generic-y += word-at-a-time.h
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index c631f98fd524..27c37b3d1dad 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -6,3 +6,4 @@ generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
diff --git a/arch/score/include/asm/Kbuild b/arch/score/include/asm/Kbuild
index 83ed116d414c..16958f529aa7 100644
--- a/arch/score/include/asm/Kbuild
+++ b/arch/score/include/asm/Kbuild
@@ -13,3 +13,4 @@ generic-y += sections.h
 generic-y += trace_clock.h
 generic-y += xor.h
 generic-y += serial.h
+generic-y += word-at-a-time.h
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index f5433e0e34e0..0804122e579a 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -39,4 +39,5 @@ generic-y += termbits.h
 generic-y += termios.h
 generic-y += trace_clock.h
 generic-y += types.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild
index 9176fa11d49b..ee02364d8922 100644
--- a/arch/um/include/asm/Kbuild
+++ b/arch/um/include/asm/Kbuild
@@ -26,4 +26,5 @@ generic-y += sections.h
 generic-y += switch_to.h
 generic-y += topology.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index 3e0c19d0f4c5..f456bfa1dd54 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -62,4 +62,5 @@ generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index 86a9ab2e2ca9..6ac0a9ab3ea3 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -29,4 +29,5 @@ generic-y += statfs.h
 generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
+generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
index 94f9ea8abcae..011dde083f23 100644
--- a/include/asm-generic/word-at-a-time.h
+++ b/include/asm-generic/word-at-a-time.h
@@ -1,15 +1,10 @@
 #ifndef _ASM_WORD_AT_A_TIME_H
 #define _ASM_WORD_AT_A_TIME_H
 
-/*
- * This says "generic", but it's actually big-endian only.
- * Little-endian can use more efficient versions of these
- * interfaces, see for example
- *	 arch/x86/include/asm/word-at-a-time.h
- * for those.
- */
-
 #include <linux/kernel.h>
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
 
 struct word_at_a_time {
 	const unsigned long high_bits, low_bits;
@@ -53,4 +48,73 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
 #define zero_bytemask(mask) (~1ul << __fls(mask))
 #endif
 
+#else
+
+/*
+ * The optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+struct word_at_a_time {
+	const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+	return mask*0x0001020304050608ul >> 56;
+}
+
+#else	/* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+	/* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+	long a = (0x0ff0001+mask) >> 23;
+	/* Fix the 1 for 00 case */
+	return a & mask;
+}
+
+#endif
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+	unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+	*bits = mask;
+	return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+	return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+	bits = (bits - 1) & ~bits;
+	return bits >> 7;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+	return count_masked_bytes(mask);
+}
+
+#endif /* __BIG_ENDIAN */
+
 #endif /* _ASM_WORD_AT_A_TIME_H */
-- 
2.1.2


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

* [PATCH v2 2/3] string: provide strscpy()
  2015-07-08 20:20   ` [PATCH v2 0/3] add new strscpy() API for string copy Chris Metcalf
  2015-07-08 20:20     ` [PATCH v2 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
@ 2015-07-08 20:20     ` Chris Metcalf
  2015-07-08 20:54       ` Geert Uytterhoeven
  2015-07-08 20:20     ` [PATCH v2 3/3] tile: use global strscpy() rather than private copy Chris Metcalf
  2 siblings, 1 reply; 35+ messages in thread
From: Chris Metcalf @ 2015-07-08 20:20 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely, Dan Carpenter,
	Geert Uytterhoeven, Michael Ellerman, Linux Kernel Mailing List,
	linux-arch

The strscpy() API is intended to be used instead of strlcpy(),
and instead of most uses of strncpy().

- Unlike strlcpy(), it doesn't read from memory beyond (src + size).

- Unlike strlcpy() or strncpy(), the API provides an easy way to check
  for destination buffer overflow: an -E2BIG error return value.

- The provided implementation is robust in the face of the source
  buffer being asynchronously changed during the copy, unlike the
  current implementation of strlcpy().

- Unlike strncpy(), the destination buffer will be NUL-terminated
  if the string in the source buffer is too long.

- Also unlike strncpy(), the destination buffer will not be updated
  beyond the NUL termination, avoiding strncpy's behavior of zeroing
  the entire tail end of the destination buffer.  (A memset() after
  the strscpy() can be used if this behavior is desired.)

- The implementation should be reasonably performant on all
  platforms since it uses the asm/word-at-a-time.h API rather than
  simple byte copy.  Kernel-to-kernel string copy is not considered
  to be performance critical in any case.

Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
---
 include/linux/string.h |  3 ++
 lib/string.c           | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index e40099e585c9..213274a0d356 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -25,6 +25,9 @@ extern char * strncpy(char *,const char *, __kernel_size_t);
 #ifndef __HAVE_ARCH_STRLCPY
 size_t strlcpy(char *, const char *, size_t);
 #endif
+#ifndef __HAVE_ARCH_STRSCPY
+ssize_t __must_check strscpy(char *, const char *, size_t);
+#endif
 #ifndef __HAVE_ARCH_STRCAT
 extern char * strcat(char *, const char *);
 #endif
diff --git a/lib/string.c b/lib/string.c
index a5792019193c..0ff54eb78f52 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -27,6 +27,10 @@
 #include <linux/bug.h>
 #include <linux/errno.h>
 
+#include <asm/byteorder.h>
+#include <asm/word-at-a-time.h>
+#include <asm/page.h>
+
 #ifndef __HAVE_ARCH_STRNCASECMP
 /**
  * strncasecmp - Case insensitive, length-limited string comparison
@@ -146,6 +150,90 @@ size_t strlcpy(char *dest, const char *src, size_t size)
 EXPORT_SYMBOL(strlcpy);
 #endif
 
+#ifndef __HAVE_ARCH_STRSCPY
+/**
+ * strscpy - Copy a C-string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: Size of destination buffer
+ *
+ * Copy the string, or as much of it as fits, into the dest buffer.
+ * The routine returns the number of characters copied (not including
+ * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough.
+ * The behavior is undefined if the string buffers overlap.
+ * If the destination buffer isn't big enough, it is NUL terminated.
+ *
+ * Preferred to strlcpy() since the API doesn't require reading memory
+ * from the src string beyond the specified "count" bytes, and since
+ * the return value is easier to error-check than strlcpy()'s.
+ * In addition, the implementation is robust to the string changing out
+ * from underneath it, unlike the current strlcpy() implementation.
+ *
+ * Preferred to strncpy() since it always returns a valid string, and
+ * doesn't unnecessarily force the tail of the destination buffer to be
+ * zeroed.  If the zeroing is desired, it's likely cleaner to use strscpy()
+ * with an overflow test, then just memset() the tail of the dest buffer.
+ */
+ssize_t strscpy(char *dest, const char *src, size_t count)
+{
+	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+	size_t max = count;
+	long res = 0;
+
+	if (count == 0)
+		return -E2BIG;
+
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	/*
+	 * If src is unaligned, don't cross a page boundary,
+	 * since we don't know if the next page is mapped.
+	 */
+	if ((long)src & (sizeof(long) - 1)) {
+		size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1));
+		if (limit < max)
+			max = limit;
+	}
+#else
+	/* If src or dest is unaligned, don't do word-at-a-time. */
+	if (((long) dest | (long) src) & (sizeof(long) - 1))
+		max = 0;
+#endif
+
+	while (max >= sizeof(unsigned long)) {
+		unsigned long c, data;
+
+		c = *(unsigned long *)(src+res);
+		*(unsigned long *)(dest+res) = c;
+		if (has_zero(c, &data, &constants)) {
+			data = prep_zero_mask(c, data, &constants);
+			data = create_zero_mask(data);
+			return res + find_zero(data);
+		}
+		res += sizeof(unsigned long);
+		count -= sizeof(unsigned long);
+		max -= sizeof(unsigned long);
+	}
+
+	while (count) {
+		char c;
+
+		c = src[res];
+		dest[res] = c;
+		if (!c)
+			return res;
+		res++;
+		count--;
+	}
+
+	/* Hit buffer length without finding a NUL; force NUL-termination. */
+	if (res)
+		dest[res-1] = '\0';
+
+	return -E2BIG;
+}
+EXPORT_SYMBOL(strscpy);
+#endif
+
 #ifndef __HAVE_ARCH_STRCAT
 /**
  * strcat - Append one %NUL-terminated string to another
-- 
2.1.2


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

* [PATCH v2 3/3] tile: use global strscpy() rather than private copy
  2015-07-08 20:20   ` [PATCH v2 0/3] add new strscpy() API for string copy Chris Metcalf
  2015-07-08 20:20     ` [PATCH v2 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
  2015-07-08 20:20     ` [PATCH v2 2/3] string: provide strscpy() Chris Metcalf
@ 2015-07-08 20:20     ` Chris Metcalf
  2 siblings, 0 replies; 35+ messages in thread
From: Chris Metcalf @ 2015-07-08 20:20 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Chris Metcalf, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, gregkh, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely, Dan Carpenter,
	Geert Uytterhoeven, Michael Ellerman, Linux Kernel Mailing List,
	linux-arch

Now that strscpy() is a standard API, remove the local copy.

Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
---
 arch/tile/gxio/mpipe.c | 33 ++++-----------------------------
 1 file changed, 4 insertions(+), 29 deletions(-)

diff --git a/arch/tile/gxio/mpipe.c b/arch/tile/gxio/mpipe.c
index ee186e13dfe6..f102048d9c0e 100644
--- a/arch/tile/gxio/mpipe.c
+++ b/arch/tile/gxio/mpipe.c
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/string.h>
 
 #include <gxio/iorpc_globals.h>
 #include <gxio/iorpc_mpipe.h>
@@ -29,32 +30,6 @@
 /* HACK: Avoid pointless "shadow" warnings. */
 #define link link_shadow
 
-/**
- * strscpy - Copy a C-string into a sized buffer, but only if it fits
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
- * @size: size of destination buffer
- *
- * Use this routine to avoid copying too-long strings.
- * The routine returns the total number of bytes copied
- * (including the trailing NUL) or zero if the buffer wasn't
- * big enough.  To ensure that programmers pay attention
- * to the return code, the destination has a single NUL
- * written at the front (if size is non-zero) when the
- * buffer is not big enough.
- */
-static size_t strscpy(char *dest, const char *src, size_t size)
-{
-	size_t len = strnlen(src, size) + 1;
-	if (len > size) {
-		if (size)
-			dest[0] = '\0';
-		return 0;
-	}
-	memcpy(dest, src, len);
-	return len;
-}
-
 int gxio_mpipe_init(gxio_mpipe_context_t *context, unsigned int mpipe_index)
 {
 	char file[32];
@@ -540,7 +515,7 @@ int gxio_mpipe_link_instance(const char *link_name)
 	if (!context)
 		return GXIO_ERR_NO_DEVICE;
 
-	if (strscpy(name.name, link_name, sizeof(name.name)) == 0)
+	if (strscpy(name.name, link_name, sizeof(name.name)) < 0)
 		return GXIO_ERR_NO_DEVICE;
 
 	return gxio_mpipe_info_instance_aux(context, name);
@@ -559,7 +534,7 @@ int gxio_mpipe_link_enumerate_mac(int idx, char *link_name, uint8_t *link_mac)
 
 	rv = gxio_mpipe_info_enumerate_aux(context, idx, &name, &mac);
 	if (rv >= 0) {
-		if (strscpy(link_name, name.name, sizeof(name.name)) == 0)
+		if (strscpy(link_name, name.name, sizeof(name.name)) < 0)
 			return GXIO_ERR_INVAL_MEMORY_SIZE;
 		memcpy(link_mac, mac.mac, sizeof(mac.mac));
 	}
@@ -576,7 +551,7 @@ int gxio_mpipe_link_open(gxio_mpipe_link_t *link,
 	_gxio_mpipe_link_name_t name;
 	int rv;
 
-	if (strscpy(name.name, link_name, sizeof(name.name)) == 0)
+	if (strscpy(name.name, link_name, sizeof(name.name)) < 0)
 		return GXIO_ERR_NO_DEVICE;
 
 	rv = gxio_mpipe_link_open_aux(context, name, flags);
-- 
2.1.2


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

* Re: [PATCH v2 2/3] string: provide strscpy()
  2015-07-08 20:20     ` [PATCH v2 2/3] string: provide strscpy() Chris Metcalf
@ 2015-07-08 20:54       ` Geert Uytterhoeven
  0 siblings, 0 replies; 35+ messages in thread
From: Geert Uytterhoeven @ 2015-07-08 20:54 UTC (permalink / raw)
  To: Chris Metcalf
  Cc: Linus Torvalds, Al Viro, Fabian Frederick, Randy Dunlap,
	Rickard Strandqvist, Greg KH, Peter Zijlstra, David S. Miller,
	Frederic Weisbecker, Andrew Morton, Sam Ravnborg,
	Stephen Rothwell, Theodore Ts'o, Grant Likely, Dan Carpenter,
	Michael Ellerman, Linux Kernel Mailing List, Linux-Arch

Hi Chris,

On Wed, Jul 8, 2015 at 10:20 PM, Chris Metcalf <cmetcalf@ezchip.com> wrote:
> + * strscpy - Copy a C-string into a sized buffer
> + * @dest: Where to copy the string to
> + * @src: Where to copy the string from
> + * @count: Size of destination buffer
> + *
> + * Copy the string, or as much of it as fits, into the dest buffer.
> + * The routine returns the number of characters copied (not including
> + * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough.
> + * The behavior is undefined if the string buffers overlap.
> + * If the destination buffer isn't big enough, it is NUL terminated.

... unless count is zero

and it's also NUL terminated if it is big enough ;-)

Perhaps
"The destination buffer is always NUL terminated, unless it's zero-sized."

> + *
> + * Preferred to strlcpy() since the API doesn't require reading memory
> + * from the src string beyond the specified "count" bytes, and since
> + * the return value is easier to error-check than strlcpy()'s.
> + * In addition, the implementation is robust to the string changing out
> + * from underneath it, unlike the current strlcpy() implementation.
> + *
> + * Preferred to strncpy() since it always returns a valid string, and
> + * doesn't unnecessarily force the tail of the destination buffer to be
> + * zeroed.  If the zeroing is desired, it's likely cleaner to use strscpy()
> + * with an overflow test, then just memset() the tail of the dest buffer.
> + */
> +ssize_t strscpy(char *dest, const char *src, size_t count)
> +{
> +       const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
> +       size_t max = count;
> +       long res = 0;
> +
> +       if (count == 0)
> +               return -E2BIG;

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

end of thread, other threads:[~2015-07-08 20:54 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-28  3:48 revert "fs/befs/linuxvfs.c: replace strncpy by strlcpy" Al Viro
2015-04-28  5:35 ` Fabian Frederick
2015-04-28 16:05   ` Al Viro
2015-04-28 16:42     ` Fabian Frederick
2015-04-28 17:39       ` Al Viro
2015-04-28 20:16         ` Fabian Frederick
2015-04-28 16:42     ` Linus Torvalds
2015-04-28 19:48       ` Chris Metcalf
2015-04-28 20:51         ` Linus Torvalds
2015-04-28 21:38           ` Chris Metcalf
2015-04-28 21:48             ` Linus Torvalds
2015-04-29  0:35               ` Al Viro
2015-04-29  8:24                 ` Geert Uytterhoeven
2015-04-30 16:01               ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
2015-04-30 16:01                 ` [PATCH 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
2015-04-30 16:01                 ` [PATCH 2/3] string: provide strscpy() and strscpy_truncate() Chris Metcalf
2015-05-06 15:01                   ` Dan Carpenter
2015-05-06 15:21                     ` Chris Metcalf
2015-05-06 15:59                       ` Dan Carpenter
2015-05-06 16:45                         ` Geert Uytterhoeven
2015-05-07  9:00                           ` Dan Carpenter
2015-05-07 15:10                             ` Chris Metcalf
2015-04-30 16:01                 ` [PATCH 3/3] tile: use global strscpy() rather than private copy Chris Metcalf
2015-05-11 15:37                 ` [PATCH 0/3] add new strscpy() API for string copy Chris Metcalf
2015-05-14 23:10                 ` Michael Ellerman
2015-05-15 15:15                   ` Chris Metcalf
2015-05-18  1:13                     ` Michael Ellerman
2015-05-26 19:33                       ` Chris Metcalf
2015-06-30 18:01 [GIT PULL] strscpy string copy function Chris Metcalf
2015-07-01 16:11 ` Linus Torvalds
2015-07-08 20:20   ` [PATCH v2 0/3] add new strscpy() API for string copy Chris Metcalf
2015-07-08 20:20     ` [PATCH v2 1/3] Make asm/word-at-a-time.h available on all architectures Chris Metcalf
2015-07-08 20:20     ` [PATCH v2 2/3] string: provide strscpy() Chris Metcalf
2015-07-08 20:54       ` Geert Uytterhoeven
2015-07-08 20:20     ` [PATCH v2 3/3] tile: use global strscpy() rather than private copy Chris Metcalf

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