Added permission checks for chmod, link, rename and chown

Those clearly need to ask for permissions.
This commit is contained in:
BritishTeapot 2025-03-24 17:11:01 +01:00
parent 6342de0dd3
commit da37376fde
3 changed files with 104 additions and 3 deletions

View File

@ -108,7 +108,29 @@ static int xmp_getattr(const char *path, struct stat *stbuf,
static int xmp_access(const char *path, int mask) { static int xmp_access(const char *path, int mask) {
int res; int res;
res = access(path, mask); // if mask is F_OK, then we don't need to check the permissions
// (is that possible?)
if (mask != F_OK) {
struct process_info pi;
struct fuse_context *fc = fuse_get_context();
pi.PID = fc->pid;
pi.UID = fc->uid;
pi.name = get_process_name_by_pid(pi.PID);
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(real_filename(path), pi)) {
free(pi.name);
return -EACCES;
}
free(pi.name);
}
res = source_access(path, mask);
if (res == -1) if (res == -1)
return -errno; return -errno;
@ -304,6 +326,30 @@ static int xmp_rename(const char *from, const char *to, unsigned int flags) {
if (flags) if (flags)
return -EINVAL; return -EINVAL;
struct process_info pi;
struct fuse_context *fc = fuse_get_context();
pi.PID = fc->pid;
pi.UID = fc->uid;
pi.name = get_process_name_by_pid(pi.PID);
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(real_filename(from), pi)) {
free(pi.name);
return -EACCES;
}
// the "to" file may exist and the process needs to get persmission to modify
// it
if (source_access(to, F_OK) == 0 &&
!interactive_access(real_filename(to), pi)) {
free(pi.name);
return -EACCES;
}
free(pi.name);
res = source_rename(from, to); res = source_rename(from, to);
if (res == -1) if (res == -1)
return -errno; return -errno;
@ -313,6 +359,22 @@ static int xmp_rename(const char *from, const char *to, unsigned int flags) {
static int xmp_link(const char *from, const char *to) { static int xmp_link(const char *from, const char *to) {
int res; int res;
struct process_info pi;
struct fuse_context *fc = fuse_get_context();
pi.PID = fc->pid;
pi.UID = fc->uid;
pi.name = get_process_name_by_pid(pi.PID);
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(real_filename(from), pi)) {
free(pi.name);
return -EACCES;
}
// no need to check the access to the "to" file, see link(2)
free(pi.name);
res = source_link(from, to); res = source_link(from, to);
if (res == -1) if (res == -1)
@ -323,6 +385,20 @@ static int xmp_link(const char *from, const char *to) {
static int xmp_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) { static int xmp_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) {
int res; int res;
struct process_info pi;
struct fuse_context *fc = fuse_get_context();
pi.PID = fc->pid;
pi.UID = fc->uid;
pi.name = get_process_name_by_pid(pi.PID);
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(real_filename(path), pi)) {
free(pi.name);
return -EACCES;
}
free(pi.name);
if (fi) if (fi)
res = fchmod(fi->fh, mode); res = fchmod(fi->fh, mode);
@ -334,9 +410,27 @@ static int xmp_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) {
return 0; return 0;
} }
/**
* This filesystem is not designed for multiuser operation (e.g. with
* allow_other) so there is little point in having chown implemnted
*/
static int xmp_chown(const char *path, uid_t uid, gid_t gid, static int xmp_chown(const char *path, uid_t uid, gid_t gid,
struct fuse_file_info *fi) { struct fuse_file_info *fi) {
int res; int res;
struct process_info pi;
struct fuse_context *fc = fuse_get_context();
pi.PID = fc->pid;
pi.UID = fc->uid;
pi.name = get_process_name_by_pid(pi.PID);
// fprintf(stderr, "%s, %d\n", path, ask_access(path, pi));
if (!interactive_access(real_filename(path), pi)) {
free(pi.name);
return -EACCES;
}
free(pi.name);
if (fi) if (fi)
res = fchown(fi->fh, uid, gid); res = fchown(fi->fh, uid, gid);
@ -660,7 +754,7 @@ static off_t xmp_lseek(const char *path, off_t off, int whence,
static const struct fuse_operations xmp_oper = { static const struct fuse_operations xmp_oper = {
.init = xmp_init, .init = xmp_init,
.getattr = xmp_getattr, .getattr = xmp_getattr,
// .access = xmp_access, .access = xmp_access,
.readlink = xmp_readlink, .readlink = xmp_readlink,
.opendir = xmp_opendir, .opendir = xmp_opendir,
.readdir = xmp_readdir, .readdir = xmp_readdir,
@ -676,7 +770,7 @@ static const struct fuse_operations xmp_oper = {
.chown = xmp_chown, .chown = xmp_chown,
.truncate = xmp_truncate, .truncate = xmp_truncate,
#ifdef HAVE_UTIMENSAT #ifdef HAVE_UTIMENSAT
// .utimens = xmp_utimens, // .utimens = xmp_utimens,
#endif #endif
.create = xmp_create, .create = xmp_create,
.open = xmp_open, .open = xmp_open,

View File

@ -66,6 +66,11 @@ int source_symlink(const char *target, const char *linkpath) {
return symlinkat(target, handle.root_fd, relative_linkpath); return symlinkat(target, handle.root_fd, relative_linkpath);
} }
int source_access(const char *filename, int mode) {
const char *relative_filename = source_filename_translate(filename);
return faccessat(handle.root_fd, relative_filename, mode, 0);
}
DIR *source_opendir(const char *filename) { DIR *source_opendir(const char *filename) {
const char *relative_filename = source_filename_translate(filename); const char *relative_filename = source_filename_translate(filename);
int fd = openat(handle.root_fd, relative_filename, 0); int fd = openat(handle.root_fd, relative_filename, 0);

View File

@ -47,6 +47,8 @@ int source_chown(const char *filename, uid_t owner, gid_t group);
int source_truncate(const char *filename, off_t length); int source_truncate(const char *filename, off_t length);
int source_access(const char *filename, int mode);
/* `open` and `create` are designed to correspond to fuse operations, not the /* `open` and `create` are designed to correspond to fuse operations, not the
* libc's `open(2)`. Both of them actually call `openat`. */ * libc's `open(2)`. Both of them actually call `openat`. */