From: Karel Zak Date: Tue, 2 Jun 2026 10:27:15 +0000 (+0200) Subject: libmount: disable libblkid probing for non-root users X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cd14e75962241d36845c0e0f5fd3ac2f90bf05c7;p=thirdparty%2Futil-linux.git libmount: disable libblkid probing for non-root users Add noprobe flag to struct libmnt_cache that disables low-level device probing via libblkid. When the mount context is restricted (non-root user), the flag is set automatically on cache creation and on externally provided caches. With noprobe enabled: - read_from_blkid() is skipped (device I/O blocked) - mnt_resolve_tag() uses blkid_evaluate_tag2() with BLKID_EVALUATE_NOPROBE, so tags are resolved only via udev /dev/disk/by-* symlinks without device scanning This minimizes the libblkid attack surface for suid mount/umount binaries. Signed-off-by: Karel Zak --- diff --git a/libmount/src/cache.c b/libmount/src/cache.c index 28af83740..e02c653f5 100644 --- a/libmount/src/cache.c +++ b/libmount/src/cache.c @@ -63,6 +63,7 @@ struct libmnt_cache { size_t nallocs; int refcount; int probe_sb_extra; /* extra BLKID_SUBLKS_* flags */ + bool noprobe; /* disable libblkid device probing */ /* blkid_evaluate_tag() works in two ways: * @@ -214,6 +215,12 @@ int mnt_cache_set_sbprobe(struct libmnt_cache *cache, int flags) return 0; } +void mnt_cache_enable_noprobe(struct libmnt_cache *cache, int enable) +{ + if (cache) + cache->noprobe = !!enable; +} + /* note that the @key could be the same pointer as @value */ static int cache_add_entry(struct libmnt_cache *cache, char *key, char *value, int flag) @@ -379,6 +386,11 @@ static int read_from_blkid(struct libmnt_cache *cache, const char *devname) assert(cache); assert(devname); + if (cache->noprobe) { + DBG_OBJ(CACHE, cache, ul_debug("%s: skip blkid probe (noprobe)", devname)); + return 1; + } + DBG_OBJ(CACHE, cache, ul_debug("%s: reading from blkid", devname)); pr = blkid_new_probe_from_filename(devname); @@ -801,9 +813,6 @@ char *mnt_resolve_tag(const char *token, const char *value, { char *p = NULL; - /*DBG_OBJ(CACHE, cache, ul_debug("resolving tag token=%s value=%s", - token, value));*/ - if (!token || !value) return NULL; @@ -811,14 +820,20 @@ char *mnt_resolve_tag(const char *token, const char *value, p = (char *) cache_find_tag(cache, token, value); if (!p) { + DBG_OBJ(CACHE, cache, ul_debug("evaluating (by blkid) tag %s=%s", token, value)); + /* returns newly allocated string */ - p = blkid_evaluate_tag(token, value, cache ? &cache->bc : NULL); + p = blkid_evaluate_tag2(token, value, + cache ? &cache->bc : NULL, + cache && cache->noprobe ? BLKID_EVALUATE_NOPROBE : 0); if (p && cache && cache_add_tag(cache, token, value, p, 0)) goto error; } + DBG_OBJ(CACHE, cache, ul_debug("resolve tag %s=%s -> %s", + token, value, p ? p : "NOT FOUND")); return p; error: free(p); diff --git a/libmount/src/context.c b/libmount/src/context.c index f4b012847..dccf8bdd5 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -1670,6 +1670,9 @@ int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache mnt_ref_cache(cache); /* new */ mnt_unref_cache(cxt->cache); /* old */ + if (cache && mnt_context_is_restricted(cxt)) + mnt_cache_enable_noprobe(cache, 1); + cxt->cache = cache; if (cxt->mountinfo) diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index 2c5512c80..094c9a928 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -696,6 +696,8 @@ extern int mnt_context_prepare_update(struct libmnt_context *cxt); extern int mnt_context_merge_mflags(struct libmnt_context *cxt); extern int mnt_context_update_tabs(struct libmnt_context *cxt); +extern void mnt_cache_enable_noprobe(struct libmnt_cache *cache, int enable); + extern int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg); extern int mnt_context_mount_setopt(struct libmnt_context *cxt, int c, char *arg);