From 62d0cd17069d26ef8cb594c92118628f26670253 Mon Sep 17 00:00:00 2001 From: Matheus Date: Tue, 27 Aug 2024 22:20:22 -0300 Subject: [PATCH] auth: AUTH_ACTIONS_FILESYSTEM_RENAME --- kernel-src/fs/vfs.c | 16 +++++++++++++- kernel-src/include/kernel/auth.h | 1 + kernel-src/sys/defaultauth.c | 38 ++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index 602f9a8b..99df5cde 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -563,7 +563,21 @@ int vfs_rename(vnode_t *srcref, char *srcpath, vnode_t *dstref, char *dstpath, i if (src != dst) VOP_LOCK(src); // lock it again for the rename if they arent the same - if (0) + // check if we can rename the old file + err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_RENAME, src, srcdir) ? EACCES : 0; + if (err) + goto cleanup_child; + + if (dst) { + // and if we have a file, check if we can replace it + err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_UNLINK, dst, dstdir) ? EACCES : 0; + if (err) + goto cleanup_child; + } + + // and if we can then write the new link to the directory + err = VOP_ACCESS(dstdir, V_ACCESS_WRITE, getcred()); + if (err) goto cleanup_child; err = VOP_RENAME(srcdir, src, srccomp, dstdir, dst, dstcomp, flags); diff --git a/kernel-src/include/kernel/auth.h b/kernel-src/include/kernel/auth.h index f082f094..9677d023 100644 --- a/kernel-src/include/kernel/auth.h +++ b/kernel-src/include/kernel/auth.h @@ -26,6 +26,7 @@ #define AUTH_ACTIONS_FILESYSTEM_SETATTR 8 #define AUTH_ACTIONS_FILESYSTEM_MOUNT 16 #define AUTH_ACTIONS_FILESYSTEM_UNLINK 32 +#define AUTH_ACTIONS_FILESYSTEM_RENAME 64 #define AUTH_ACTIONS_CRED_SETRESUID 1 #define AUTH_ACTIONS_CRED_SETRESGID 2 diff --git a/kernel-src/sys/defaultauth.c b/kernel-src/sys/defaultauth.c index 9f2f0346..a737e426 100644 --- a/kernel-src/sys/defaultauth.c +++ b/kernel-src/sys/defaultauth.c @@ -8,6 +8,19 @@ goto done; \ } +static inline bool writecheck(cred_t *cred, vattr_t *attr) { + if (CRED_IS_ESU(cred)) + return true; + else if (attr->uid == cred->euid && (attr->mode & V_ATTR_MODE_USER_WRITE)) + return true; + else if (attr->uid != cred->euid && attr->gid == cred->egid && (attr->mode & V_ATTR_MODE_GROUP_WRITE)) + return true; + else if (attr->uid != cred->euid && attr->gid != cred->egid && (attr->mode & V_ATTR_MODE_OTHERS_WRITE)) + return true; + else + return false; +} + static int filesystem(cred_t *cred, int actions, void *arg0, void *arg1, void *arg2) { vnode_t *vnode = arg0; // expected locked vnode_t *dirvnode = arg1; // expected locked @@ -21,13 +34,7 @@ static int filesystem(cred_t *cred, int actions, void *arg0, void *arg1, void *a int weight = 0; if (actions & AUTH_ACTIONS_FILESYSTEM_WRITE) { - if (CRED_IS_ESU(cred)) - weight += 1; - else if (attr.uid == cred->euid && (attr.mode & V_ATTR_MODE_USER_WRITE)) - weight += 1; - else if (attr.uid != cred->euid && attr.gid == cred->egid && (attr.mode & V_ATTR_MODE_GROUP_WRITE)) - weight += 1; - else if (attr.uid != cred->euid && attr.gid != cred->egid && (attr.mode & V_ATTR_MODE_OTHERS_WRITE)) + if (writecheck(cred, &attr)) weight += 1; else return AUTH_DECISION_DENY; @@ -86,23 +93,24 @@ static int filesystem(cred_t *cred, int actions, void *arg0, void *arg1, void *a DONE_CHECK(actions); } - if (actions & AUTH_ACTIONS_FILESYSTEM_UNLINK) { + if (actions & (AUTH_ACTIONS_FILESYSTEM_UNLINK | AUTH_ACTIONS_FILESYSTEM_RENAME)) { __assert(dirvnode); bool dosticky = false; if (CRED_IS_ESU(cred)) { dosticky = false; - weight += 1; - } else if (dirattr.uid == cred->euid && (dirattr.mode & V_ATTR_MODE_USER_WRITE)) { - dosticky = true; - } else if (dirattr.uid != cred->euid && dirattr.gid == cred->egid && (dirattr.mode & V_ATTR_MODE_GROUP_WRITE)) { - dosticky = true; - } else if (dirattr.uid != cred->euid && dirattr.gid != cred->egid && (dirattr.mode & V_ATTR_MODE_OTHERS_WRITE)) { + } else if (writecheck(cred, &dirattr)) { dosticky = true; } else { return AUTH_DECISION_DENY; } + // when renaming, we need to make sure we can also change the .. entry for the renamed + // directory when it is a directory + if ((actions & AUTH_ACTIONS_FILESYSTEM_RENAME) && vnode->type == V_TYPE_DIR && writecheck(cred, &attr) == false) { + return AUTH_DECISION_DENY; + } + if (dosticky && (dirattr.mode & V_ATTR_MODE_STICKY)) { // sticky directory, file can only be unlinked if: // - user requesting deletion is root (already checked for) @@ -115,6 +123,8 @@ static int filesystem(cred_t *cred, int actions, void *arg0, void *arg1, void *a weight += 1; else return AUTH_DECISION_DENY; + } else { + weight += 1; } DONE_CHECK(actions);