mirror of
https://github.com/containers/fuse-overlayfs.git
synced 2025-08-04 02:15:58 -04:00
Merge pull request #228 from giuseppe/override-file-mode-and-owner
fuse-overlays: introduce xattr to override gid/uid/mode
This commit is contained in:
commit
519ce4df6f
51
contrib/fix-mode.py
Executable file
51
contrib/fix-mode.py
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import stat
|
||||||
|
import errno
|
||||||
|
|
||||||
|
XATTR_OVERRIDE_STAT_PRIVILEGED = "security.fuseoverlayfs.override_stat"
|
||||||
|
XATTR_OVERRIDE_STAT = "user.fuseoverlayfs.override_stat"
|
||||||
|
|
||||||
|
if os.geteuid() == 0:
|
||||||
|
xattr_name = XATTR_OVERRIDE_STAT_PRIVILEGED
|
||||||
|
else:
|
||||||
|
xattr_name = XATTR_OVERRIDE_STAT
|
||||||
|
|
||||||
|
cwd_fd = os.open(".", os.O_PATH)
|
||||||
|
|
||||||
|
def fix_path(path):
|
||||||
|
st = os.lstat(path)
|
||||||
|
content = "%s:%s:%o" % (st.st_uid, st.st_gid, stat.S_IMODE(st.st_mode))
|
||||||
|
|
||||||
|
try:
|
||||||
|
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))
|
||||||
|
return
|
||||||
|
raise e
|
||||||
|
|
||||||
|
fd = os.open(path, os.O_PATH|os.O_NOFOLLOW|os.O_NONBLOCK)
|
||||||
|
try:
|
||||||
|
proc_path = "/proc/self/fd/%d" % fd
|
||||||
|
os.chmod(proc_path, 0o755)
|
||||||
|
except Exception as e:
|
||||||
|
if e.errno != errno.ENOTSUP:
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
os.close(fd)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_mode_directory(d):
|
||||||
|
for root, dirs, files in os.walk(d, topdown=False):
|
||||||
|
for i in dirs+files:
|
||||||
|
path = os.path.join(root, i)
|
||||||
|
fix_path(path)
|
||||||
|
fix_path(d)
|
||||||
|
|
||||||
|
for i in sys.argv[1:]:
|
||||||
|
fix_mode_directory(i)
|
||||||
|
|
||||||
|
|
92
direct.c
92
direct.c
@ -34,6 +34,9 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define XATTR_OVERRIDE_STAT "user.fuseoverlayfs.override_stat"
|
||||||
|
#define XATTR_PRIVILEGED_OVERRIDE_STAT "security.fuseoverlayfs.override_stat"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
direct_file_exists (struct ovl_layer *l, const char *pathname)
|
direct_file_exists (struct ovl_layer *l, const char *pathname)
|
||||||
{
|
{
|
||||||
@ -76,11 +79,69 @@ direct_getxattr (struct ovl_layer *l, const char *path, const char *name, char *
|
|||||||
return lgetxattr (full_path, name, buf, size);
|
return lgetxattr (full_path, name, buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
override_mode (struct ovl_layer *l, int fd, const char *path, struct stat *st)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
mode_t mode;
|
||||||
|
char buf[64];
|
||||||
|
cleanup_close int cleanup_fd = -1;
|
||||||
|
const char *xattr_name;
|
||||||
|
|
||||||
|
if (l->has_stat_override == 0 && l->has_privileged_stat_override == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
xattr_name = l->has_privileged_stat_override ? XATTR_PRIVILEGED_OVERRIDE_STAT : XATTR_OVERRIDE_STAT;
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
ret = fgetxattr (fd, xattr_name, buf, sizeof (buf) - 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char full_path[PATH_MAX];
|
||||||
|
|
||||||
|
full_path[0] = '\0';
|
||||||
|
ret = open_fd_or_get_path (l, path, full_path, &cleanup_fd, O_RDONLY);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
fd = cleanup_fd;
|
||||||
|
|
||||||
|
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)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[ret] = '\0';
|
||||||
|
|
||||||
|
ret = sscanf (buf, "%d:%d:%o", &uid, &gid, &mode);
|
||||||
|
if (ret != 3)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->st_uid = uid;
|
||||||
|
st->st_gid = gid;
|
||||||
|
st->st_mode = (st->st_mode & S_IFMT) | mode;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
direct_fstat (struct ovl_layer *l, int fd, const char *path, unsigned int mask, struct stat *st)
|
direct_fstat (struct ovl_layer *l, int fd, const char *path, unsigned int mask, struct stat *st)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_STATX
|
|
||||||
int ret;
|
int ret;
|
||||||
|
#ifdef HAVE_STATX
|
||||||
struct statx stx;
|
struct statx stx;
|
||||||
|
|
||||||
ret = statx (fd, "", AT_STATX_DONT_SYNC|AT_EMPTY_PATH, mask, &stx);
|
ret = statx (fd, "", AT_STATX_DONT_SYNC|AT_EMPTY_PATH, mask, &stx);
|
||||||
@ -88,21 +149,27 @@ direct_fstat (struct ovl_layer *l, int fd, const char *path, unsigned int mask,
|
|||||||
if (ret < 0 && errno == ENOSYS)
|
if (ret < 0 && errno == ENOSYS)
|
||||||
goto fallback;
|
goto fallback;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
statx_to_stat (&stx, st);
|
{
|
||||||
|
statx_to_stat (&stx, st);
|
||||||
|
return override_mode (l, fd, path, st);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fallback:
|
fallback:
|
||||||
return fstat (fd, st);
|
ret = fstat (fd, st);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return override_mode (l, fd, path, st);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags, unsigned int mask)
|
direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags, unsigned int mask)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_STATX
|
|
||||||
int ret;
|
int ret;
|
||||||
|
#ifdef HAVE_STATX
|
||||||
struct statx stx;
|
struct statx stx;
|
||||||
|
|
||||||
ret = statx (l->fd, path, AT_STATX_DONT_SYNC|flags, mask, &stx);
|
ret = statx (l->fd, path, AT_STATX_DONT_SYNC|flags, mask, &stx);
|
||||||
@ -110,12 +177,19 @@ direct_statat (struct ovl_layer *l, const char *path, struct stat *st, int flags
|
|||||||
if (ret < 0 && errno == ENOSYS)
|
if (ret < 0 && errno == ENOSYS)
|
||||||
goto fallback;
|
goto fallback;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
statx_to_stat (&stx, st);
|
{
|
||||||
|
statx_to_stat (&stx, st);
|
||||||
|
return override_mode (l, -1, path, st);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
fallback:
|
fallback:
|
||||||
return fstatat (l->fd, path, st, flags);
|
ret = fstatat (l->fd, path, st, flags);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return override_mode (l, -1, path, st);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dirent *
|
static struct dirent *
|
||||||
@ -164,6 +238,7 @@ direct_readlinkat (struct ovl_layer *l, const char *path, char *buf, size_t bufs
|
|||||||
static int
|
static int
|
||||||
direct_load_data_source (struct ovl_layer *l, const char *opaque, const char *path, int n_layer)
|
direct_load_data_source (struct ovl_layer *l, const char *opaque, const char *path, int n_layer)
|
||||||
{
|
{
|
||||||
|
char tmp[64];
|
||||||
l->path = realpath (path, NULL);
|
l->path = realpath (path, NULL);
|
||||||
if (l->path == NULL)
|
if (l->path == NULL)
|
||||||
{
|
{
|
||||||
@ -179,6 +254,11 @@ direct_load_data_source (struct ovl_layer *l, const char *opaque, const char *pa
|
|||||||
return l->fd;
|
return l->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fgetxattr (l->fd, XATTR_PRIVILEGED_OVERRIDE_STAT, tmp, sizeof (tmp)) >= 0)
|
||||||
|
l->has_privileged_stat_override = 1;
|
||||||
|
else if (fgetxattr (l->fd, XATTR_OVERRIDE_STAT, tmp, sizeof (tmp)) >= 0)
|
||||||
|
l->has_stat_override = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +112,8 @@ struct ovl_layer
|
|||||||
bool low;
|
bool low;
|
||||||
|
|
||||||
void *data_source_private_data;
|
void *data_source_private_data;
|
||||||
|
unsigned int has_stat_override : 1;
|
||||||
|
unsigned int has_privileged_stat_override : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* a data_source defines the methods for accessing a lower layer. */
|
/* a data_source defines the methods for accessing a lower layer. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user