From 26c25145f4162b3095b39954e77060f2d647acef Mon Sep 17 00:00:00 2001 From: David du Colombier Date: Thu, 22 Oct 2026 13:49:21 +0200 Subject: [PATCH] Read /proc/self/mounts when /etc/mtab is missing fsdev_init reads the local file systems from /etc/mtab, which on Linux is a link to /proc/self/mounts. containerd 1.7.18 and podman 1.6.4 create containers without the link, and in them every object with recurse_file_system="local" comes out "does not exist": a check that no such file exists passes. --- src/OVAL/probes/fsdev.c | 20 +++++- tests/API/probes/test_fsdev_is_local_fs.c | 77 +++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/OVAL/probes/fsdev.c b/src/OVAL/probes/fsdev.c index 08d1d3ed58..d402144837 100644 --- a/src/OVAL/probes/fsdev.c +++ b/src/OVAL/probes/fsdev.c @@ -146,6 +146,19 @@ static int is_local_fs(struct mntent *ment) return 1; } +/* + * /etc/mtab links to /proc/self/mounts. Some container runtimes, + * containerd among them, create containers without the link. + */ +static FILE *open_mount_table(void) +{ + FILE *fp = setmntent(_PATH_MOUNTED, "r"); + + if (fp == NULL && errno == ENOENT) + fp = setmntent("/proc/self/mounts", "r"); + return fp; +} + #elif defined(OS_AIX) static int is_local_fs(struct mntent *ment) { @@ -174,6 +187,11 @@ static int is_local_fs(struct mntent *ment) return 1; } +static FILE *open_mount_table(void) +{ + return setmntent(_PATH_MOUNTED, "r"); +} + #endif /* OS_AIX */ static fsdev_t *__fsdev_init(fsdev_t *lfs) @@ -185,7 +203,7 @@ static fsdev_t *__fsdev_init(fsdev_t *lfs) struct mntent *ment; struct stat st; - fp = setmntent(_PATH_MOUNTED, "r"); + fp = open_mount_table(); if (fp == NULL) { e = errno; free(lfs); diff --git a/tests/API/probes/test_fsdev_is_local_fs.c b/tests/API/probes/test_fsdev_is_local_fs.c index b7e43b6997..0edcfef49f 100644 --- a/tests/API/probes/test_fsdev_is_local_fs.c +++ b/tests/API/probes/test_fsdev_is_local_fs.c @@ -26,6 +26,16 @@ #include #include + +#if defined(OS_LINUX) +#include + +/* __fsdev_init reads the mount table that mtab names. */ +#undef _PATH_MOUNTED +static const char *mtab; +#define _PATH_MOUNTED mtab +#endif + #include "fsdev.h" #include "fsdev.c" @@ -63,6 +73,60 @@ static int test_multiple_calls(const char *fake_mtab) return (locals == 3); } +#if defined(OS_LINUX) +/* + * read_table returns the devices that __fsdev_init finds in the mount + * table at path, in the order of the table, or NULL with errno set. + */ +static fsdev_t *read_table(const char *path) +{ + fsdev_t *lfs = malloc(sizeof(fsdev_t)); + + if (lfs == NULL) + return NULL; + mtab = path; + return __fsdev_init(lfs); +} + +/* + * A missing mount table gives the devices of /proc/self/mounts, which proc + * holds. fake_mtab gives its own: those of /, /tmp and /home that exist + * here, / first. + */ +static int test_mount_table(const fsdev_t *proc, const char *fake_mtab) +{ + fsdev_t *lfs; + struct stat st; + int ok; + + lfs = read_table("test_fsdev_is_local_fs.missing"); + if (lfs == NULL) { + fprintf(stderr, "missing mount table: %s\n", strerror(errno)); + return 0; + } + ok = lfs->cnt == proc->cnt && + (lfs->cnt == 0 || memcmp(lfs->ids, proc->ids, sizeof(dev_t) * lfs->cnt) == 0); + if (!ok) + fprintf(stderr, "missing mount table: %u devices, /proc/self/mounts gives %u\n", + (unsigned)lfs->cnt, (unsigned)proc->cnt); + fsdev_free(lfs); + if (!ok) + return 0; + + lfs = read_table(fake_mtab); + if (lfs == NULL) { + fprintf(stderr, "%s: %s\n", fake_mtab, strerror(errno)); + return 0; + } + ok = lfs->cnt >= 1 && lfs->cnt <= 3 && stat("/", &st) == 0 && lfs->ids[0] == st.st_dev; + if (!ok) + fprintf(stderr, "%s: %u devices, want 1 to 3, that of / first\n", + fake_mtab, (unsigned)lfs->cnt); + fsdev_free(lfs); + return ok; +} +#endif + int main(int argc, char *argv[]) { if (!test_single_call()) { @@ -73,6 +137,19 @@ int main(int argc, char *argv[]) fprintf(stderr, "test_multiple_calls has failed\n"); return 1; } +#if defined(OS_LINUX) + fsdev_t *proc = read_table("/proc/self/mounts"); + if (proc == NULL) { + fprintf(stderr, "/proc/self/mounts: %s: skipping test_mount_table\n", strerror(errno)); + return 255; + } + int ok = test_mount_table(proc, argv[1]); + fsdev_free(proc); + if (!ok) { + fprintf(stderr, "test_mount_table has failed\n"); + return 1; + } +#endif return 0; }