diff --git a/kernel-src/fs/devfs.c b/kernel-src/fs/devfs.c index a0ef733c..a9ff7f8b 100644 --- a/kernel-src/fs/devfs.c +++ b/kernel-src/fs/devfs.c @@ -191,7 +191,7 @@ int devfs_munmap(vnode_t *node, void *addr, uintmax_t offset, int flags, cred_t } int devfs_access(vnode_t *vnode, mode_t mode, cred_t *cred) { - return auth_filesystem_check(cred, auth_filesystem_convertaccess(mode), vnode) ? EACCES : 0; + return auth_filesystem_check(cred, auth_filesystem_convertaccess(mode), vnode, NULL) ? EACCES : 0; } int devfs_isatty(vnode_t *node) { diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index cf7b6517..da16f7b9 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -1243,7 +1243,7 @@ static int ext2_getdents(vnode_t *vnode, dent_t *buffer, size_t count, uintmax_t } static int ext2_access(vnode_t *vnode, mode_t mode, cred_t *cred) { - return auth_filesystem_check(cred, auth_filesystem_convertaccess(mode), vnode) ? EACCES : 0; + return auth_filesystem_check(cred, auth_filesystem_convertaccess(mode), vnode, NULL) ? EACCES : 0; } static int ext2_readlink(vnode_t *vnode, char **link, cred_t *cred) { diff --git a/kernel-src/fs/tmpfs.c b/kernel-src/fs/tmpfs.c index da0c2347..b80a64e8 100644 --- a/kernel-src/fs/tmpfs.c +++ b/kernel-src/fs/tmpfs.c @@ -238,7 +238,7 @@ static int tmpfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offse } static int tmpfs_access(vnode_t *vnode, mode_t mode, cred_t *cred) { - return auth_filesystem_check(cred, auth_filesystem_convertaccess(mode), vnode) ? EACCES : 0; + return auth_filesystem_check(cred, auth_filesystem_convertaccess(mode), vnode, NULL) ? EACCES : 0; } static int tmpfs_unlink(vnode_t *node, vnode_t *child, char *name, cred_t *cred) { diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index 6703f930..602f9a8b 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -85,7 +85,7 @@ int vfs_mount(vnode_t *backing, vnode_t *pathref, char *path, char *name, void * if (err) return err; - err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_MOUNT, mounton); + err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_MOUNT, mounton, NULL); if (err) { // locked by vfs_lookup VOP_UNLOCK(mounton); @@ -487,22 +487,15 @@ int vfs_unlink(vnode_t *ref, char *path) { goto cleanup; } - // TODO auth check - if (0) { - // locked by VOP_LOOKUP - VOP_UNLOCK(child); - // locked by vfs_lookup, unlocked by VOP_LOOKUP if component is ".." - if (!isdotdot) - VOP_UNLOCK(parent); - VOP_RELEASE(child); - VOP_RELEASE(parent); - return err; - } + err = auth_filesystem_check(getcred(), AUTH_ACTIONS_FILESYSTEM_UNLINK, child, parent) ? EACCES : 0; + if (err) + goto cleanup_release; err = VOP_UNLINK(parent, child, component, getcred()); + cleanup_release: // locked by VOP_LOOKUP VOP_UNLOCK(child); - // locked by vfs_lookup, unlocked by VOP_LOOKUP if component is ".." + // locked by vfs_lookup, unlocked by VOP_LOOKUP if component is ".." if (!isdotdot) VOP_UNLOCK(parent); @@ -570,7 +563,6 @@ 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 - // TODO auth check if (0) goto cleanup_child; diff --git a/kernel-src/include/kernel/auth.h b/kernel-src/include/kernel/auth.h index 196d6cfd..f082f094 100644 --- a/kernel-src/include/kernel/auth.h +++ b/kernel-src/include/kernel/auth.h @@ -25,6 +25,7 @@ #define AUTH_ACTIONS_FILESYSTEM_READ 4 #define AUTH_ACTIONS_FILESYSTEM_SETATTR 8 #define AUTH_ACTIONS_FILESYSTEM_MOUNT 16 +#define AUTH_ACTIONS_FILESYSTEM_UNLINK 32 #define AUTH_ACTIONS_CRED_SETRESUID 1 #define AUTH_ACTIONS_CRED_SETRESGID 2 @@ -44,8 +45,8 @@ typedef struct { void auth_registerlistener(int scope, authlistener_t listener); int auth_check(int scope, cred_t *cred, int actions, void *arg0, void *arg1, void *arg2); -static inline int auth_filesystem_check(cred_t *cred, int actions, vnode_t *vnode) { - return auth_check(AUTH_SCOPE_FILESYSTEM, cred, actions, vnode, NULL, NULL); +static inline int auth_filesystem_check(cred_t *cred, int actions, vnode_t *vnode, vnode_t *dirvnode) { + return auth_check(AUTH_SCOPE_FILESYSTEM, cred, actions, vnode, dirvnode, NULL); } static inline int auth_system_check(cred_t *cred, int actions) { diff --git a/kernel-src/sys/defaultauth.c b/kernel-src/sys/defaultauth.c index 765d76e9..9f2f0346 100644 --- a/kernel-src/sys/defaultauth.c +++ b/kernel-src/sys/defaultauth.c @@ -10,10 +10,15 @@ 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 vattr_t attr; VOP_GETATTR(vnode, &attr, NULL); + vattr_t dirattr; + if (dirvnode) + VOP_GETATTR(dirvnode, &dirattr, NULL); + int weight = 0; if (actions & AUTH_ACTIONS_FILESYSTEM_WRITE) { if (CRED_IS_ESU(cred)) @@ -77,8 +82,43 @@ static int filesystem(cred_t *cred, int actions, void *arg0, void *arg1, void *a weight += 1; else return AUTH_DECISION_DENY; + + DONE_CHECK(actions); } + if (actions & AUTH_ACTIONS_FILESYSTEM_UNLINK) { + __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)) { + dosticky = true; + } else { + 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) + // OR + // - user requesting deletion has write access (already checked for) AND + // - effective user requesting deletion is owner of directory + // OR + // - effective user requesting deletion is owner of file + if (dirattr.uid == cred->euid || attr.uid == cred->euid) + weight += 1; + else + return AUTH_DECISION_DENY; + } + + DONE_CHECK(actions); + } done: return weight ? AUTH_DECISION_ALLOW : AUTH_DECISION_DEFER; diff --git a/kernel-src/sys/syscalls/chmod.c b/kernel-src/sys/syscalls/chmod.c index 2d4c1644..2aba528e 100644 --- a/kernel-src/sys/syscalls/chmod.c +++ b/kernel-src/sys/syscalls/chmod.c @@ -10,7 +10,7 @@ static int dochmod(vnode_t *node, mode_t mode) { vattr_t attr; cred_t *cred = &_cpu()->thread->proc->cred; - int e = auth_filesystem_check(cred, AUTH_ACTIONS_FILESYSTEM_SETATTR, node); + int e = auth_filesystem_check(cred, AUTH_ACTIONS_FILESYSTEM_SETATTR, node, NULL); if (e) return e; diff --git a/kernel-src/sys/syscalls/fchownat.c b/kernel-src/sys/syscalls/fchownat.c index 914468c5..c23e3514 100644 --- a/kernel-src/sys/syscalls/fchownat.c +++ b/kernel-src/sys/syscalls/fchownat.c @@ -50,7 +50,7 @@ syscallret_t syscall_fchownat(context_t *, int fd, char *upath, uid_t owner, gid goto cleanup; } - ret.errno = auth_filesystem_check(&_cpu()->thread->proc->cred, AUTH_ACTIONS_FILESYSTEM_SETATTR, node); + ret.errno = auth_filesystem_check(&_cpu()->thread->proc->cred, AUTH_ACTIONS_FILESYSTEM_SETATTR, node, NULL); if (ret.errno) { VOP_UNLOCK(node); goto cleanup; diff --git a/kernel-src/sys/syscalls/utime.c b/kernel-src/sys/syscalls/utime.c index ea1b9b74..6fc4c765 100644 --- a/kernel-src/sys/syscalls/utime.c +++ b/kernel-src/sys/syscalls/utime.c @@ -71,7 +71,7 @@ syscallret_t syscall_utimensat(context_t *, int fd, char *upath, timespec_t uts[ attr.atime = ts[0]; attr.mtime = ts[1]; - ret.errno = auth_filesystem_check(&_cpu()->thread->proc->cred, AUTH_ACTIONS_FILESYSTEM_SETATTR, node); + ret.errno = auth_filesystem_check(&_cpu()->thread->proc->cred, AUTH_ACTIONS_FILESYSTEM_SETATTR, node, NULL); if (ret.errno) { if (uts == NULL) ret.errno = VOP_ACCESS(node, V_ACCESS_WRITE, &_cpu()->thread->proc->cred);