From: Karel Zak Date: Tue, 18 Apr 2023 13:54:25 +0000 (+0200) Subject: libmount: cleanup all stat() use X-Git-Tag: v2.39-rc3~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f2663ba7d26283195b158b70038a04098080588c;p=thirdparty%2Futil-linux.git libmount: cleanup all stat() use * don't use STATX_MODE as we need only file type * use fstatat() or stat() as fallback on EOPNOTSUPP * use st_rdev from statx() too * rename to mnt_stat_mountpoint() to more generic mnt_safe_stat() * use mnt_is_path() on more places * cleanup mnt_context_*_excode() to not use stat() * use on others places mnt_safe_stat() Note that on some places stat() remaining, but it's not related to the mountpoints, it's about /run/mount/utab permissions, file locking and /dev/* permissions for non-root mounts. Signed-off-by: Karel Zak --- diff --git a/libmount/src/context.c b/libmount/src/context.c index 2df4716a71..4c5e65659f 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -1407,7 +1407,7 @@ int mnt_context_get_mountinfo_for_target(struct libmnt_context *cxt, if (mnt_context_is_nocanonicalize(cxt)) mnt_context_set_tabfilter(cxt, mountinfo_filter, (void *) tgt); - else if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISDIR(st.st_mode)) { + else if (mnt_safe_stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) { cache = mnt_context_get_cache(cxt); cn_tgt = mnt_resolve_path(tgt, cache); if (cn_tgt) @@ -2025,34 +2025,32 @@ int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name, if (!ns_old) return -MNT_ERR_NAMESPACE; - /* Ignore errors when search in $PATH and do not modify - * @rc due to stat() etc. + /* Ignore errors when search in $PATH and do not modify @rc */ path = strtok_r(search_path, ":", &p); while (path) { char helper[PATH_MAX]; - struct stat st; - int xrc; + int len, found = 0; - xrc = snprintf(helper, sizeof(helper), "%s/%s.%s", + len = snprintf(helper, sizeof(helper), "%s/%s.%s", path, name, type); path = strtok_r(NULL, ":", &p); - if (xrc < 0 || (size_t) xrc >= sizeof(helper)) + if (len < 0 || (size_t) len >= sizeof(helper)) continue; - xrc = stat(helper, &st); - if (xrc == -1 && errno == ENOENT && strchr(type, '.')) { + found = mnt_is_path(helper); + if (!found && strchr(type, '.')) { /* If type ends with ".subtype" try without it */ char *hs = strrchr(helper, '.'); if (hs) *hs = '\0'; - xrc = stat(helper, &st); + found = mnt_is_path(helper); } DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper, - xrc ? "not found" : "found")); - if (xrc) + found ? "found" : "not found")); + if (!found) continue; /* success */ diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c index 7bda266825..b8499471af 100644 --- a/libmount/src/context_mount.c +++ b/libmount/src/context_mount.c @@ -1558,7 +1558,7 @@ int mnt_context_get_mount_excode( if (!buf) break; if (geteuid() == 0) { - if (mnt_stat_mountpoint(tgt, &st) || !S_ISDIR(st.st_mode)) + if (mnt_safe_stat(tgt, &st) || !S_ISDIR(st.st_mode)) snprintf(buf, bufsz, _("mount point is not a directory")); else snprintf(buf, bufsz, _("permission denied")); @@ -1584,13 +1584,13 @@ int mnt_context_get_mount_excode( snprintf(buf, bufsz, _("%s already mounted or mount point busy"), src); break; case ENOENT: - if (tgt && mnt_lstat_mountpoint(tgt, &st)) { + if (tgt && mnt_safe_lstat(tgt, &st)) { if (buf) snprintf(buf, bufsz, _("mount point does not exist")); - } else if (tgt && mnt_stat_mountpoint(tgt, &st)) { + } else if (tgt && mnt_safe_stat(tgt, &st)) { if (buf) snprintf(buf, bufsz, _("mount point is a symbolic link to nowhere")); - } else if (src && stat(src, &st)) { + } else if (src && !mnt_is_path(src)) { if (uflags & MNT_MS_NOFAIL) return MNT_EX_SUCCESS; if (buf) @@ -1602,10 +1602,10 @@ int mnt_context_get_mount_excode( break; case ENOTDIR: - if (mnt_stat_mountpoint(tgt, &st) || ! S_ISDIR(st.st_mode)) { + if (mnt_safe_stat(tgt, &st) || ! S_ISDIR(st.st_mode)) { if (buf) snprintf(buf, bufsz, _("mount point is not a directory")); - } else if (src && stat(src, &st) && errno == ENOTDIR) { + } else if (src && !mnt_is_path(src)) { if (uflags & MNT_MS_NOFAIL) return MNT_EX_SUCCESS; if (buf) @@ -1664,7 +1664,7 @@ int mnt_context_get_mount_excode( return MNT_EX_SUCCESS; if (!buf) break; - if (src && stat(src, &st)) + if (src && mnt_safe_stat(src, &st)) snprintf(buf, bufsz, _("%s is not a block device, and stat(2) fails?"), src); else if (src && S_ISBLK(st.st_mode)) snprintf(buf, bufsz, @@ -1710,7 +1710,7 @@ int mnt_context_get_mount_excode( case EBADMSG: /* Bad CRC for classic filesystems (e.g. extN or XFS) */ - if (buf && src && stat(src, &st) == 0 + if (buf && src && mnt_safe_stat(src, &st) == 0 && (S_ISBLK(st.st_mode) || S_ISREG(st.st_mode))) { snprintf(buf, bufsz, _("cannot mount; probably corrupted filesystem on %s"), src); break; diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c index efb6675b3a..26394d51ef 100644 --- a/libmount/src/context_umount.c +++ b/libmount/src/context_umount.c @@ -134,7 +134,7 @@ try_loopdev: */ struct stat st; - if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISREG(st.st_mode)) { + if (mnt_safe_stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) { int count; struct libmnt_cache *cache = mnt_context_get_cache(cxt); const char *bf = cache ? mnt_resolve_path(tgt, cache) : tgt; @@ -275,7 +275,7 @@ static int lookup_umount_fs_by_statfs(struct libmnt_context *cxt, const char *tg || mnt_context_is_lazy(cxt) || mnt_context_is_nocanonicalize(cxt) || mnt_context_is_loopdel(cxt) - || mnt_stat_mountpoint(tgt, &st) != 0 || !S_ISDIR(st.st_mode) + || mnt_safe_stat(tgt, &st) != 0 || !S_ISDIR(st.st_mode) || has_utab_entry(cxt, tgt)) return 1; /* not found */ diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index 4af212388c..bceb04a92b 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -128,8 +128,8 @@ extern void mnt_free_filesystems(char **filesystems); extern char *mnt_get_kernel_cmdline_option(const char *name); -extern int mnt_stat_mountpoint(const char *target, struct stat *st); -extern int mnt_lstat_mountpoint(const char *target, struct stat *st); +extern int mnt_safe_stat(const char *target, struct stat *st); +extern int mnt_safe_lstat(const char *target, struct stat *st); extern int mnt_is_path(const char *target); extern int mnt_tmptgt_unshare(int *old_ns_fd); diff --git a/libmount/src/tab.c b/libmount/src/tab.c index d8b239b305..60bef8b2d1 100644 --- a/libmount/src/tab.c +++ b/libmount/src/tab.c @@ -1775,7 +1775,7 @@ int __mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_f struct stat st; devno = mnt_fs_get_devno(fstab_fs); - if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode)) + if (!devno && mnt_safe_stat(src, &st) == 0 && S_ISBLK(st.st_mode)) devno = st.st_rdev; } diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c index 526a0078bb..b8ec244f79 100644 --- a/libmount/src/tab_parse.c +++ b/libmount/src/tab_parse.c @@ -974,11 +974,10 @@ int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent) { struct libmnt_table *tb; - struct stat st; if (!filename) return NULL; - if (stat(filename, &st)) + if (!mnt_is_path(filename)) return empty_for_enoent ? mnt_new_table() : NULL; tb = mnt_new_table(); @@ -1149,7 +1148,7 @@ int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename) filename = mnt_get_fstab_path(); if (!filename) return -EINVAL; - if (stat(filename, &st) != 0) + if (mnt_safe_stat(filename, &st) != 0) return -errno; tb->fmt = MNT_FMT_FSTAB; diff --git a/libmount/src/utils.c b/libmount/src/utils.c index 1fa67b85f4..e03d932651 100644 --- a/libmount/src/utils.c +++ b/libmount/src/utils.c @@ -100,6 +100,10 @@ static int fstype_cmp(const void *v1, const void *v2) return strcmp(s1, s2); } +/* This very simplified stat() alternative uses cached VFS data and does not + * directly ask the filesystem for details. It requires a kernel that supports + * statx(). It's usable only for file type, rdev and ino! + */ static int safe_stat(const char *target, struct stat *st, int nofollow) { assert(target); @@ -125,26 +129,28 @@ static int safe_stat(const char *target, struct stat *st, int nofollow) if (rc == 0) { st->st_ino = stx.stx_ino; st->st_dev = makedev(stx.stx_dev_major, stx.stx_dev_minor); + st->st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor); st->st_mode = stx.stx_mode; } - return rc; + + if (rc == 0 || errno != EOPNOTSUPP) + return rc; } -#else -# ifdef AT_NO_AUTOMOUNT +#endif + +#ifdef AT_NO_AUTOMOUNT return fstatat(AT_FDCWD, target, st, AT_NO_AUTOMOUNT | (nofollow ? AT_SYMLINK_NOFOLLOW : 0)); -# else - return nofollow ? lstat(target, st) : stat(target, st); -# endif #endif + return nofollow ? lstat(target, st) : stat(target, st); } -int mnt_stat_mountpoint(const char *target, struct stat *st) +int mnt_safe_stat(const char *target, struct stat *st) { return safe_stat(target, st, 0); } -int mnt_lstat_mountpoint(const char *target, struct stat *st) +int mnt_safe_lstat(const char *target, struct stat *st) { return safe_stat(target, st, 1); } @@ -1074,7 +1080,7 @@ char *mnt_get_mountpoint(const char *path) if (*mnt == '/' && *(mnt + 1) == '\0') goto done; - if (mnt_stat_mountpoint(mnt, &st)) + if (mnt_safe_stat(mnt, &st)) goto err; base = st.st_dev; @@ -1083,7 +1089,7 @@ char *mnt_get_mountpoint(const char *path) if (!p) break; - if (mnt_stat_mountpoint(*mnt ? mnt : "/", &st)) + if (mnt_safe_stat(*mnt ? mnt : "/", &st)) goto err; dir = st.st_dev; if (dir != base) { @@ -1488,9 +1494,9 @@ static int tests_stat(struct libmnt_test *ts, int argc, char *argv[]) int rc; if (strcmp(argv[0], "--lstat") == 0) - rc = mnt_lstat_mountpoint(path, &st); + rc = mnt_safe_lstat(path, &st); else - rc = mnt_stat_mountpoint(path, &st); + rc = mnt_safe_stat(path, &st); if (rc) printf("%s: failed: rc=%d: %m\n", path, rc); else {