From a8e8f89998f1443d36f860c4d0e2fee3a1de5d7d Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 8 Apr 2019 13:33:04 +0200 Subject: [PATCH] libmount: don't use sscanf() for fstab parsing Addresses: https://github.com/karelzak/util-linux/issues/780 Signed-off-by: Karel Zak --- lib/mangle.c | 2 +- libmount/src/tab_parse.c | 135 ++++++++++++++++++++------------------- 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/lib/mangle.c b/lib/mangle.c index b61c57fcf0..b514cd8d35 100644 --- a/lib/mangle.c +++ b/lib/mangle.c @@ -96,7 +96,7 @@ size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len) static inline const char *skip_nonspaces(const char *s) { - while (*s && !(*s == ' ' || *s == '\t')) + while (s && *s && !(*s == ' ' || *s == '\t')) s++; return s; } diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c index 45ca45966d..6eec8ba353 100644 --- a/libmount/src/tab_parse.c +++ b/libmount/src/tab_parse.c @@ -43,110 +43,111 @@ static void parser_cleanup(struct libmnt_parser *pa) memset(pa, 0, sizeof(*pa)); } -static const char *next_number(const char *s, int *num, int *ok) +static const char *next_number(const char *s, int *num, int *rc) { char *end = NULL; assert(num); assert(s); - assert(ok); - - *ok = 0; - s = skip_blank(s); - if (!s || !*s) - return s; + assert(rc); + *rc = -EINVAL; *num = strtol(s, &end, 10); if (end == NULL || s == end) return s; /* valid end of number is a space or a terminator */ if (*end == ' ' || *end == '\t' || *end == '\0') - *ok = 1; + *rc = 0; return end; } +static inline const char *skip_separator(const char *p) +{ + while (p && (*p == ' ' || *p == '\t')) + ++p; + return p; +} + /* * Parses one line from {fs,m}tab */ static int mnt_parse_table_line(struct libmnt_fs *fs, const char *s) { - int rc, n = 0, xrc; - char *src = NULL, *fstype = NULL, *optstr = NULL; + int rc = 0; + char *p; - rc = sscanf(s, UL_SCNsA" " /* (1) source */ - UL_SCNsA" " /* (2) target */ - UL_SCNsA" " /* (3) FS type */ - UL_SCNsA" " /* (4) options */ - "%n", /* byte count */ + fs->passno = fs->freq = 0; - &src, - &fs->target, - &fstype, - &optstr, - &n); - xrc = rc; + /* (1) source */ + p = unmangle(s, &s); + if (!p || (rc = __mnt_fs_set_source_ptr(fs, p))) { + DBG(TAB, ul_debug("tab parse error: [source]")); + goto fail; + } - if (rc == 3 || rc == 4) { /* options are optional */ - unmangle_string(src); - unmangle_string(fs->target); - unmangle_string(fstype); + s = skip_separator(s); - if (optstr && *optstr) - unmangle_string(optstr); + /* (2) target */ + fs->target = unmangle(s, &s); + if (!fs->target) { + DBG(TAB, ul_debug("tab parse error: [target]")); + goto fail; + } - /* note that __foo functions do not reallocate the string - */ - rc = __mnt_fs_set_source_ptr(fs, src); - if (!rc) { - src = NULL; - rc = __mnt_fs_set_fstype_ptr(fs, fstype); - if (!rc) - fstype = NULL; - } - if (!rc && optstr) - rc = mnt_fs_set_options(fs, optstr); - free(optstr); - optstr = NULL; - } else { - DBG(TAB, ul_debug("tab parse error: [sscanf rc=%d]: '%s'", rc, s)); - rc = -EINVAL; + s = skip_separator(s); + + /* (3) FS type */ + p = unmangle(s, &s); + if (!p || (rc = __mnt_fs_set_fstype_ptr(fs, p))) { + DBG(TAB, ul_debug("tab parse error: [fstype]")); + goto fail; } - if (rc) { - free(src); - free(fstype); - free(optstr); - DBG(TAB, ul_debug("tab parse error: [set vars, rc=%d]\n", rc)); - return rc; /* error */ + s = skip_separator(s); + + /* (4) options (optional) */ + p = unmangle(s, &s); + if (p && (rc = mnt_fs_set_options(fs, p))) { + DBG(TAB, ul_debug("tab parse error: [options]")); + goto fail; } - fs->passno = fs->freq = 0; + if (!p) + goto done; + s = skip_separator(s); + if (!s || !*s) + goto done; - if (xrc == 4 && n) - s = skip_blank(s + n); - if (xrc == 4 && *s) { - int ok = 0; + /* (5) freq (optional) */ + s = next_number(s, &fs->freq, &rc); + if (s && *s && rc) { + DBG(TAB, ul_debug("tab parse error: [freq]")); + goto fail; + } - s = next_number(s, &fs->freq, &ok); - if (!ok) { - if (s && *s) { - DBG(TAB, ul_debug("tab parse error: [freq]")); - rc = -EINVAL; - } - } else { - s = next_number(s, &fs->passno, &ok); - if (!ok && s && *s) { - DBG(TAB, ul_debug("tab parse error: [passno]")); - rc = -EINVAL; - } - } + s = skip_separator(s); + if (!s || !*s) + goto done; + + /* (6) freq (optional) */ + s = next_number(s, &fs->passno, &rc); + if (s && *s && rc) { + DBG(TAB, ul_debug("tab parse error: [passno]")); + goto fail; } +done: + return 0; +fail: + if (rc == 0) + rc = -EINVAL; + DBG(TAB, ul_debug("tab parse error on: '%s' [rc=%d]", s, rc)); return rc; } + /* * Parses one line from a mountinfo file */ -- 2.39.2