mirror of
https://github.com/containers/fuse-overlayfs.git
synced 2025-08-04 02:15: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:
|
jobs:
|
||||||
build_job:
|
build_job:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
name: Build on ${{ matrix.arch }}
|
name: Build on ${{ matrix.arch }}
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- arch: armv7
|
- arch: armv7
|
||||||
distro: ubuntu20.04
|
distro: ubuntu22.04
|
||||||
- arch: aarch64
|
- arch: aarch64
|
||||||
distro: ubuntu20.04
|
distro: ubuntu22.04
|
||||||
- arch: s390x
|
- arch: s390x
|
||||||
distro: ubuntu20.04
|
distro: ubuntu22.04
|
||||||
- arch: ppc64le
|
- arch: ppc64le
|
||||||
distro: ubuntu20.04
|
distro: ubuntu22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.1.0
|
- 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
|
name: Build
|
||||||
id: build
|
id: build
|
||||||
with:
|
with:
|
||||||
@ -34,7 +34,7 @@ jobs:
|
|||||||
|
|
||||||
install: |
|
install: |
|
||||||
apt-get update -q -y
|
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: |
|
run: |
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
@ -49,7 +49,7 @@ jobs:
|
|||||||
fuse-overlayfs
|
fuse-overlayfs
|
||||||
|
|
||||||
Test:
|
Test:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@ -66,7 +66,7 @@ jobs:
|
|||||||
- name: install dependencies
|
- name: install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update -q -y
|
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 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"
|
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
|
- name: Archive build artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: fuse-overlayfs-x86_64-ubuntu20.04
|
name: fuse-overlayfs-x86_64-ubuntu22.04
|
||||||
path: |
|
path: |
|
||||||
fuse-overlayfs
|
fuse-overlayfs
|
||||||
if: ${{ matrix.test == 'ovl-whiteouts' }}
|
if: ${{ matrix.test == 'ovl-whiteouts' }}
|
||||||
|
@ -6,12 +6,12 @@ import stat
|
|||||||
import errno
|
import errno
|
||||||
|
|
||||||
XATTR_OVERRIDE_STAT_PRIVILEGED = "security.fuseoverlayfs.override_stat"
|
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:
|
if os.geteuid() == 0:
|
||||||
xattr_name = XATTR_OVERRIDE_STAT_PRIVILEGED
|
xattr_name = XATTR_OVERRIDE_STAT_PRIVILEGED
|
||||||
else:
|
else:
|
||||||
xattr_name = XATTR_OVERRIDE_STAT
|
xattr_name = XATTR_OVERRIDE_CONTAINERS_STAT
|
||||||
|
|
||||||
cwd_fd = os.open(".", os.O_PATH)
|
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)
|
os.setxattr(path, xattr_name, str.encode(content), flags=os.XATTR_CREATE, follow_symlinks=False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if e.errno == errno.EEXIST:
|
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
|
return
|
||||||
raise e
|
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)
|
if (fgetxattr (l->fd, XATTR_PRIVILEGED_OVERRIDE_STAT, tmp, sizeof (tmp)) >= 0)
|
||||||
l->stat_override_mode = STAT_OVERRIDE_PRIVILEGED;
|
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)
|
else if (fgetxattr (l->fd, XATTR_OVERRIDE_CONTAINERS_STAT, tmp, sizeof (tmp)) >= 0)
|
||||||
l->stat_override_mode = STAT_OVERRIDE_CONTAINERS;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
243
main.c
243
main.c
@ -59,6 +59,7 @@
|
|||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <sys/xattr.h>
|
#include <sys/xattr.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/xattr.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <pthread.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 ORIGIN_XATTR "user.fuseoverlayfs.origin"
|
||||||
#define OPAQUE_XATTR "user.fuseoverlayfs.opaque"
|
#define OPAQUE_XATTR "user.fuseoverlayfs.opaque"
|
||||||
#define XATTR_CONTAINERS_PREFIX "user.containers."
|
#define XATTR_CONTAINERS_PREFIX "user.containers."
|
||||||
|
#define XATTR_CONTAINERS_OVERRIDE_PREFIX "user.containers.override_"
|
||||||
#define UNPRIVILEGED_XATTR_PREFIX "user.overlay."
|
#define UNPRIVILEGED_XATTR_PREFIX "user.overlay."
|
||||||
#define UNPRIVILEGED_OPAQUE_XATTR "user.overlay.opaque"
|
#define UNPRIVILEGED_OPAQUE_XATTR "user.overlay.opaque"
|
||||||
#define PRIVILEGED_XATTR_PREFIX "trusted.overlay."
|
#define PRIVILEGED_XATTR_PREFIX "trusted.overlay."
|
||||||
@ -524,11 +526,46 @@ has_prefix (const char *str, const char *pref)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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)
|
return ! (has_prefix (name, XATTR_PREFIX)
|
||||||
&& ! has_prefix (name, PRIVILEGED_XATTR_PREFIX)
|
|| has_prefix (name, PRIVILEGED_XATTR_PREFIX)
|
||||||
&& ! has_prefix (name, UNPRIVILEGED_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
|
static ssize_t
|
||||||
@ -539,17 +576,21 @@ write_permission_xattr (struct ovl_data *lo, int fd, const char *path, uid_t uid
|
|||||||
int ret;
|
int ret;
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
|
|
||||||
switch (lo->xattr_permissions)
|
switch (get_upper_layer (lo)->stat_override_mode)
|
||||||
{
|
{
|
||||||
case 0:
|
case STAT_OVERRIDE_NONE:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 1:
|
case STAT_OVERRIDE_USER:
|
||||||
|
name = XATTR_OVERRIDE_STAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STAT_OVERRIDE_PRIVILEGED:
|
||||||
name = XATTR_PRIVILEGED_OVERRIDE_STAT;
|
name = XATTR_PRIVILEGED_OVERRIDE_STAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case STAT_OVERRIDE_CONTAINERS:
|
||||||
name = XATTR_OVERRIDE_STAT;
|
name = XATTR_OVERRIDE_CONTAINERS_STAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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
|
#define fchownat ERROR
|
||||||
|
|
||||||
static int
|
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)
|
if (lo->xattr_permissions)
|
||||||
{
|
{
|
||||||
struct ovl_layer *upper = get_upper_layer (lo);
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (upper == NULL)
|
|
||||||
{
|
|
||||||
errno = EROFS;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
st.st_uid = 0;
|
st.st_uid = 0;
|
||||||
st.st_gid = 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 -1;
|
||||||
|
|
||||||
return write_permission_xattr (lo, fd, NULL, st.st_uid, st.st_gid, mode);
|
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
|
#define fchmod ERROR
|
||||||
|
|
||||||
static int
|
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)
|
if (lo->xattr_permissions)
|
||||||
{
|
{
|
||||||
struct ovl_layer *upper = get_upper_layer (lo);
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (upper == NULL)
|
|
||||||
{
|
|
||||||
errno = EROFS;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
st.st_uid = 0;
|
st.st_uid = 0;
|
||||||
st.st_gid = 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 -1;
|
||||||
|
|
||||||
return write_permission_xattr (lo, -1, path, st.st_uid, st.st_gid, mode);
|
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)
|
if (st_in)
|
||||||
memcpy (st, st_in, sizeof (*st));
|
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
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
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. */
|
/* in-place filter xattrs that cannot be accessed. */
|
||||||
static ssize_t
|
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;
|
ssize_t ret = 0;
|
||||||
char *it;
|
char *it;
|
||||||
@ -2598,14 +2636,17 @@ filter_xattrs_list (char *buf, ssize_t len)
|
|||||||
|
|
||||||
it_len = strlen (it) + 1;
|
it_len = strlen (it) + 1;
|
||||||
|
|
||||||
if (can_access_xattr (it))
|
if (can_access_xattr (l, it))
|
||||||
{
|
{
|
||||||
it += it_len;
|
it += it_len;
|
||||||
ret += it_len;
|
ret += it_len;
|
||||||
}
|
}
|
||||||
else
|
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);
|
memmove (it, next, buf + len - next);
|
||||||
len -= it_len;
|
len -= it_len;
|
||||||
@ -2665,7 +2706,7 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = filter_xattrs_list (buf, ret);
|
len = filter_xattrs_list (node->layer, buf, ret);
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
fuse_reply_xattr (req, len);
|
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;
|
ssize_t len;
|
||||||
struct ovl_node *node;
|
struct ovl_node *node;
|
||||||
struct ovl_data *lo = ovl_data (req);
|
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;
|
int ret;
|
||||||
|
|
||||||
if (UNLIKELY (ovl_debug (req)))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! can_access_xattr (name))
|
|
||||||
{
|
|
||||||
fuse_reply_err (req, ENODATA);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = do_lookup_file (lo, ino, NULL);
|
node = do_lookup_file (lo, ino, NULL);
|
||||||
if (node == NULL || node->whiteout)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = encode_xattr_name (node->layer, name_buf, name);
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, ENODATA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
buf = malloc (size);
|
value_buf = malloc (size);
|
||||||
if (buf == NULL)
|
if (value_buf == NULL)
|
||||||
{
|
{
|
||||||
fuse_reply_err (req, errno);
|
fuse_reply_err (req, errno);
|
||||||
return;
|
return;
|
||||||
@ -2716,12 +2759,12 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! node->hidden)
|
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
|
else
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
strconcat3 (path, PATH_MAX, lo->workdir, "/", node->path);
|
strconcat3 (path, PATH_MAX, lo->workdir, "/", node->path);
|
||||||
ret = getxattr (path, name, buf, size);
|
ret = getxattr (path, name, value_buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
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)
|
if (size == 0)
|
||||||
fuse_reply_xattr (req, len);
|
fuse_reply_xattr (req, len);
|
||||||
else
|
else
|
||||||
fuse_reply_buf (req, buf, len);
|
fuse_reply_buf (req, value_buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2756,7 +2799,8 @@ ovl_access (fuse_req_t req, fuse_ino_t ino, int mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
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)
|
for (it = buf; it - buf < xattr_len; it += strlen (it) + 1)
|
||||||
{
|
{
|
||||||
cleanup_free char *v = NULL;
|
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;
|
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;
|
continue;
|
||||||
|
|
||||||
s = safe_read_xattr (&v, sfd, it, 256);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsetxattr (dfd, it, v, s, 0) < 0)
|
if (fsetxattr (dfd, encoded_name, v, s, 0) < 0)
|
||||||
{
|
{
|
||||||
if (errno == EINVAL || errno == EOPNOTSUPP)
|
if (errno == EINVAL || errno == EOPNOTSUPP)
|
||||||
continue;
|
continue;
|
||||||
@ -2856,7 +2907,8 @@ static int create_node_directory (struct ovl_data *lo, struct ovl_node *src);
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct timespec *times,
|
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 ret;
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
@ -2920,7 +2972,7 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct
|
|||||||
goto out;
|
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)
|
if (ret < 0)
|
||||||
goto out;
|
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)
|
if (override_mode (src->layer, sfd, NULL, NULL, &st) < 0 && errno != ENODATA && errno != EOPNOTSUPP)
|
||||||
return -1;
|
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)
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
src->layer = get_upper_layer (lo);
|
src->layer = get_upper_layer (lo);
|
||||||
@ -3192,7 +3244,7 @@ copyup (struct ovl_data *lo, struct ovl_node *node)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto exit;
|
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)
|
if (ret < 0)
|
||||||
goto exit;
|
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 ();
|
cleanup_lock int l = enter_big_lock ();
|
||||||
struct ovl_data *lo = ovl_data (req);
|
struct ovl_data *lo = ovl_data (req);
|
||||||
struct ovl_node *node;
|
struct ovl_node *node;
|
||||||
|
char name_buf[XATTR_NAME_MAX + 1];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (UNLIKELY (ovl_debug (req)))
|
if (UNLIKELY (ovl_debug (req)))
|
||||||
@ -3484,12 +3537,6 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name,
|
|||||||
return;
|
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);
|
node = do_lookup_file (lo, ino, NULL);
|
||||||
if (node == NULL || node->whiteout)
|
if (node == NULL || node->whiteout)
|
||||||
{
|
{
|
||||||
@ -3504,6 +3551,13 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = encode_xattr_name (node->layer, name_buf, name);
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, EPERM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (! node->hidden)
|
if (! node->hidden)
|
||||||
ret = direct_setxattr (node->layer, node->path, name, value, size, flags);
|
ret = direct_setxattr (node->layer, node->path, name, value, size, flags);
|
||||||
else
|
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 ();
|
cleanup_lock int l = enter_big_lock ();
|
||||||
struct ovl_node *node;
|
struct ovl_node *node;
|
||||||
struct ovl_data *lo = ovl_data (req);
|
struct ovl_data *lo = ovl_data (req);
|
||||||
|
char name_buf[XATTR_NAME_MAX + 1];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (UNLIKELY (ovl_debug (req)))
|
if (UNLIKELY (ovl_debug (req)))
|
||||||
@ -3564,6 +3619,13 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = encode_xattr_name (node->layer, name_buf, name);
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, EPERM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (! node->hidden)
|
if (! node->hidden)
|
||||||
ret = direct_removexattr (node->layer, node->path, name);
|
ret = direct_removexattr (node->layer, node->path, name);
|
||||||
else
|
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 it is a writepage request, make sure to restore the setuid bit. */
|
||||||
if (fi->writepage && (inode->mode & (S_ISUID | S_ISGID)))
|
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);
|
fuse_reply_err (req, errno);
|
||||||
return;
|
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 (to_set & FUSE_SET_ATTR_MODE)
|
||||||
{
|
{
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
ret = do_fchmod (lo, fd, attr->st_mode);
|
ret = do_fchmod (lo, node, fd, attr->st_mode);
|
||||||
else
|
else
|
||||||
ret = do_chmod (lo, path, attr->st_mode);
|
ret = do_chmod (lo, node, path, attr->st_mode);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
fuse_reply_err (req, errno);
|
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)
|
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)
|
if (fd >= 0)
|
||||||
ret = do_fchown (lo, fd, uid, gid, node->ino->mode);
|
ret = do_fchown (lo, fd, uid, gid, node->ino->mode);
|
||||||
else
|
else
|
||||||
@ -5089,7 +5169,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
|
|||||||
return;
|
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,
|
get_uid (lo, ctx->uid), get_gid (lo, ctx->gid), mode & ~ctx->umask,
|
||||||
true, &st);
|
true, &st);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -5777,13 +5857,22 @@ main (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else if (lo.xattr_permissions == 2)
|
else if (lo.xattr_permissions == 2)
|
||||||
{
|
{
|
||||||
get_upper_layer (&lo)->stat_override_mode = STAT_OVERRIDE_USER;
|
get_upper_layer (&lo)->stat_override_mode = STAT_OVERRIDE_CONTAINERS;
|
||||||
name = XATTR_OVERRIDE_STAT;
|
name = XATTR_OVERRIDE_CONTAINERS_STAT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error (EXIT_FAILURE, 0, "invalid value for xattr_permissions");
|
error (EXIT_FAILURE, 0, "invalid value for xattr_permissions");
|
||||||
|
|
||||||
s = fgetxattr (get_upper_layer (&lo)->fd, name, data, sizeof (data));
|
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)
|
if (s < 0)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -5794,15 +5883,19 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
for (l = get_lower_layers (&lo); l; l = l->next)
|
for (l = get_lower_layers (&lo); l; l = l->next)
|
||||||
{
|
{
|
||||||
s = fgetxattr (l->fd, name, data, sizeof (data));
|
switch (lo.xattr_permissions)
|
||||||
if (s < 0 && errno != ENODATA)
|
|
||||||
error (EXIT_FAILURE, errno, "fgetxattr mode from lower layer");
|
|
||||||
if (s < 0 && lo.xattr_permissions == 2)
|
|
||||||
{
|
{
|
||||||
|
case 1:
|
||||||
|
s = fgetxattr (l->fd, name, data, sizeof (data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
s = fgetxattr (l->fd, XATTR_OVERRIDE_CONTAINERS_STAT, data, sizeof (data));
|
s = fgetxattr (l->fd, XATTR_OVERRIDE_CONTAINERS_STAT, data, sizeof (data));
|
||||||
if (s < 0 && errno != ENODATA)
|
if (s < 0 && errno == ENODATA)
|
||||||
error (EXIT_FAILURE, errno, "fgetxattr mode from lower layer");
|
s = fgetxattr (l->fd, XATTR_OVERRIDE_STAT, data, sizeof (data));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s > 0)
|
if (s > 0)
|
||||||
{
|
{
|
||||||
ret = fsetxattr (get_upper_layer (&lo)->fd, name, data, s, 0);
|
ret = fsetxattr (get_upper_layer (&lo)->fd, name, data, s, 0);
|
||||||
|
@ -29,3 +29,27 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
fusermount -u merged || [ $? -eq "${EXPECT_UMOUNT_STATUS:-0}" ]
|
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)
|
if (fd >= 0)
|
||||||
{
|
{
|
||||||
ret = fgetxattr (fd, xattr_name, buf, sizeof (buf) - 1);
|
ret = fgetxattr (fd, xattr_name, buf, sizeof (buf) - 1);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
else if (abs_path)
|
else if (abs_path)
|
||||||
{
|
{
|
||||||
ret = lgetxattr (abs_path, xattr_name, buf, sizeof (buf) - 1);
|
ret = lgetxattr (abs_path, xattr_name, buf, sizeof (buf) - 1);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -292,15 +288,11 @@ override_mode (struct ovl_layer *l, int fd, const char *abs_path, const char *pa
|
|||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
ret = fgetxattr (fd, xattr_name, buf, sizeof (buf) - 1);
|
ret = fgetxattr (fd, xattr_name, buf, sizeof (buf) - 1);
|
||||||
else
|
else
|
||||||
{
|
|
||||||
ret = lgetxattr (full_path, xattr_name, buf, sizeof (buf) - 1);
|
ret = lgetxattr (full_path, xattr_name, buf, sizeof (buf) - 1);
|
||||||
if (ret < 0 && errno == ENODATA)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return errno == ENODATA ? 0 : ret;
|
||||||
}
|
|
||||||
|
|
||||||
buf[ret] = '\0';
|
buf[ret] = '\0';
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user