mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
To: linux-kernel@vger.kernel.org
Cc: Tejun Heo <tj@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Alexey Dobriyan <adobriyan@gmail.com>
Subject: [PATCH v1 3/6] lib: scanf: add vsscanf feature for matching end of text
Date: Sun, 10 Mar 2019 19:56:34 +0300	[thread overview]
Message-ID: <155223699475.4075.10085989782784489732.stgit@buzz> (raw)
In-Reply-To: <155223448227.4075.6846910559654700796.stgit@buzz>

Traditional sscanf ignores trailing unmatched characters,
because it derives from design of streaming fscanf().

Without extra care this leads to confusing parsing results:
"%d" successfully parses "0x1" as 0 and "1M" as 1.

Silent ignore of trailing input also could hide bugs and
unexpectedly break backward compatibility at any change.

This patch adds end of text matching into sscanf format by
ASCII End-Of-Transfer character '\004' (EOT aka ^D).

EOT stops matching and if input text haven't ended and adds
flag SCANF_MORE to the result value. Result stays positive.

EOT allows to rephrase common end of text checks like:

int end;
if (sscanf(buf, fmt "%n", ..., &end) == NR && !buf[end])

char dummy;
if (sscanf(buf, fmt "%c", ..., &dummy) == NR - 1)

purely in format string without extra code or arguments:

if (sscanf(buf, fmt KERN_EOT, ...) == NR)

This checks that text ends strictly after previous matched character.
For skipping trailing white spaces simply add space before EOT.

Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
---
 include/linux/kernel.h |    6 ++++++
 lib/vsprintf.c         |   11 ++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 34a5036debd3..32726b25eaa5 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -476,6 +476,12 @@ char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
 extern __printf(2, 0)
 const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list args);
 
+#define KERN_EOT	"\004"	/* ASCII End Of Transfer */
+#define KERN_EOT_ASCII	'\004'
+
+/* sscanf adds this to the result if EOT does not match end of text */
+#define SCANF_MORE	(1 << 30)
+
 extern __scanf(2, 3)
 int sscanf(const char *, const char *, ...);
 extern __scanf(2, 0)
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index ada0501f1525..66debf42387a 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -3005,7 +3005,8 @@ EXPORT_SYMBOL_GPL(bprintf);
  * @fmt:	format of buffer
  * @args:	arguments
  *
- * Returns number of successfully matched arguments.
+ * Returns number of successfully matched arguments,
+ * plus SCANF_MORE bit flag if EOT does not matched end of text.
  *
  * This function implements only basic vsscanf features:
  *
@@ -3027,6 +3028,8 @@ EXPORT_SYMBOL_GPL(bprintf);
  * - %s without field width limited with SHRT_MAX
  * - "%*..." simply skips non white-space characters without conversion
  * - integer overflows are handled as matching failure
+ * - KERN_EOT ("\004") matches end of string otherwise stops parsing and
+ *   returns count matched arguments plus SCANF_MORE bit flag,
  */
 int vsscanf(const char *buf, const char *fmt, va_list args)
 {
@@ -3055,6 +3058,12 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
 
 		/* anything that is not a conversion must match exactly */
 		if (*fmt != '%' && *fmt) {
+			/* EOT in format string: text must end here */
+			if (*fmt == KERN_EOT_ASCII) {
+				if (*str)
+					num |= SCANF_MORE;
+				break;
+			}
 			if (*fmt++ != *str++)
 				break;
 			continue;


  parent reply	other threads:[~2019-03-10 16:56 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-10 16:56 [PATCH v1 0/6] Make sscanf safer Konstantin Khlebnikov
2019-03-10 16:56 ` [PATCH v1 1/6] lib: scanf: document features of scanf format string Konstantin Khlebnikov
2019-03-10 16:56 ` [PATCH v1 2/6] lib: scanf: handle integer overflows in vsscanf Konstantin Khlebnikov
2019-03-10 21:06   ` Rasmus Villemoes
2019-03-10 21:52     ` Linus Torvalds
2019-03-11  7:22       ` Konstantin Khlebnikov
2019-03-10 16:56 ` Konstantin Khlebnikov [this message]
2019-03-10 16:56 ` [PATCH v1 4/6] lib: scanf: handle character ranges in %[...] Konstantin Khlebnikov
2019-03-10 16:56 ` [PATCH v1 5/6] lib: scanf: mark sscanf and vsscanf as __must_check Konstantin Khlebnikov
2019-03-10 16:56 ` [PATCH v1 6/6] lib: scanf: add test module Konstantin Khlebnikov

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=155223699475.4075.10085989782784489732.stgit@buzz \
    --to=khlebnikov@yandex-team.ru \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tj@kernel.org \
    --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

all inboxes | Powered by JetHome®