From db63f0e1e935ebc1e86c3d9b6a5649b79cecff34 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Thu, 5 Sep 2024 14:21:03 +0200 Subject: [PATCH] Skip directories and symlinks when mounting libraries This ensures that only actual libraries from the compat folders are mounted into the container. Signed-off-by: Evan Lezar --- src/nvc_mount.c | 19 +++++++++++++++---- src/utils.c | 19 +++++++++++++++++-- src/utils.h | 1 + src/xfuncs.h | 11 +++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/nvc_mount.c b/src/nvc_mount.c index 61564e3f..dd6e6088 100644 --- a/src/nvc_mount.c +++ b/src/nvc_mount.c @@ -99,9 +99,10 @@ mount_with_flags(struct error *err, const char *src, const char *dst, uid_t uid, static char ** mount_files(struct error *err, const char *root, const struct nvc_container *cnt, const char *dir, char *paths[], size_t size) { + char dummy[PATH_MAX]; char src[PATH_MAX]; char dst[PATH_MAX]; - mode_t mode; + mode_t mode, dst_mode; char *src_end, *dst_end, *file; char **mnt, **ptr; @@ -124,13 +125,23 @@ mount_files(struct error *err, const char *root, const struct nvc_container *cnt continue; if (path_append(err, src, paths[i]) < 0) goto fail; - if (path_append(err, dst, file) < 0) + if (file_mode_nofollow(err, src, &mode) < 0) goto fail; - if (file_mode(err, src, &mode) < 0) + // If we encounter resolved directories or symlinks here, we raise an error. + if (S_ISDIR(mode) || S_ISLNK(mode)) { + error_setx(err, "unexpected source file mode %o for %s", mode, paths[i]); goto fail; + } + if (path_append(err, dst, file) < 0) + goto fail; + if (file_mode_nofollow(err, dst, &dst_mode) == 0) { + if (S_ISDIR(dst_mode) || S_ISLNK(dst_mode)) { + error_setx(err, "unexpected destination file mode %o for %s", dst_mode, file); + goto fail; + } + }; if (file_create(err, dst, NULL, cnt->uid, cnt->gid, mode) < 0) goto fail; - log_infof("mounting %s at %s", src, dst); if (xmount(err, src, dst, NULL, MS_BIND, NULL) < 0) goto fail; diff --git a/src/utils.c b/src/utils.c index ab9bacff..a4ba1915 100644 --- a/src/utils.c +++ b/src/utils.c @@ -542,9 +542,9 @@ file_create(struct error *err, const char *path, const char *data, uid_t uid, gi int rv = -1; // We check whether the file already exists with the required mode and skip the creation. - if (data == NULL && file_mode(err, path, &perm) == 0) { + if (data == NULL && file_mode_nofollow(err, path, &perm) == 0) { if (perm == mode) { - log_errf("The path %s already exists with the required mode; skipping create", path); + log_warnf("The path %s already exists with the required mode; skipping create", path); return (0); } } @@ -677,6 +677,21 @@ file_mode(struct error *err, const char *path, mode_t *mode) return (0); } +// file_mode_nofollow implements the same functionality as file_mode except that +// in that case of a symlink, the file is not followed and the mode of the +// original file is returned. +int +file_mode_nofollow(struct error *err, const char *path, mode_t *mode) +{ + struct stat s; + int rv; + + if (xlstat(err, path, &s) < 0) + return (-1); + *mode = s.st_mode; + return (0); +} + int file_read_line(struct error *err, const char *path, char *buf, size_t size) { diff --git a/src/utils.h b/src/utils.h index e9cedf1a..82ea199d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -73,6 +73,7 @@ int file_remove(struct error *, const char *); int file_exists(struct error *, const char *); int file_exists_at(struct error *, const char *, const char *); int file_mode(struct error *, const char *, mode_t *); +int file_mode_nofollow(struct error *, const char *, mode_t *); int file_read_line(struct error *, const char *, char *, size_t); int file_read_text(struct error *, const char *, char **); int file_read_uint32(struct error *, const char *, uint32_t *); diff --git a/src/xfuncs.h b/src/xfuncs.h index 2c3f3f90..8d5e5f2b 100644 --- a/src/xfuncs.h +++ b/src/xfuncs.h @@ -22,6 +22,7 @@ static inline void xclose(int); static inline int xopen(struct error *, const char *, int); static inline void *xcalloc(struct error *, size_t, size_t); static inline int xstat(struct error *, const char *, struct stat *); +static inline int xlstat(struct error *, const char *, struct stat *); static inline FILE *xfopen(struct error *, const char *, const char *); static inline char *xstrdup(struct error *, const char *); static inline int xasprintf(struct error *, char **, const char *, ...) @@ -74,6 +75,16 @@ xstat(struct error *err, const char *path, struct stat *buf) return (rv); } +static inline int +xlstat(struct error *err, const char *path, struct stat *buf) +{ + int rv; + + if ((rv = lstat(path, buf)) < 0) + error_set(err, "lstat failed: %s", path); + return (rv); +} + static inline FILE * xfopen(struct error *err, const char *path, const char *mode) {