libmount: don't use sscanf() for swaps 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 86673b3a46
commit 6c9ab254ae
2 changed files with 75 additions and 48 deletions

View File

@ -16,7 +16,6 @@
/* used by kernel in /proc (e.g. /proc/swaps) for deleted files */ /* used by kernel in /proc (e.g. /proc/swaps) for deleted files */
#define PATH_DELETED_SUFFIX " (deleted)" #define PATH_DELETED_SUFFIX " (deleted)"
#define PATH_DELETED_SUFFIX_SZ (sizeof(PATH_DELETED_SUFFIX) - 1)
/* DEFPATHs from <paths.h> don't include /usr/local */ /* DEFPATHs from <paths.h> don't include /usr/local */
#undef _PATH_DEFPATH #undef _PATH_DEFPATH

View File

@ -43,25 +43,35 @@ static void parser_cleanup(struct libmnt_parser *pa)
memset(pa, 0, sizeof(*pa)); memset(pa, 0, sizeof(*pa));
} }
static const char *next_number(const char *s, int *num, int *rc) static const char *next_s32(const char *s, int *num, int *rc)
{ {
char *end = NULL; char *end = NULL;
if (!s || !*s) if (!s || !*s)
return s; return s;
assert(num);
assert(rc);
*rc = -EINVAL; *rc = -EINVAL;
*num = strtol(s, &end, 10); *num = strtol(s, &end, 10);
if (end == NULL || s == end) if (end == NULL || s == end)
return s; return s;
/* valid end of number is a space or a terminator */
if (*end == ' ' || *end == '\t' || *end == '\0') if (*end == ' ' || *end == '\t' || *end == '\0')
*rc = 0; *rc = 0;
return end;
}
static const char *next_u64(const char *s, uint64_t *num, int *rc)
{
char *end = NULL;
if (!s || !*s)
return s;
*rc = -EINVAL;
*num = (uint64_t) strtoumax(s, &end, 10);
if (end == NULL || s == end)
return s;
if (*end == ' ' || *end == '\t' || *end == '\0')
*rc = 0;
return end; return end;
} }
@ -130,7 +140,7 @@ static int mnt_parse_table_line(struct libmnt_fs *fs, const char *s)
goto done; goto done;
/* (5) freq (optional) */ /* (5) freq (optional) */
s = next_number(s, &fs->freq, &rc); s = next_s32(s, &fs->freq, &rc);
if (s && *s && rc) { if (s && *s && rc) {
DBG(TAB, ul_debug("tab parse error: [freq]")); DBG(TAB, ul_debug("tab parse error: [freq]"));
goto fail; goto fail;
@ -141,7 +151,7 @@ static int mnt_parse_table_line(struct libmnt_fs *fs, const char *s)
goto done; goto done;
/* (6) freq (optional) */ /* (6) freq (optional) */
s = next_number(s, &fs->passno, &rc); s = next_s32(s, &fs->passno, &rc);
if (s && *s && rc) { if (s && *s && rc) {
DBG(TAB, ul_debug("tab parse error: [passno]")); DBG(TAB, ul_debug("tab parse error: [passno]"));
goto fail; goto fail;
@ -169,7 +179,7 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, const char *s)
fs->flags |= MNT_FS_KERNEL; fs->flags |= MNT_FS_KERNEL;
/* (1) id */ /* (1) id */
s = next_number(s, &fs->id, &rc); s = next_s32(s, &fs->id, &rc);
if (!s || !*s || rc) { if (!s || !*s || rc) {
DBG(TAB, ul_debug("tab parse error: [id]")); DBG(TAB, ul_debug("tab parse error: [id]"));
goto fail; goto fail;
@ -178,7 +188,7 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, const char *s)
s = skip_separator(s); s = skip_separator(s);
/* (2) parent */ /* (2) parent */
s = next_number(s, &fs->parent, &rc); s = next_s32(s, &fs->parent, &rc);
if (!s || !*s || rc) { if (!s || !*s || rc) {
DBG(TAB, ul_debug("tab parse error: [parent]")); DBG(TAB, ul_debug("tab parse error: [parent]"));
goto fail; goto fail;
@ -355,48 +365,66 @@ enomem:
*/ */
static int mnt_parse_swaps_line(struct libmnt_fs *fs, const char *s) static int mnt_parse_swaps_line(struct libmnt_fs *fs, const char *s)
{ {
uintmax_t fsz, usz; uint64_t num;
int rc; int rc;
char *src = NULL; char *p;
rc = sscanf(s, UL_SCNsA" " /* (1) source */ /* (1) source */
UL_SCNsA" " /* (2) type */ p = unmangle(s, &s);
"%ju" /* (3) size */ if (p) {
"%ju" /* (4) used */ char *x = (char *) endswith(p, PATH_DELETED_SUFFIX);
"%d", /* priority */ if (x && *x)
*x = '\0';
&src, }
&fs->swaptype, if (!p || (rc = __mnt_fs_set_source_ptr(fs, p))) {
&fsz, DBG(TAB, ul_debug("tab parse error: [source]"));
&usz, goto fail;
&fs->priority);
if (rc == 5) {
size_t sz;
fs->size = fsz;
fs->usedsize = usz;
/* remove "\040(deleted)" suffix */
sz = strlen(src);
if (sz > PATH_DELETED_SUFFIX_SZ) {
char *p = src + (sz - PATH_DELETED_SUFFIX_SZ);
if (strcmp(p, PATH_DELETED_SUFFIX) == 0)
*p = '\0';
}
unmangle_string(src);
rc = mnt_fs_set_source(fs, src);
if (!rc)
mnt_fs_set_fstype(fs, "swap");
} else {
DBG(TAB, ul_debug("tab parse error: [sscanf rc=%d]: '%s'", rc, s));
rc = -EINVAL;
} }
free(src); s = skip_separator(s);
/* (2) type */
fs->swaptype = unmangle(s, &s);
if (!fs->swaptype) {
DBG(TAB, ul_debug("tab parse error: [swaptype]"));
goto fail;
}
s = skip_separator(s);
/* (3) size */
s = next_u64(s, &num, &rc);
if (!s || !*s || rc) {
DBG(TAB, ul_debug("tab parse error: [size]"));
goto fail;
}
fs->size = num;
s = skip_separator(s);
/* (4) size */
s = next_u64(s, &num, &rc);
if (!s || !*s || rc) {
DBG(TAB, ul_debug("tab parse error: [used size]"));
goto fail;
}
fs->usedsize = num;
s = skip_separator(s);
/* (5) priority */
s = next_s32(s, &fs->priority, &rc);
if (rc) {
DBG(TAB, ul_debug("tab parse error: [priority]"));
goto fail;
}
mnt_fs_set_fstype(fs, "swap");
return 0;
fail:
if (rc == 0)
rc = -EINVAL;
DBG(TAB, ul_debug("tab parse error on: '%s' [rc=%d]", s, rc));
return rc; return rc;
} }