]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
findmnt: fix SIGSEGV when parsing empty file
authorKarel Zak <kzak@redhat.com>
Wed, 18 Mar 2026 11:01:11 +0000 (12:01 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 18 Mar 2026 11:01:11 +0000 (12:01 +0100)
Set mnt_table_set_userdata() right after mnt_new_table() in all
functions that create a libmount table, so that parser_errcb() can
always safely access the findmnt userdata.

Previously, userdata was set only in main() after parse_tabfiles()
returned, meaning the error callback would dereference a NULL pointer
when encountering parse errors (e.g., an empty file passed via -F).

Also add a NULL guard in parser_errcb() as a safety net, and a test
for the empty file case.

Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2448233
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/findmnt.c
tests/expected/findmnt/outputs-empty-file [new file with mode: 0644]
tests/ts/findmnt/outputs

index afc40ebeb55b18cc45c39f747eb645c3caa111b4..c892bf2993c63ddab99fc20e6842c7bc13fd16f6 100644 (file)
@@ -1019,7 +1019,8 @@ static int parser_errcb(struct libmnt_table *tb,
 {
        struct findmnt *findmnt = mnt_table_get_userdata(tb);
        warnx(_("%s: parse error at line %d -- ignored"), filename, line);
-       findmnt->parse_nerrors++;
+       if (findmnt)
+               findmnt->parse_nerrors++;
        return 1;
 }
 
@@ -1039,7 +1040,8 @@ static char **append_pid_tabfile(char **files, int *nfiles, pid_t pid)
 }
 
 /* calls libmount fstab/mtab/mountinfo parser */
-static struct libmnt_table *parse_tabfiles(char **files,
+static struct libmnt_table *parse_tabfiles(struct findmnt *findmnt,
+                                          char **files,
                                           int nfiles,
                                           int tabtype)
 {
@@ -1051,6 +1053,7 @@ static struct libmnt_table *parse_tabfiles(char **files,
                warn(_("failed to initialize libmount table"));
                return NULL;
        }
+       mnt_table_set_userdata(tb, findmnt);
        mnt_table_set_parser_errcb(tb, parser_errcb);
 
        do {
@@ -1086,7 +1089,7 @@ static struct libmnt_table *parse_tabfiles(char **files,
        return tb;
 }
 
-static struct libmnt_table *fetch_listmount(void)
+static struct libmnt_table *fetch_listmount(struct findmnt *findmnt)
 {
        struct libmnt_table *tb = NULL;
        struct libmnt_statmnt *sm = NULL;
@@ -1102,6 +1105,7 @@ static struct libmnt_table *fetch_listmount(void)
                warn(_("failed to initialize libmount table"));
                goto failed;
        }
+       mnt_table_set_userdata(tb, findmnt);
 
        mnt_table_refer_statmnt(tb, sm);
 
@@ -1121,7 +1125,7 @@ failed:
  * Parses mountinfo and calls mnt_cache_set_targets(cache, mtab). Only
  * necessary if @tb in main() was read from a non-kernel source.
  */
-static void cache_set_targets(struct libmnt_cache *tmp)
+static void cache_set_targets(struct findmnt *findmnt, struct libmnt_cache *tmp)
 {
        struct libmnt_table *tb;
        const char *path;
@@ -1129,6 +1133,8 @@ static void cache_set_targets(struct libmnt_cache *tmp)
        tb = mnt_new_table();
        if (!tb)
                return;
+       mnt_table_set_userdata(tb, findmnt);
+       mnt_table_set_parser_errcb(tb, parser_errcb);
 
        path = access(_PATH_PROC_MOUNTINFO, R_OK) == 0 ?
                _PATH_PROC_MOUNTINFO :
@@ -1402,6 +1408,7 @@ static int poll_table(struct libmnt_table *tb, const char *tabfile,
                goto done;
        }
 
+       mnt_table_set_userdata(tb_new, findmnt);
        mnt_table_set_parser_errcb(tb_new, parser_errcb);
 
        fds[0].fd = fileno(f);
@@ -2142,12 +2149,11 @@ int main(int argc, char *argv[])
        mnt_init_debug(0);
 
        if (tabtype == TABTYPE_KERNEL_LISTMOUNT)
-               tb = fetch_listmount();
+               tb = fetch_listmount(&findmnt);
        else
-               tb = parse_tabfiles(tabfiles, ntabfiles, tabtype);
+               tb = parse_tabfiles(&findmnt, tabfiles, ntabfiles, tabtype);
        if (!tb)
                goto leave;
-       mnt_table_set_userdata(tb, &findmnt);
 
        if (tabtype == TABTYPE_MTAB && tab_is_kernel(tb))
                tabtype = TABTYPE_KERNEL_MOUNTINFO;
@@ -2168,7 +2174,7 @@ int main(int argc, char *argv[])
                mnt_table_set_cache(tb, findmnt.cache);
 
                if (tabtype == TABTYPE_FSTAB || tabtype == TABTYPE_MTAB)
-                       cache_set_targets(findmnt.cache);
+                       cache_set_targets(&findmnt, findmnt.cache);
        }
 
        if (findmnt.flags & FL_UNIQ)
diff --git a/tests/expected/findmnt/outputs-empty-file b/tests/expected/findmnt/outputs-empty-file
new file mode 100644 (file)
index 0000000..3214337
--- /dev/null
@@ -0,0 +1 @@
+rc=1
index 83c9134f9932b5b40ea82ed2c1c7fba653b9895e..198cbea98689f6771015055f3d10cff99e08028b 100755 (executable)
@@ -46,4 +46,10 @@ $TS_CMD_FINDMNT --tab-file "$TS_SELF/files/mountinfo-messy" &> $TS_OUTPUT
 echo rc=$? >> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "empty-file"
+touch "$TS_OUTDIR/empty"
+$TS_CMD_FINDMNT --tab-file "$TS_OUTDIR/empty" &> $TS_OUTPUT
+echo rc=$? >> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_finalize