linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Petr Mladek <pmladek@suse.com>
To: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	"Tobin C . Harding" <me@tobin.cc>, Joe Perches <joe@perches.com>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Michal Hocko <mhocko@suse.cz>,
	Sergey Senozhatsky <sergey.senozhatsky@gmail.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Subject: Re: [PATCH v3] vsprintf: Prevent crash when dereferencing invalid pointers
Date: Thu, 15 Mar 2018 16:07:54 +0100	[thread overview]
Message-ID: <20180315150754.qeshnhmtnob2jhxs@pathway.suse.cz> (raw)
In-Reply-To: <0c52c2f1-60d8-bb8a-80f2-c699d47659d3@rasmusvillemoes.dk>

On Wed 2018-03-14 23:12:36, Rasmus Villemoes wrote:
> On 2018-03-14 15:09, Petr Mladek wrote:
> 
> > diff --git a/lib/test_printf.c b/lib/test_printf.c
> > index 71ebfa43ad05..61c05a352d79 100644
> > --- a/lib/test_printf.c
> > +++ b/lib/test_printf.c
> > @@ -207,14 +207,15 @@ test_string(void)
> > @@ -256,18 +259,18 @@ plain_hash(void)
> >   * after an address is hashed.
> >   */
> >  static void __init
> > -plain(void)
> > +plain(void *ptr)
> >  {
> >  	int err;
> >  
> > -	err = plain_hash();
> > +	err = plain_hash(ptr);
> >  	if (err) {
> >  		pr_warn("plain 'p' does not appear to be hashed\n");
> >  		failed_tests++;
> >  		return;
> >  	}
> >  
> > -	err = plain_format();
> > +	err = plain_format(ptr);
> >  	if (err) {
> >  		pr_warn("hashing plain 'p' has unexpected format\n");
> >  		failed_tests++;
> > @@ -275,6 +278,24 @@ plain(void)
> >  }
> 
> Thanks for adding tests. Please increment total_tests for each test case.

Good point! Will do in v4.

> >  static void __init
> > +null_pointer(void)
> > +{
> > +	plain(NULL);
> > +	test(ZEROS "00000000", "%px", NULL);
> > +	test(SPACE "  (null)", "%pC", NULL);
> > +}
> 
> Hm, %pC depends on CONFIG_CLOCK, not that we ever reach clock() with
> these invalid pointers, but perhaps clearer to choose one whose
> behaviour is not config-dependent.

It is not a real problem, but I could select another "random" one for v4.

BTW: I chosen "%pC" because clock was a basic word that anyone could
understand ;-) Otherwise, "%pC" is always handled and the purpose of the
specifier is to access the data. IMHO, it does not make sense to make
it too complicated and avoid the access check when CONFIG_CLOCK is not
enabled.

The only specifier that is optionally handled is "%pg". And I think
that it is wrong. It is strange when 'g' is sometimes handled as
specifier and sometimes part of the output string. Well, it is
not a big deal. Who would want to print something like "hello, %pgroup"?

Anyway, you made me to look at clock() more closely. The
implementation is questionable:

  + it always printks "(null)" when CONFIG_HAVE_CLK is not enabled.
    This might hide an error.

  + it prints the address for plain "%pC" and "%pCn" when
    CONFIG_COMMON_CLK is not enabled. We should rather print
    the pointer hash or some error string.

Andy Shevchenko plans to do some clean up on top of this patch.
We could sort it there.


> > diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> > index d7a708f82559..54b985143e07 100644
> > --- a/lib/vsprintf.c
> > +++ b/lib/vsprintf.c
> > @@ -520,6 +520,19 @@ char *number(char *buf, char *end, unsigned long long num,
> >  	return buf;
> >  }
> >  
> > +static const char *check_pointer_access(const void *ptr)
> > +{
> > +	unsigned char byte;
> > +
> > +	if (!ptr)
> > +		return "(null)";
> > +
> > +	if (probe_kernel_read(&byte, ptr, 1))
> > +		return "(efault)";
> > +
> > +	return 0;
> > +}
> 
> return NULL;

Good catch! This is an artifact from an older variant where it returned int.

> > +
> >  static noinline_for_stack
> >  char *special_hex_number(char *buf, char *end, unsigned long long num, int size)
> >  {
> > @@ -1847,16 +1862,22 @@ static noinline_for_stack
> >  char *pointer(const char *fmt, char *buf, char *end, void *ptr,
> >  	      struct printf_spec spec)
> >  {
> > +	static const char data_access_fmt[] = "RrhbM mIiEU VNadC DgGO";
> >  	const int default_width = 2 * sizeof(void *);
> > +	const char *err_msg = NULL;
> > +
> > +	/* Prevent silent crash when this is called under logbuf_lock. */
> > +	if (*fmt && strchr(data_access_fmt, *fmt) != NULL)
> > +		err_msg = check_pointer_access(ptr);
> 
> Can we please make this more readable and maintainable in case other
> fancy %p* stuff is added. The extensions which do dereference ptr
> outnumber those which don't, and a new one is also likely to fall in
> that category. Something like
> 
> static bool extension_dereferences_ptr(const char *fmt)
> {
>   switch(*fmt) {
>   case 'x':
>   case 'K':
>   case 'F':
>   case 'f':
>   case 'S':
>   case 's':
>   case 'B':
>     return false;
>   default:
>     return isalnum(*fmt);
>   }
> }
> 
> which you could spell isalnum(*fmt) && !strchr("xKFfSsB", *fmt), but
> having a switch is a closer match to the subsequent dispatching (and
> would allow a more fine-grained approach should the answer depend on
> fmt[1] as well).

The thing is that *fmt points to the original format. It might be
something like: "print%ponscreen". It will be handled as "%p" because
'o' is not valid specifier. But your function would return true.

To be honest, I cannot imagine reasonable real-life example where
the above implementation might fail. On the other hand, there are
currently 19 specifiers where we do the dereference. It means the
your simplified approach has 36 false positives. People might be
creative, ... So I prefer to avoid false positives.


> Question: probe_kernel_read seems to allow (mapped) userspace addresses.
> Is that really what we want? Sure, some %p* just format the pointed-to
> bytes directly (as an IP address or raw hex dump or whatnot), but some
> (e.g. %pD, and %pV could be particularly fun) do another dereference.
> I'm not saying it would be easy for an attacker to get a userpointer
> passed to %pV, but there's a lot of places that end up calling vsnprintf
> (not just printk and friends). Isn't there some cheap address comparison
> one can do to rule that out completely?

Good point. The following should do the job:

static const char *check_pointer_access(const void *ptr)
{
	char c;

	if (!ptr)
		return "(null)";

	if ((unsigned long)ptr < TASK_SIZE || probe_kernel_address(ptr, c))
		return "(efault)";

	return 0;
}

Best Regards,
Petr

  reply	other threads:[~2018-03-15 15:07 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-16 21:07 [PATCH v2 1/9] lib/test_printf: Mark big constant with ULL Andy Shevchenko
2018-02-16 21:07 ` [PATCH v2 2/9] lib/vsprintf: Make dec_spec global Andy Shevchenko
2018-04-11  9:44   ` Petr Mladek
2018-02-16 21:07 ` [PATCH v2 3/9] lib/vsprintf: Make strspec global Andy Shevchenko
2018-04-11  9:44   ` Petr Mladek
2018-02-16 21:07 ` [PATCH v2 4/9] lib/vsprintf: Make flag_spec global Andy Shevchenko
2018-04-11  9:45   ` Petr Mladek
2018-02-16 21:07 ` [PATCH v2 5/9] lib/vsprintf: Move pointer_string() upper Andy Shevchenko
2018-04-11  9:45   ` Petr Mladek
2018-02-16 21:07 ` [PATCH v2 6/9] lib/vsprintf: Deduplicate pointer_string() Andy Shevchenko
2018-04-11  9:46   ` Petr Mladek
2018-02-16 21:07 ` [PATCH v2 7/9] lib/vsprintf: Replace space with '_' before crng is ready Andy Shevchenko
2018-02-20  2:57   ` [此邮件可能存在风险] " Yang, Shunyong
2018-04-11  9:47   ` Petr Mladek
2018-02-16 21:07 ` [PATCH v2 8/9] lib/vsprintf: Remove useless NULL checks Andy Shevchenko
2018-02-27 15:50   ` Petr Mladek
2018-02-27 17:35     ` Andy Shevchenko
2018-02-28 10:04       ` Petr Mladek
2018-02-28 10:42         ` Andy Shevchenko
2018-03-02 12:51           ` Petr Mladek
2018-03-02 12:53             ` [PATCH] vsprintf: Make "null" pointer dereference more robust Petr Mladek
2018-03-02 14:17               ` Andy Shevchenko
2018-03-05 14:53                 ` Petr Mladek
2018-03-29 15:13                 ` Petr Mladek
2018-03-29 16:11                   ` Joe Perches
2018-03-05 15:16               ` Rasmus Villemoes
2018-03-05 15:25                 ` Andy Shevchenko
2018-03-06  9:25                 ` Petr Mladek
2018-03-06  9:56                   ` Andy Shevchenko
2018-03-07 15:52                     ` Petr Mladek
2018-03-07 18:18                       ` Andy Shevchenko
2018-03-07 18:34                       ` Linus Torvalds
2018-03-08 14:18                         ` Petr Mladek
2018-03-08 16:45                           ` Linus Torvalds
2018-03-08 17:26                             ` Linus Torvalds
2018-03-09 15:01                               ` Petr Mladek
2018-03-09 19:05                                 ` Linus Torvalds
2018-03-14 14:09                                   ` [PATCH v3] vsprintf: Prevent crash when dereferencing invalid pointers Petr Mladek
2018-03-14 22:12                                     ` Rasmus Villemoes
2018-03-15 15:07                                       ` Petr Mladek [this message]
2018-03-15 17:07                                         ` Steven Rostedt
2018-03-15 17:06                                       ` Steven Rostedt
2018-03-15  0:57                                     ` Sergey Senozhatsky
2018-03-15  7:58                                     ` Sergey Senozhatsky
2018-03-15  8:03                                       ` Sergey Senozhatsky
2018-03-15 17:01                                         ` Steven Rostedt
2018-03-16  1:18                                           ` Sergey Senozhatsky
2018-03-16  1:35                                             ` Linus Torvalds
2018-03-16  5:53                                               ` Sergey Senozhatsky
2018-03-16  8:55                                                 ` Petr Mladek
2018-03-16 14:32                                                   ` Steven Rostedt
2018-03-17  1:29                                                   ` Sergey Senozhatsky
2018-03-15 13:07                                       ` Andy Shevchenko
2018-03-15 13:09                                     ` Andy Shevchenko
2018-03-15 15:26                                       ` Petr Mladek
2018-03-16 18:19                                         ` Andy Shevchenko
2018-03-29 14:53                                           ` Petr Mladek
2018-04-02 14:15                                             ` Andy Shevchenko
2018-04-03  1:12                                               ` Sergey Senozhatsky
2018-04-03 11:52                                                 ` Petr Mladek
2018-04-03 11:56                                                   ` Andy Shevchenko
2018-04-03 13:57                                                   ` Sergey Senozhatsky
2018-04-03 11:46                                               ` Petr Mladek
2018-04-03 11:54                                                 ` Andy Shevchenko
2018-04-03 13:13                                                   ` Petr Mladek
2018-04-03 13:40                                                     ` Andy Shevchenko
2018-04-03 14:50                                                       ` Petr Mladek
2018-03-15 14:48                                     ` kbuild test robot
2018-03-15 20:26                                     ` kbuild test robot
2018-03-06 18:11                   ` [PATCH 1/2] vsprintf: distinguish between (null), (err) and (invalid) pointer derefs Adam Borowski
2018-03-06 18:11                     ` [PATCH 2/2] vsprintf: don't dereference pointers to the first or last page Adam Borowski
2018-03-07 13:22                       ` Andy Shevchenko
2018-03-07 13:17                     ` [PATCH 1/2] vsprintf: distinguish between (null), (err) and (invalid) pointer derefs Andy Shevchenko
2018-03-07 13:42                       ` Adam Borowski
2018-03-07 13:29                     ` Andy Shevchenko
2018-03-02 14:15             ` [PATCH v2 8/9] lib/vsprintf: Remove useless NULL checks Andy Shevchenko
2018-03-05 14:57               ` Petr Mladek
2018-02-28 10:44         ` Andy Shevchenko
2018-03-01 14:56         ` Andy Shevchenko
2018-02-16 21:07 ` [PATCH v2 9/9] lib/vsprintf: Mark expected switch fall-through Andy Shevchenko
2018-04-11  9:47   ` Petr Mladek
2018-02-18 12:58 ` [PATCH v2 1/9] lib/test_printf: Mark big constant with ULL Luc Van Oostenryck
2018-02-18 14:20   ` Andy Shevchenko
2018-02-19 15:24   ` Andy Shevchenko
2018-04-11  9:41     ` Petr Mladek
2018-02-18 21:52 ` Tobin C. Harding
2018-02-18 23:55   ` Andy Shevchenko

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=20180315150754.qeshnhmtnob2jhxs@pathway.suse.cz \
    --to=pmladek@suse.com \
    --cc=akpm@linux-foundation.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=joe@perches.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=me@tobin.cc \
    --cc=mhocko@suse.cz \
    --cc=rostedt@goodmis.org \
    --cc=sergey.senozhatsky.work@gmail.com \
    --cc=sergey.senozhatsky@gmail.com \
    --cc=torvalds@linux-foundation.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 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).