From f899cee097a646421ad372a10a4348ce4f86a715 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 29 Nov 2024 23:46:13 +0100 Subject: [PATCH] main: use extended override xattr Signed-off-by: Giuseppe Scrivano --- main.c | 72 +++++++++++++++++++------------------------------ utils.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- utils.h | 2 ++ 3 files changed, 109 insertions(+), 49 deletions(-) diff --git a/main.c b/main.c index 965f8f4..f0f24a6 100644 --- a/main.c +++ b/main.c @@ -508,43 +508,26 @@ node_dirfd (struct ovl_node *n) return n->layer->fd; } -static bool -has_prefix (const char *str, const char *pref) -{ - while (1) - { - if (*pref == '\0') - return true; - if (*str == '\0') - return false; - if (*pref != *str) - return false; - str++; - pref++; - } - return false; -} - static bool can_access_xattr (const struct ovl_layer *l, const char *name) { return ! (has_prefix (name, XATTR_PREFIX) || has_prefix (name, PRIVILEGED_XATTR_PREFIX) || has_prefix (name, UNPRIVILEGED_XATTR_PREFIX) - || (l->stat_override_mode == STAT_OVERRIDE_CONTAINERS && - has_prefix (name, XATTR_SECURITY_PREFIX))); + || (l->stat_override_mode == STAT_OVERRIDE_CONTAINERS && has_prefix (name, XATTR_SECURITY_PREFIX))); } -static bool encoded_xattr_name (const struct ovl_layer *l, const char *name) +static bool +encoded_xattr_name (const struct ovl_layer *l, const char *name) { - return has_prefix (name, XATTR_CONTAINERS_OVERRIDE_PREFIX) && - ! can_access_xattr (l, name + sizeof(XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1); + return has_prefix (name, XATTR_CONTAINERS_OVERRIDE_PREFIX) && ! can_access_xattr (l, name + sizeof (XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1); } -static const char *decode_xattr_name (const struct ovl_layer *l, const char *name) +static const char * +decode_xattr_name (const struct ovl_layer *l, const char *name) { if (encoded_xattr_name (l, name)) - return name + sizeof(XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1; + return name + sizeof (XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1; if (can_access_xattr (l, name)) return name; @@ -552,18 +535,18 @@ static const char *decode_xattr_name (const struct ovl_layer *l, const char *nam return NULL; } -static const char *encode_xattr_name (const struct ovl_layer *l, char *buf, - const char *name) +static const char * +encode_xattr_name (const struct ovl_layer *l, char *buf, + const char *name) { if (can_access_xattr (l, name)) return name; - if (l->stat_override_mode != STAT_OVERRIDE_CONTAINERS || - strlen(name) > XATTR_NAME_MAX + 1 - sizeof(XATTR_CONTAINERS_OVERRIDE_PREFIX)) + if (l->stat_override_mode != STAT_OVERRIDE_CONTAINERS || strlen (name) > XATTR_NAME_MAX + 1 - sizeof (XATTR_CONTAINERS_OVERRIDE_PREFIX)) return NULL; - strcpy(buf, XATTR_CONTAINERS_OVERRIDE_PREFIX); - strcpy(buf + sizeof(XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1, name); + strcpy (buf, XATTR_CONTAINERS_OVERRIDE_PREFIX); + strcpy (buf + sizeof (XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1, name); return buf; } @@ -2645,8 +2628,7 @@ filter_xattrs_list (struct ovl_layer *l, char *buf, ssize_t len) { char *next = it; - next += encoded_xattr_name (l, it) ? - sizeof(XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1 : it_len; + next += encoded_xattr_name (l, it) ? sizeof (XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1 : it_len; memmove (it, next, buf + len - next); len -= it_len; @@ -2742,7 +2724,7 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) } name = encode_xattr_name (node->layer, name_buf, name); - if (!name) + if (! name) { fuse_reply_err (req, ENODATA); return; @@ -3551,12 +3533,12 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, return; } - name = encode_xattr_name (node->layer, name_buf, name); - if (!name) - { - fuse_reply_err (req, EPERM); - return; - } + name = encode_xattr_name (node->layer, name_buf, name); + if (! name) + { + fuse_reply_err (req, EPERM); + return; + } if (! node->hidden) ret = direct_setxattr (node->layer, node->path, name, value, size, flags); @@ -3619,12 +3601,12 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name) return; } - name = encode_xattr_name (node->layer, name_buf, name); - if (!name) - { - fuse_reply_err (req, EPERM); - return; - } + name = encode_xattr_name (node->layer, name_buf, name); + if (! name) + { + fuse_reply_err (req, EPERM); + return; + } if (! node->hidden) ret = direct_removexattr (node->layer, node->path, name); diff --git a/utils.c b/utils.c index fbe06a4..b9317bb 100644 --- a/utils.c +++ b/utils.c @@ -224,16 +224,38 @@ open_fd_or_get_path (struct ovl_layer *l, const char *path, char *out, int *fd, return *fd; } +int +read_device (const char *s, dev_t *dev) +{ + unsigned int major, minor; + int ret; + + while (*s == '-') + s++; + + ret = sscanf (s, "%u-%u", &major, &minor); + if (ret != 2) + { + errno = EINVAL; + return -1; + } + + *dev = makedev (major, minor); + + return 0; +} + int override_mode (struct ovl_layer *l, int fd, const char *abs_path, const char *path, struct stat *st) { int ret; uid_t uid; gid_t gid; - mode_t mode; + mode_t mode = 0; char buf[64]; cleanup_close int cleanup_fd = -1; const char *xattr_name; + cleanup_free char *type = NULL; switch (st->st_mode & S_IFMT) { @@ -296,8 +318,45 @@ override_mode (struct ovl_layer *l, int fd, const char *abs_path, const char *pa buf[ret] = '\0'; - ret = sscanf (buf, "%d:%d:%o", &uid, &gid, &mode); - if (ret != 3) + ret = sscanf (buf, "%d:%d:%o:%ms", &uid, &gid, &mode, &type); + if (ret == 4) + { + if (has_prefix (type, "dir")) + mode |= S_IFDIR; + else if (has_prefix (type, "file")) + mode |= S_IFREG; + else if (has_prefix (type, "symlink")) + mode |= S_IFLNK; + else if (has_prefix (type, "pipe")) + mode |= S_IFIFO; + else if (has_prefix (type, "socket")) + mode |= S_IFSOCK; + else if (has_prefix (type, "block")) + { + mode |= S_IFBLK; + ret = read_device (type + strlen ("block"), &st->st_rdev); + if (ret < 0) + return ret; + } + else if (has_prefix (type, "char")) + { + mode |= S_IFCHR; + ret = read_device (type + strlen ("char"), &st->st_rdev); + if (ret < 0) + return ret; + } + else + { + errno = EINVAL; + return -1; + } + } + else if (ret == 3) + { + /* If a type is not specified, keep the original one. */ + mode |= (st->st_mode & S_IFMT); + } + else { errno = EINVAL; return -1; @@ -305,7 +364,24 @@ override_mode (struct ovl_layer *l, int fd, const char *abs_path, const char *pa st->st_uid = uid; st->st_gid = gid; - st->st_mode = (st->st_mode & S_IFMT) | mode; + st->st_mode = mode; return 0; } + +bool +has_prefix (const char *str, const char *pref) +{ + while (1) + { + if (*pref == '\0') + return true; + if (*str == '\0') + return false; + if (*pref != *str) + return false; + str++; + pref++; + } + return false; +} diff --git a/utils.h b/utils.h index a9176f9..284b451 100644 --- a/utils.h +++ b/utils.h @@ -62,4 +62,6 @@ int safe_openat (int dirfd, const char *pathname, int flags, mode_t mode); int override_mode (struct ovl_layer *l, int fd, const char *abs_path, const char *path, struct stat *st); +bool has_prefix (const char *str, const char *pref); + #endif