mirror of
https://github.com/containers/fuse-overlayfs.git
synced 2025-08-03 18:05:58 -04:00
Merge pull request #422 from akihikodaki/containers
Prefer user.containers.override_stat over user.fuseoverlayfs.
This commit is contained in:
commit
4217e1c160
20
.github/workflows/test.yaml
vendored
20
.github/workflows/test.yaml
vendored
@ -4,23 +4,23 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build_job:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
name: Build on ${{ matrix.arch }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: armv7
|
||||
distro: ubuntu20.04
|
||||
distro: ubuntu22.04
|
||||
- arch: aarch64
|
||||
distro: ubuntu20.04
|
||||
distro: ubuntu22.04
|
||||
- arch: s390x
|
||||
distro: ubuntu20.04
|
||||
distro: ubuntu22.04
|
||||
- arch: ppc64le
|
||||
distro: ubuntu20.04
|
||||
distro: ubuntu22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2.1.0
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
- uses: uraimo/run-on-arch-action@v2.7.2
|
||||
name: Build
|
||||
id: build
|
||||
with:
|
||||
@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
install: |
|
||||
apt-get update -q -y
|
||||
apt-get install -q -y attr automake autotools-dev git make gcc pkg-config xz-utils python3.8 g++ python3-setuptools libdevmapper-dev btrfs-progs libbtrfs-dev go-md2man parallel libfuse3-dev bats
|
||||
apt-get install -q -y attr automake autotools-dev git make gcc pkg-config xz-utils python3 g++ python3-setuptools libdevmapper-dev btrfs-progs libbtrfs-dev go-md2man parallel libfuse3-dev bats
|
||||
|
||||
run: |
|
||||
./autogen.sh
|
||||
@ -49,7 +49,7 @@ jobs:
|
||||
fuse-overlayfs
|
||||
|
||||
Test:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
- name: install dependencies
|
||||
run: |
|
||||
sudo apt-get update -q -y
|
||||
sudo apt-get install -q -y attr automake autotools-dev git make gcc pkg-config xz-utils python3.8 g++ python3-setuptools libdevmapper-dev btrfs-progs libbtrfs-dev go-md2man parallel wget libfuse3-dev bats
|
||||
sudo apt-get install -q -y attr automake autotools-dev git make gcc pkg-config xz-utils python3 g++ python3-setuptools libdevmapper-dev btrfs-progs libbtrfs-dev go-md2man parallel wget libfuse3-dev bats
|
||||
|
||||
sudo mkdir -p /lower /upper /mnt $GOPATH/src/github.com/containers
|
||||
sudo sh -c "cd $GOPATH/src/github.com/containers; git clone --depth=1 https://github.com/containers/storage"
|
||||
@ -90,7 +90,7 @@ jobs:
|
||||
- name: Archive build artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fuse-overlayfs-x86_64-ubuntu20.04
|
||||
name: fuse-overlayfs-x86_64-ubuntu22.04
|
||||
path: |
|
||||
fuse-overlayfs
|
||||
if: ${{ matrix.test == 'ovl-whiteouts' }}
|
||||
|
@ -6,12 +6,12 @@ import stat
|
||||
import errno
|
||||
|
||||
XATTR_OVERRIDE_STAT_PRIVILEGED = "security.fuseoverlayfs.override_stat"
|
||||
XATTR_OVERRIDE_STAT = "user.fuseoverlayfs.override_stat"
|
||||
XATTR_OVERRIDE_CONTAINERS_STAT = "user.fuseoverlayfs.override_stat"
|
||||
|
||||
if os.geteuid() == 0:
|
||||
xattr_name = XATTR_OVERRIDE_STAT_PRIVILEGED
|
||||
else:
|
||||
xattr_name = XATTR_OVERRIDE_STAT
|
||||
xattr_name = XATTR_OVERRIDE_CONTAINERS_STAT
|
||||
|
||||
cwd_fd = os.open(".", os.O_PATH)
|
||||
|
||||
@ -23,7 +23,7 @@ def fix_path(path):
|
||||
os.setxattr(path, xattr_name, str.encode(content), flags=os.XATTR_CREATE, follow_symlinks=False)
|
||||
except Exception as e:
|
||||
if e.errno == errno.EEXIST:
|
||||
print("attr %s already present for %s: %s" % (XATTR_OVERRIDE_STAT, path, e.errno))
|
||||
print("attr %s already present for %s: %s" % (xattr_name, path, e.errno))
|
||||
return
|
||||
raise e
|
||||
|
||||
|
4
direct.c
4
direct.c
@ -186,10 +186,10 @@ direct_load_data_source (struct ovl_layer *l, const char *opaque, const char *pa
|
||||
|
||||
if (fgetxattr (l->fd, XATTR_PRIVILEGED_OVERRIDE_STAT, tmp, sizeof (tmp)) >= 0)
|
||||
l->stat_override_mode = STAT_OVERRIDE_PRIVILEGED;
|
||||
else if (fgetxattr (l->fd, XATTR_OVERRIDE_STAT, tmp, sizeof (tmp)) >= 0)
|
||||
l->stat_override_mode = STAT_OVERRIDE_USER;
|
||||
else if (fgetxattr (l->fd, XATTR_OVERRIDE_CONTAINERS_STAT, tmp, sizeof (tmp)) >= 0)
|
||||
l->stat_override_mode = STAT_OVERRIDE_CONTAINERS;
|
||||
else if (fgetxattr (l->fd, XATTR_OVERRIDE_STAT, tmp, sizeof (tmp)) >= 0)
|
||||
l->stat_override_mode = STAT_OVERRIDE_USER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
243
main.c
243
main.c
@ -59,6 +59,7 @@
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <pthread.h>
|
||||
@ -141,6 +142,7 @@ open_by_handle_at (int mount_fd, struct file_handle *handle, int flags)
|
||||
#define ORIGIN_XATTR "user.fuseoverlayfs.origin"
|
||||
#define OPAQUE_XATTR "user.fuseoverlayfs.opaque"
|
||||
#define XATTR_CONTAINERS_PREFIX "user.containers."
|
||||
#define XATTR_CONTAINERS_OVERRIDE_PREFIX "user.containers.override_"
|
||||
#define UNPRIVILEGED_XATTR_PREFIX "user.overlay."
|
||||
#define UNPRIVILEGED_OPAQUE_XATTR "user.overlay.opaque"
|
||||
#define PRIVILEGED_XATTR_PREFIX "trusted.overlay."
|
||||
@ -524,11 +526,46 @@ has_prefix (const char *str, const char *pref)
|
||||
}
|
||||
|
||||
static bool
|
||||
can_access_xattr (const char *name)
|
||||
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);
|
||||
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)));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (can_access_xattr (l, name))
|
||||
return name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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))
|
||||
return NULL;
|
||||
|
||||
strcpy(buf, XATTR_CONTAINERS_OVERRIDE_PREFIX);
|
||||
strcpy(buf + sizeof(XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1, name);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -539,17 +576,21 @@ write_permission_xattr (struct ovl_data *lo, int fd, const char *path, uid_t uid
|
||||
int ret;
|
||||
const char *name = NULL;
|
||||
|
||||
switch (lo->xattr_permissions)
|
||||
switch (get_upper_layer (lo)->stat_override_mode)
|
||||
{
|
||||
case 0:
|
||||
case STAT_OVERRIDE_NONE:
|
||||
return 0;
|
||||
|
||||
case 1:
|
||||
case STAT_OVERRIDE_USER:
|
||||
name = XATTR_OVERRIDE_STAT;
|
||||
break;
|
||||
|
||||
case STAT_OVERRIDE_PRIVILEGED:
|
||||
name = XATTR_PRIVILEGED_OVERRIDE_STAT;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
name = XATTR_OVERRIDE_STAT;
|
||||
case STAT_OVERRIDE_CONTAINERS:
|
||||
name = XATTR_OVERRIDE_CONTAINERS_STAT;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -622,22 +663,32 @@ do_fchownat (struct ovl_data *lo, int dfd, const char *path, uid_t uid, gid_t gi
|
||||
#define fchownat ERROR
|
||||
|
||||
static int
|
||||
do_fchmod (struct ovl_data *lo, int fd, mode_t mode)
|
||||
do_stat (struct ovl_node *node, int fd, const char *path, struct stat *st)
|
||||
{
|
||||
struct ovl_layer *l = node->layer;
|
||||
|
||||
if (fd >= 0)
|
||||
return l->ds->fstat (l, fd, path, STATX_BASIC_STATS, st);
|
||||
|
||||
if (path != NULL)
|
||||
return stat (path, st);
|
||||
|
||||
if (node->hidden)
|
||||
return fstatat (node_dirfd (node), node->path, st, AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
return l->ds->statat (l, node->path, st, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS);
|
||||
}
|
||||
|
||||
static int
|
||||
do_fchmod (struct ovl_data *lo, struct ovl_node *node, int fd, mode_t mode)
|
||||
{
|
||||
if (lo->xattr_permissions)
|
||||
{
|
||||
struct ovl_layer *upper = get_upper_layer (lo);
|
||||
struct stat st;
|
||||
|
||||
if (upper == NULL)
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
st.st_uid = 0;
|
||||
st.st_gid = 0;
|
||||
if (override_mode (upper, fd, NULL, NULL, &st) < 0 && errno != ENODATA)
|
||||
if (do_stat (node, fd, NULL, &st) < 0)
|
||||
return -1;
|
||||
|
||||
return write_permission_xattr (lo, fd, NULL, st.st_uid, st.st_gid, mode);
|
||||
@ -648,22 +699,15 @@ do_fchmod (struct ovl_data *lo, int fd, mode_t mode)
|
||||
#define fchmod ERROR
|
||||
|
||||
static int
|
||||
do_chmod (struct ovl_data *lo, const char *path, mode_t mode)
|
||||
do_chmod (struct ovl_data *lo, struct ovl_node *node, const char *path, mode_t mode)
|
||||
{
|
||||
if (lo->xattr_permissions)
|
||||
{
|
||||
struct ovl_layer *upper = get_upper_layer (lo);
|
||||
struct stat st;
|
||||
|
||||
if (upper == NULL)
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
st.st_uid = 0;
|
||||
st.st_gid = 0;
|
||||
if (override_mode (upper, -1, path, NULL, &st) < 0 && errno != ENODATA)
|
||||
if (do_stat (node, -1, path, &st) < 0)
|
||||
return -1;
|
||||
|
||||
return write_permission_xattr (lo, -1, path, st.st_uid, st.st_gid, mode);
|
||||
@ -921,14 +965,8 @@ rpl_stat (fuse_req_t req, struct ovl_node *node, int fd, const char *path, struc
|
||||
|
||||
if (st_in)
|
||||
memcpy (st, st_in, sizeof (*st));
|
||||
else if (fd >= 0)
|
||||
ret = l->ds->fstat (l, fd, path, STATX_BASIC_STATS, st);
|
||||
else if (path != NULL)
|
||||
ret = stat (path, st);
|
||||
else if (node->hidden)
|
||||
ret = fstatat (node_dirfd (node), node->path, st, AT_SYMLINK_NOFOLLOW);
|
||||
else
|
||||
ret = l->ds->statat (l, node->path, st, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS);
|
||||
ret = do_stat (node, fd, path, st);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -2582,7 +2620,7 @@ inherit_acl (struct ovl_data *lo, struct ovl_node *parent, int targetfd, const c
|
||||
|
||||
/* in-place filter xattrs that cannot be accessed. */
|
||||
static ssize_t
|
||||
filter_xattrs_list (char *buf, ssize_t len)
|
||||
filter_xattrs_list (struct ovl_layer *l, char *buf, ssize_t len)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
char *it;
|
||||
@ -2598,14 +2636,17 @@ filter_xattrs_list (char *buf, ssize_t len)
|
||||
|
||||
it_len = strlen (it) + 1;
|
||||
|
||||
if (can_access_xattr (it))
|
||||
if (can_access_xattr (l, it))
|
||||
{
|
||||
it += it_len;
|
||||
ret += it_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *next = it + it_len;
|
||||
char *next = it;
|
||||
|
||||
next += encoded_xattr_name (l, it) ?
|
||||
sizeof(XATTR_CONTAINERS_OVERRIDE_PREFIX) - 1 : it_len;
|
||||
|
||||
memmove (it, next, buf + len - next);
|
||||
len -= it_len;
|
||||
@ -2665,7 +2706,7 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size)
|
||||
return;
|
||||
}
|
||||
|
||||
len = filter_xattrs_list (buf, ret);
|
||||
len = filter_xattrs_list (node->layer, buf, ret);
|
||||
|
||||
if (size == 0)
|
||||
fuse_reply_xattr (req, len);
|
||||
@ -2680,7 +2721,8 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
|
||||
ssize_t len;
|
||||
struct ovl_node *node;
|
||||
struct ovl_data *lo = ovl_data (req);
|
||||
cleanup_free char *buf = NULL;
|
||||
cleanup_free char *value_buf = NULL;
|
||||
char name_buf[XATTR_NAME_MAX + 1];
|
||||
int ret;
|
||||
|
||||
if (UNLIKELY (ovl_debug (req)))
|
||||
@ -2692,12 +2734,6 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
|
||||
return;
|
||||
}
|
||||
|
||||
if (! can_access_xattr (name))
|
||||
{
|
||||
fuse_reply_err (req, ENODATA);
|
||||
return;
|
||||
}
|
||||
|
||||
node = do_lookup_file (lo, ino, NULL);
|
||||
if (node == NULL || node->whiteout)
|
||||
{
|
||||
@ -2705,10 +2741,17 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
|
||||
return;
|
||||
}
|
||||
|
||||
name = encode_xattr_name (node->layer, name_buf, name);
|
||||
if (!name)
|
||||
{
|
||||
fuse_reply_err (req, ENODATA);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
buf = malloc (size);
|
||||
if (buf == NULL)
|
||||
value_buf = malloc (size);
|
||||
if (value_buf == NULL)
|
||||
{
|
||||
fuse_reply_err (req, errno);
|
||||
return;
|
||||
@ -2716,12 +2759,12 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
|
||||
}
|
||||
|
||||
if (! node->hidden)
|
||||
ret = node->layer->ds->getxattr (node->layer, node->path, name, buf, size);
|
||||
ret = node->layer->ds->getxattr (node->layer, node->path, name, value_buf, size);
|
||||
else
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
strconcat3 (path, PATH_MAX, lo->workdir, "/", node->path);
|
||||
ret = getxattr (path, name, buf, size);
|
||||
ret = getxattr (path, name, value_buf, size);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
@ -2735,7 +2778,7 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
|
||||
if (size == 0)
|
||||
fuse_reply_xattr (req, len);
|
||||
else
|
||||
fuse_reply_buf (req, buf, len);
|
||||
fuse_reply_buf (req, value_buf, len);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2756,7 +2799,8 @@ ovl_access (fuse_req_t req, fuse_ino_t ino, int mask)
|
||||
}
|
||||
|
||||
static int
|
||||
copy_xattr (int sfd, int dfd, char *buf, size_t buf_size)
|
||||
copy_xattr (const struct ovl_layer *sl, int sfd,
|
||||
const struct ovl_layer *dl, int dfd, char *buf, size_t buf_size)
|
||||
{
|
||||
ssize_t xattr_len;
|
||||
|
||||
@ -2767,9 +2811,16 @@ copy_xattr (int sfd, int dfd, char *buf, size_t buf_size)
|
||||
for (it = buf; it - buf < xattr_len; it += strlen (it) + 1)
|
||||
{
|
||||
cleanup_free char *v = NULL;
|
||||
const char *decoded_name = decode_xattr_name (sl, it);
|
||||
const char *encoded_name;
|
||||
char buf[XATTR_NAME_MAX + 1];
|
||||
ssize_t s;
|
||||
|
||||
if (! can_access_xattr (it))
|
||||
if (! decoded_name)
|
||||
continue;
|
||||
|
||||
encoded_name = encode_xattr_name (dl, buf, decoded_name);
|
||||
if (! encoded_name)
|
||||
continue;
|
||||
|
||||
s = safe_read_xattr (&v, sfd, it, 256);
|
||||
@ -2780,7 +2831,7 @@ copy_xattr (int sfd, int dfd, char *buf, size_t buf_size)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fsetxattr (dfd, it, v, s, 0) < 0)
|
||||
if (fsetxattr (dfd, encoded_name, v, s, 0) < 0)
|
||||
{
|
||||
if (errno == EINVAL || errno == EOPNOTSUPP)
|
||||
continue;
|
||||
@ -2856,7 +2907,8 @@ static int create_node_directory (struct ovl_data *lo, struct ovl_node *src);
|
||||
|
||||
static int
|
||||
create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct timespec *times,
|
||||
struct ovl_node *parent, int xattr_sfd, uid_t uid, gid_t gid, mode_t mode, bool set_opaque, struct stat *st_out)
|
||||
struct ovl_node *parent, struct ovl_layer *sl, int xattr_sfd,
|
||||
uid_t uid, gid_t gid, mode_t mode, bool set_opaque, struct stat *st_out)
|
||||
{
|
||||
int ret;
|
||||
int saved_errno;
|
||||
@ -2920,7 +2972,7 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = copy_xattr (xattr_sfd, dfd, buf, buf_size);
|
||||
ret = copy_xattr (sl, xattr_sfd, get_upper_layer (lo), dfd, buf, buf_size);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
@ -3013,7 +3065,7 @@ create_node_directory (struct ovl_data *lo, struct ovl_node *src)
|
||||
if (override_mode (src->layer, sfd, NULL, NULL, &st) < 0 && errno != ENODATA && errno != EOPNOTSUPP)
|
||||
return -1;
|
||||
|
||||
ret = create_directory (lo, get_upper_layer (lo)->fd, src->path, times, src->parent, sfd, st.st_uid, st.st_gid, st.st_mode, false, NULL);
|
||||
ret = create_directory (lo, get_upper_layer (lo)->fd, src->path, times, src->parent, src->layer, sfd, st.st_uid, st.st_gid, st.st_mode, false, NULL);
|
||||
if (ret == 0)
|
||||
{
|
||||
src->layer = get_upper_layer (lo);
|
||||
@ -3192,7 +3244,7 @@ copyup (struct ovl_data *lo, struct ovl_node *node)
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
ret = copy_xattr (sfd, dfd, buf, buf_size);
|
||||
ret = copy_xattr (node->layer, sfd, get_upper_layer (lo), dfd, buf, buf_size);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
@ -3472,6 +3524,7 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name,
|
||||
cleanup_lock int l = enter_big_lock ();
|
||||
struct ovl_data *lo = ovl_data (req);
|
||||
struct ovl_node *node;
|
||||
char name_buf[XATTR_NAME_MAX + 1];
|
||||
int ret;
|
||||
|
||||
if (UNLIKELY (ovl_debug (req)))
|
||||
@ -3484,12 +3537,6 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_prefix (name, PRIVILEGED_XATTR_PREFIX) || has_prefix (name, XATTR_PREFIX) || has_prefix (name, XATTR_CONTAINERS_PREFIX))
|
||||
{
|
||||
fuse_reply_err (req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
node = do_lookup_file (lo, ino, NULL);
|
||||
if (node == NULL || node->whiteout)
|
||||
{
|
||||
@ -3504,6 +3551,13 @@ 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;
|
||||
}
|
||||
|
||||
if (! node->hidden)
|
||||
ret = direct_setxattr (node->layer, node->path, name, value, size, flags);
|
||||
else
|
||||
@ -3545,6 +3599,7 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name)
|
||||
cleanup_lock int l = enter_big_lock ();
|
||||
struct ovl_node *node;
|
||||
struct ovl_data *lo = ovl_data (req);
|
||||
char name_buf[XATTR_NAME_MAX + 1];
|
||||
int ret;
|
||||
|
||||
if (UNLIKELY (ovl_debug (req)))
|
||||
@ -3564,6 +3619,13 @@ 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;
|
||||
}
|
||||
|
||||
if (! node->hidden)
|
||||
ret = direct_removexattr (node->layer, node->path, name);
|
||||
else
|
||||
@ -3823,7 +3885,7 @@ ovl_write_buf (fuse_req_t req, fuse_ino_t ino,
|
||||
/* if it is a writepage request, make sure to restore the setuid bit. */
|
||||
if (fi->writepage && (inode->mode & (S_ISUID | S_ISGID)))
|
||||
{
|
||||
if (do_fchmod (lo, fi->fh, inode->mode) < 0)
|
||||
if (do_fchmod (lo, inode->node, fi->fh, inode->mode) < 0)
|
||||
{
|
||||
fuse_reply_err (req, errno);
|
||||
return;
|
||||
@ -4135,9 +4197,9 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
|
||||
if (to_set & FUSE_SET_ATTR_MODE)
|
||||
{
|
||||
if (fd >= 0)
|
||||
ret = do_fchmod (lo, fd, attr->st_mode);
|
||||
ret = do_fchmod (lo, node, fd, attr->st_mode);
|
||||
else
|
||||
ret = do_chmod (lo, path, attr->st_mode);
|
||||
ret = do_chmod (lo, node, path, attr->st_mode);
|
||||
if (ret < 0)
|
||||
{
|
||||
fuse_reply_err (req, errno);
|
||||
@ -4161,6 +4223,24 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
|
||||
|
||||
if (uid != -1 || gid != -1)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (do_stat (node, fd, NULL, &st) < 0)
|
||||
{
|
||||
fuse_reply_err (req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uid == -1)
|
||||
{
|
||||
uid = st.st_uid;
|
||||
}
|
||||
|
||||
if (gid == -1)
|
||||
{
|
||||
gid = st.st_gid;
|
||||
}
|
||||
|
||||
if (fd >= 0)
|
||||
ret = do_fchown (lo, fd, uid, gid, node->ino->mode);
|
||||
else
|
||||
@ -5089,7 +5169,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
|
||||
return;
|
||||
}
|
||||
|
||||
ret = create_directory (lo, get_upper_layer (lo)->fd, path, NULL, pnode, -1,
|
||||
ret = create_directory (lo, get_upper_layer (lo)->fd, path, NULL, pnode, NULL, -1,
|
||||
get_uid (lo, ctx->uid), get_gid (lo, ctx->gid), mode & ~ctx->umask,
|
||||
true, &st);
|
||||
if (ret < 0)
|
||||
@ -5777,13 +5857,22 @@ main (int argc, char *argv[])
|
||||
}
|
||||
else if (lo.xattr_permissions == 2)
|
||||
{
|
||||
get_upper_layer (&lo)->stat_override_mode = STAT_OVERRIDE_USER;
|
||||
name = XATTR_OVERRIDE_STAT;
|
||||
get_upper_layer (&lo)->stat_override_mode = STAT_OVERRIDE_CONTAINERS;
|
||||
name = XATTR_OVERRIDE_CONTAINERS_STAT;
|
||||
}
|
||||
else
|
||||
error (EXIT_FAILURE, 0, "invalid value for xattr_permissions");
|
||||
|
||||
s = fgetxattr (get_upper_layer (&lo)->fd, name, data, sizeof (data));
|
||||
if (s < 0 && errno == ENODATA && lo.xattr_permissions == 2)
|
||||
{
|
||||
s = fgetxattr (get_upper_layer (&lo)->fd, XATTR_OVERRIDE_STAT, data, sizeof (data));
|
||||
if (s >= 0)
|
||||
{
|
||||
get_upper_layer (&lo)->stat_override_mode = STAT_OVERRIDE_USER;
|
||||
name = XATTR_OVERRIDE_STAT;
|
||||
}
|
||||
}
|
||||
if (s < 0)
|
||||
{
|
||||
bool found = false;
|
||||
@ -5794,15 +5883,19 @@ main (int argc, char *argv[])
|
||||
|
||||
for (l = get_lower_layers (&lo); l; l = l->next)
|
||||
{
|
||||
s = fgetxattr (l->fd, name, data, sizeof (data));
|
||||
if (s < 0 && errno != ENODATA)
|
||||
error (EXIT_FAILURE, errno, "fgetxattr mode from lower layer");
|
||||
if (s < 0 && lo.xattr_permissions == 2)
|
||||
switch (lo.xattr_permissions)
|
||||
{
|
||||
case 1:
|
||||
s = fgetxattr (l->fd, name, data, sizeof (data));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
s = fgetxattr (l->fd, XATTR_OVERRIDE_CONTAINERS_STAT, data, sizeof (data));
|
||||
if (s < 0 && errno != ENODATA)
|
||||
error (EXIT_FAILURE, errno, "fgetxattr mode from lower layer");
|
||||
if (s < 0 && errno == ENODATA)
|
||||
s = fgetxattr (l->fd, XATTR_OVERRIDE_STAT, data, sizeof (data));
|
||||
break;
|
||||
}
|
||||
|
||||
if (s > 0)
|
||||
{
|
||||
ret = fsetxattr (get_upper_layer (&lo)->fd, name, data, s, 0);
|
||||
|
@ -29,3 +29,27 @@ else
|
||||
fi
|
||||
|
||||
fusermount -u merged || [ $? -eq "${EXPECT_UMOUNT_STATUS:-0}" ]
|
||||
|
||||
# xattr_permissions=2
|
||||
rm -rf lower upper workdir merged
|
||||
mkdir lower upper workdir merged
|
||||
|
||||
touch upper/file
|
||||
unshare -r setcap cap_net_admin+ep upper/file
|
||||
|
||||
fuse-overlayfs -o lowerdir=lower,upperdir=upper,workdir=workdir,xattr_permissions=2 merged
|
||||
|
||||
# Ensure the security xattr namespace is isolated.
|
||||
test "$(unshare -r getcap merged/file)" = ''
|
||||
unshare -r setcap cap_net_admin+ep merged/file
|
||||
test "$(unshare -r getcap merged/file)" = 'merged/file cap_net_admin=ep'
|
||||
|
||||
# Ensure UID is preserved with chgrp.
|
||||
podman unshare chgrp 1 merged/file
|
||||
test $(podman unshare stat -c %u:%g merged/file) = 0:1
|
||||
|
||||
# Ensure UID and GID are preserved with chmod.
|
||||
chmod 600 merged/file
|
||||
test $(podman unshare stat -c %u:%g merged/file) = 0:1
|
||||
|
||||
fusermount -u merged || [ $? -eq "${EXPECT_UMOUNT_STATUS:-0}" ]
|
||||
|
10
utils.c
10
utils.c
@ -270,14 +270,10 @@ override_mode (struct ovl_layer *l, int fd, const char *abs_path, const char *pa
|
||||
if (fd >= 0)
|
||||
{
|
||||
ret = fgetxattr (fd, xattr_name, buf, sizeof (buf) - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
else if (abs_path)
|
||||
{
|
||||
ret = lgetxattr (abs_path, xattr_name, buf, sizeof (buf) - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -292,15 +288,11 @@ override_mode (struct ovl_layer *l, int fd, const char *abs_path, const char *pa
|
||||
if (fd >= 0)
|
||||
ret = fgetxattr (fd, xattr_name, buf, sizeof (buf) - 1);
|
||||
else
|
||||
{
|
||||
ret = lgetxattr (full_path, xattr_name, buf, sizeof (buf) - 1);
|
||||
if (ret < 0 && errno == ENODATA)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return errno == ENODATA ? 0 : ret;
|
||||
|
||||
buf[ret] = '\0';
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user