All of lore.kernel.org
 help / color / mirror / Atom feed
From: Francis Laniel <laniel_francis@privacyrequired.com>
To: Kees Cook <keescook@chromium.org>
Cc: linux-hardening@vger.kernel.org, Daniel Axtens <dja@axtens.net>
Subject: Re: [RFC][PATCH v2] Fortify string function strscpy.
Date: Wed, 21 Oct 2020 16:49:21 +0200	[thread overview]
Message-ID: <11802252.guoqaGusNR@machine> (raw)
In-Reply-To: <202010191606.72397DFC6E@keescook>

Le mardi 20 octobre 2020, 01:19:43 CEST Kees Cook a écrit :
> On Sat, Oct 17, 2020 at 11:22:04AM +0200, Francis Laniel wrote:
> > Le samedi 17 octobre 2020, 01:16:36 CEST Kees Cook a écrit :
> > > On Fri, Oct 16, 2020 at 02:38:09PM +0200,
> > > laniel_francis@privacyrequired.com> 
> > wrote:
> > > > From: Francis Laniel <laniel_francis@privacyrequired.com>
> > > > 
> > > > Thanks to kees advices (see:
> > > > https://github.com/KSPP/linux/issues/96#issuecomment-709620337) I
> > > > wrote a
> > > > LKDTM test for the fortified version of strscpy I added in the v1 of
> > > > this
> > > > patch. The test panics due to write overflow.
> > > 
> > > Ah nice, thanks! I am reminded about this series as well:
> > > https://lore.kernel.org/lkml/20200120045424.16147-1-dja@axtens.net
> > > I think we can likely do this all at the same time, merge the
> > > complementary pieces, etc.
> > 
> > You are welcome!
> > Just to be sure I understand correctly: you want me to add work of Daniel
> > Axtens to my local version, then add my modifications on top of his work
> > and republish the whole patch set?
> 
> Yup; I would rebase his, and then have your patches follow.
> 
> > > Notes below...
> > > 
> > > > Signed-off-by: Francis Laniel <laniel_francis@privacyrequired.com>
> > > > ---
> > > > 
> > > >  drivers/misc/lkdtm/Makefile  |  1 +
> > > >  drivers/misc/lkdtm/core.c    |  1 +
> > > >  drivers/misc/lkdtm/fortify.c | 37 +++++++++++++++++++++++++++++
> > > >  drivers/misc/lkdtm/lkdtm.h   | 17 ++++++++------
> > > 
> > > Yay tests! These should, however, be a separate patch.
> > 
> > Ok, I will separate it.
> > If I understand correctly: one semantic modification = one commit.
> 
> Right -- I'd like to see the tests be separate. Also, probably the new
> test should get added to tools/testing/selftests/lkdtm/tests.txt. I
> forgot to suggest that last time!

I separated my commit in three different for the v3.

> 
> > > > +/*
> > > > + * Calls fortified strscpy to generate a panic because there is a
> > > > write
> > > > + * overflow (i.e. src length is greater than dst length).
> > > > + */
> > > > +void lkdtm_FORTIFIED_STRSCPY(void)
> > > > +{
> > > > +#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) &&
> > > > defined(CONFIG_FORTIFY_SOURCE) +	char *src;
> > > > +	char dst[3];
> > > > +
> > > > +	src = kmalloc(7, GFP_KERNEL);
> > > > +	src[0] = 'f';
> > > > +	src[1] = 'o';
> > > > +	src[2] = 'o';
> > > > +	src[3] = 'b';
> > > > +	src[4] = 'a';
> > > > +	src[5] = 'r';
> > > > +	src[6] = '\0';
> > > 
> > > Hah, yes, I guess we need to bypass the common utilities. ;) I wonder if
> > > using __underlying_strcpy() might be easier.
> > 
> > I am sorry but I did not understand.
> > If we use here __underlying_strcpy() the function this will not profit
> > from the protection added in fortified version of strscpy()?
> 
> Sorry, I meant that instead open-coding the assignment, you could use
> __underlying_strcpy(). Better yet, now that I look at it, would be:
> 
> 	src = strdup("foobar", GFP_KERNEL);
> 
> Instead of the kmalloc and src[0], src[1] = ...

I did not think about strdup... It is now used in v3.

> > > > +
> > > > +	strscpy(dst, src, 1000);
> > > > +
> > > > +	kfree(dst);
> > > > +
> > > > +	pr_info("Fail: No overflow in above strscpy call!\n");
> > > > +#endif
> > > > +}
> > > 
> > > One thing I'd love to see is a _compile-time_ test too: but it needs to
> > > be a negative failure case, which Makefiles are not well suited to
> > > dealing with. e.g. something like:
> > > 
> > > good.o: nop.c bad.c
> > > 
> > > 	if $(CC) .... -o bad.o bad.c $< ; then exit 1; else $(CC) ... -o good.c
> > > 
> > > nop.c ; fi
> > > 
> > > I'm not sure how to do it.
> > 
> > This is a good idea, I though to it but I did not see an easy way to deal
> > with it.
> > I will investigate one it, but I cannot guarantee the next version will
> > come with this feature.
> 
> Yeah, this isn't required for the series; it's just me thinking out
> loud. It'd be really nice to validate the fortification on the compile
> side. Though, in following Linus's guidelines, it may need to be a
> warning, not a hard failure of the build. Hmm.

Should we redeclare __write_overflow() as a warning instead of an error?

> > > > +extern ssize_t __real_strscpy(char *, const char *, size_t)
> > > > __RENAME(strscpy); +__FORTIFY_INLINE ssize_t strscpy(char *p, const
> > > > char
> > > > *q, size_t count)
> > > > +{
> > > > +	size_t len;
> > > > +	size_t p_size = __builtin_object_size(p, 0);
> > > > +	size_t q_size = __builtin_object_size(q, 0);
> > > > +	/*
> > > > +	 * If p_size and q_size cannot be known at compile time we just had
> > > > to
> > > > +	 * trust this function caller.
> > > > +	 */
> > > > +	if (p_size == (size_t)-1 && q_size == (size_t)-1)
> > > > +		return __real_strscpy(p, q, count);
> > > > +	len = strlen(q);
> 
> I realize again that this needs to be strnlen(q, size), I think?
> Otherwise we're just repeating the flaws of strlcpy().

Using strnlen would save us when src does not contain '\0' so I replaced 
strlen by strnlen for v3.

> > > > +	if (count) {
> > > 
> > > This test isn't needed; it'll work itself out correctly. :P
> > 
> > Indeed, if this condition is met, __real_strscpy will be called later.
> > 
> > > > +		/* If count is bigger than INT_MAX, strscpy returns -E2BIG. */
> > > > +		if (WARN_ON_ONCE(count > INT_MAX))
> > > > +			return -E2BIG;
> > > 
> > > This is already handled in strscpy, I'd drop this here.
> > 
> > I though of it at first, but since the patch modify count/size before
> > giving it to __real_strscpy(), real one will never return -E2BIG due to
> > that. So removing this modification will lead to difference between
> > returned value of fortified strscpy() and __real_strscpy().
> 
> I think if you avoid modifying size, it'll work out correctly.

I removed all about modifying size for v3.
When I implemented that I though "you should recompute size here because 
strscpy can save you because it exits when '\0' is met".
Then I though about it and changed my mind because we need safety inside 
fortified version of strscpy and the maximum safety.

> > > > +		/*
> > > > +		 * strscpy handles read overflows by stop reading q when '\0' is
> > > > +		 * met.
> > > > +		 * We stick to this behavior here.
> > > > +		 */
> > > > +		len = (len >= count) ? count : len;
> > > > +		/*
> > > > +		 * If len can be known at compile time and is greater than
> > > > +		 * p_size, generate a compile time write overflow error.
> > > > +		 */
> > > > +		if (__builtin_constant_p(len) && len > p_size)
> > > 
> > > This won't work (len wasn't an argument and got assigned); you need:
> > > 		if (__builtin_constant_p(size) && p_size < size)
> > 
> > You are right, len is unknown at compile time... So, I will correct it for
> > next version!
> > 
> > > > +			__write_overflow();
> > > > +		/* Otherwise generate a runtime write overflow error. */
> > > > +		if (len > p_size)
> > > > +			fortify_panic(__func__);
> > > 
> > > I think this just needs to be:
> > > 		if (p_size < size)
> > > 		
> > > 			fortify_panic(__func__);
> > 
> > I am not really sure.
> > If p_size is 4, size is 1000 and q is "foo\0", then what you suggested
> > will
> > panic but there is not need to panic since __real_strscpy will truncate
> > size and copy just 4 bytes into p (because of '\0' in q).
> > Am I correct?
> 
> Hm, so, if p_size is 4 and size is __builtin_constant_p(), and p_size
> < size, it should fail to compile. (The wrong max size is proposed.)
> But yes, you're right, for the runtime case, if len < p_size, we shouldn't
> panic. But that means the test needs to be "len >= p_size"

I do not agree on the fact that the condition should be "len >= p_size".
Indeed, there is not write overflow when len equals p_size, src can just be 
truncated when written to dst.
When len is strictly greater than p_size, there is, for sure, a write overflow.

> > > > +		/*
> > > > +		 * Still use count as third argument to correctly compute max
> > > > +		 * inside strscpy.
> > > > +		 */
> > > > +		return __real_strscpy(p, q, count);
> > > > +	}
> > > > +	/* If count is 0, strscpy return -E2BIG. */
> > > > +	return -E2BIG;
> > > 
> > > I'd let __real_strscpy() handle this.
> > 
> > See my three times above comment.
> > __real_strscpy is called only if count > 0, so it will never return -E2BIG
> > due to this.
> > So it will lead to difference in returned value between fortified
> > strscpy() and __real_strscpy().
> 
> There are enough changes pending here that I'll wait for the next
> version to look at this part again. Regardless, we should at least have
> the tests described even if the compile-time ones can't be tested yet.

Normally the review for the next version should be easier.



      reply	other threads:[~2020-10-21 14:49 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-13 16:59 [RFC][PATCH v1] Fortify string function strscpy laniel_francis
2020-10-16 12:38 ` [RFC][PATCH v2] " laniel_francis
2020-10-16 23:16   ` Kees Cook
2020-10-17  9:22     ` Francis Laniel
2020-10-19 11:51       ` Daniel Axtens
2020-10-21 12:43         ` Francis Laniel
2020-10-19 23:19       ` Kees Cook
2020-10-21 14:49         ` Francis Laniel [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11802252.guoqaGusNR@machine \
    --to=laniel_francis@privacyrequired.com \
    --cc=dja@axtens.net \
    --cc=keescook@chromium.org \
    --cc=linux-hardening@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.