diff options
author | Karel Zak | 2014-05-20 10:11:57 +0200 |
---|---|---|
committer | Karel Zak | 2014-05-20 10:11:57 +0200 |
commit | 1dbbd85b9498536ab38758a03c9ec20362f1c572 (patch) | |
tree | 68c6e9f425e7132df226ca59873868ef148273b3 /lib | |
parent | mount: fix tiny typo in man page (diff) | |
download | kernel-qcow2-util-linux-1dbbd85b9498536ab38758a03c9ec20362f1c572.tar.gz kernel-qcow2-util-linux-1dbbd85b9498536ab38758a03c9ec20362f1c572.tar.xz kernel-qcow2-util-linux-1dbbd85b9498536ab38758a03c9ec20362f1c572.zip |
lib/canonicalize: make DM canonicalization more robust
The current code cares about filenames, but it's too fragile, we have
to check the path is really path to the block device.
Addresses: https://github.com/karelzak/util-linux/issues/83
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/canonicalize.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/lib/canonicalize.c b/lib/canonicalize.c index cac60d7a4..49ac80246 100644 --- a/lib/canonicalize.c +++ b/lib/canonicalize.c @@ -48,9 +48,27 @@ char *canonicalize_dm_name(const char *ptname) return res; } +static int is_dm_devname(char *canonical, char **name) +{ + struct stat sb; + char *p = strrchr(canonical, '/'); + + *name = NULL; + + if (!p + || strncmp(p, "/dm-", 4) != 0 + || !isdigit(*(p + 4)) + || stat(canonical, &sb) != 0 + || !S_ISBLK(sb.st_mode)) + return 0; + + *name = p + 1; + return 1; +} + char *canonicalize_path(const char *path) { - char *canonical, *p; + char *canonical, *dmname; if (!path || !*path) return NULL; @@ -59,9 +77,8 @@ char *canonicalize_path(const char *path) if (!canonical) return strdup(path); - p = strrchr(canonical, '/'); - if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) { - char *dm = canonicalize_dm_name(p + 1); + if (is_dm_devname(canonical, &dmname)) { + char *dm = canonicalize_dm_name(dmname); if (dm) { free(canonical); return dm; @@ -73,7 +90,7 @@ char *canonicalize_path(const char *path) char *canonicalize_path_restricted(const char *path) { - char *canonical, *p = NULL; + char *canonical, *dmname; int errsv; uid_t euid; gid_t egid; @@ -91,17 +108,15 @@ char *canonicalize_path_restricted(const char *path) errsv = errno = 0; canonical = realpath(path, NULL); - if (canonical) { - p = strrchr(canonical, '/'); - if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) { - char *dm = canonicalize_dm_name(p + 1); - if (dm) { - free(canonical); - canonical = dm; - } - } - } else + if (!canonical) errsv = errno; + else if (is_dm_devname(canonical, &dmname)) { + char *dm = canonicalize_dm_name(dmname); + if (dm) { + free(canonical); + canonical = dm; + } + } /* restore */ if (setegid(egid) < 0 || seteuid(euid) < 0) { |