libmount: don't use sscanf() for fstab parsing

Addresses: https://github.com/karelzak/util-linux/issues/780
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2019-04-08 13:33:04 +02:00
parent f1428af5be
commit 36fcefa651
2 changed files with 77 additions and 76 deletions

View File

@ -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;
}

View File

@ -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;
rc = sscanf(s, UL_SCNsA" " /* (1) source */
UL_SCNsA" " /* (2) target */
UL_SCNsA" " /* (3) FS type */
UL_SCNsA" " /* (4) options */
"%n", /* byte count */
&src,
&fs->target,
&fstype,
&optstr,
&n);
xrc = rc;
if (rc == 3 || rc == 4) { /* options are optional */
unmangle_string(src);
unmangle_string(fs->target);
unmangle_string(fstype);
if (optstr && *optstr)
unmangle_string(optstr);
/* 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;
}
if (rc) {
free(src);
free(fstype);
free(optstr);
DBG(TAB, ul_debug("tab parse error: [set vars, rc=%d]\n", rc));
return rc; /* error */
}
int rc = 0;
char *p;
fs->passno = fs->freq = 0;
if (xrc == 4 && n)
s = skip_blank(s + n);
if (xrc == 4 && *s) {
int ok = 0;
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;
}
}
/* (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;
}
s = skip_separator(s);
/* (2) target */
fs->target = unmangle(s, &s);
if (!fs->target) {
DBG(TAB, ul_debug("tab parse error: [target]"));
goto fail;
}
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;
}
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;
}
if (!p)
goto done;
s = skip_separator(s);
if (!s || !*s)
goto done;
/* (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 = 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
*/