linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Peter Seebach <peter.seebach@windriver.com>
To: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>,
	Anton Blanchard <anton@samba.org>, <paulus@samba.org>,
	<peterz@infradead.org>, <dsahern@gmail.com>, <fweisbec@gmail.com>,
	<yanmin_zhang@linux.intel.com>, <emunson@mgebm.net>,
	<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] perf: Incorrect use of snprintf results in SEGV
Date: Fri, 9 Mar 2012 13:00:09 -0600	[thread overview]
Message-ID: <20120309130009.1b1fc742@wrlaptop> (raw)
In-Reply-To: <20120308074837.GE20784@elte.hu>

On Thu, 8 Mar 2012 08:48:37 +0100
Ingo Molnar <mingo@elte.hu> wrote:
> Erm. Doing:
> 
> 	+= snprintf(...);
> 
> is a *very* common pattern within the kernel. It occurs more 
> than a thousand times - i.e. about 25% of all snprintf uses 
> (~5000 instances) within the kernel does care about the return 
> value.
> 
> I found only a single case that did a reallocation if the buffer 
> did not fit. Lets assume that I missed some and there's 4 
> altogether.

I came back to this, because I totally thought I saw one of the horse's
legs twitch out of the corner of my eye.

See, after this conversation, I decided to go audit some of my code,
and sure enough, I found a similar pattern -- I found a couple of
places where my code had this idiom, and did not reallocate.

And in both cases, it was *a bug* that the code did not attempt to
reallocate.

This led me to reevaluate my assumptions.  It appears to me that if you
have a buffer of a given size, and for some reason you have more data
than will fit in the buffer, you have four options:

1.  Scribble outside the buffer.
2.  Truncate the data.
3.  Reallocate a larger buffer.
4.  Report a failure.

In userspace code, I think it is probably nearly always an error to
truncate rather than reallocating.  I can't think of a case where
truncating would be better.  Reporting a failure may be reasonable in
some cases.

In the kernel, that's going to be a harder call -- there are probably
circumstances where reallocating is impractical.  But casually browsing
through the many cases where no attempt is made to reallocate, I
frequently find myself thinking "boy, truncating that would sorta suck."

The assumption that code reflects intended use is a completely
reasonable one, but on evaluating the code not for what it does, but
for what it probably ought to do, I find that there are many more cases
where the correct answer should be "get a larger buffer" rather than
"discard data or possibly cut off halfway through a word".

And in userspace, I don't think I've yet found a case where
reallocating isn't the right call.  (The C library was not really
designed with kernel requirements, such as the possibility that
allocation might not be an option, in mind.)

So I think a sample of how snprintf() *is* used is not the right way to
determine the "common" use case to design for.  So far as I can tell,
in nearly all cases you need to know whether snprintf needed more
space, and you probably *want* to know how much more it needed;
otherwise, you are silently producing corrupted data.  And indeed, most
of the APIs I checked that aren't correctly checking whether snprintf
wanted to overflow are, as a result, potentially returning bogus data.

For a specific example, consider mm/mempolicy.c:

        if (flags & MPOL_MODE_FLAGS) {
                if (buffer + maxlen < p + 2)
                        return -ENOSPC;
                *p++ = '=';
                /*
                 * Currently, the only defined flags are mutually
                exclusive */
                if (flags & MPOL_F_STATIC_NODES)
                        p += snprintf(p, buffer + maxlen - p, "static");
	...

This code clearly takes great care to ensure that it returns -ENOSPC
if there isn't enough space, but does not check that the result of the
snprintf call was in range.  Failure to check this is a bug.  Because
the code is full of other careful checks, it won't result in
scribbling, but it could result in returning a buffer which ends with
"=sta" and reporting too high a length for it.

So studying the code has left me convinced that the snprintf()
interface is the right interface, and that the usage errors
you've identified are bugs, not because snprintf() returns the wrong
value, but because they are failures to check for a condition which
needs to be handled.

-s
-- 
Listen, get this.  Nobody with a good compiler needs to be justified.

  parent reply	other threads:[~2012-03-09 19:00 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-07  0:42 [PATCH] perf: Incorrect use of snprintf results in SEGV Anton Blanchard
2012-03-07  0:49 ` Peter Seebach
2012-03-07  1:09 ` Arnaldo Carvalho de Melo
2012-03-07  1:29   ` Peter Seebach
2012-03-07 18:44     ` Nick Bowler
2012-03-07 20:24       ` Peter Seebach
2012-03-07 20:37     ` Ingo Molnar
2012-03-07 20:59       ` Peter Zijlstra
2012-03-07 21:28         ` Peter Seebach
2012-03-08  7:34         ` Ingo Molnar
2012-03-08  8:51           ` Peter Seebach
2012-03-07 21:19       ` Peter Seebach
2012-03-08  0:58         ` Arnaldo Carvalho de Melo
2012-03-08  7:48         ` Ingo Molnar
2012-03-08  7:52           ` Ingo Molnar
2012-03-09 19:00           ` Peter Seebach [this message]
2012-03-14 19:59 ` [tip:perf/urgent] perf tools: " tip-bot for Anton Blanchard

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=20120309130009.1b1fc742@wrlaptop \
    --to=peter.seebach@windriver.com \
    --cc=acme@redhat.com \
    --cc=anton@samba.org \
    --cc=dsahern@gmail.com \
    --cc=emunson@mgebm.net \
    --cc=fweisbec@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=paulus@samba.org \
    --cc=peterz@infradead.org \
    --cc=yanmin_zhang@linux.intel.com \
    /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).