2. `mkdir(2)`
2. `lseek(2)`
2. `readdir(2)`
-2. `readlink(2)`※
-2. `readlinkat(2)`※
-2. `rmdir(2)`※
-2. `unlink(2)`※
-2. `unlinkat(2)`※
-2. `link(2)`※
-2. `fsync(2)`※
+2. `readlink(2)`
+2. `readlinkat(2)`
+2. `rmdir(2)`
+2. `unlink(2)`
+2. `unlinkat(2)`
+2. `link(2)`
+2. `fsync(2)`
2. `dup(2)`
2. `dup2(2)`
-2. `symlink(2)`※
+2. `symlink(2)`
2. `chdir(2)`
2. `fchdir(2)`
2. `getcwd(2)`
2. `rename(2)`※
2. `mount(2)`
-2. `unmount` (a.k.a `umount(2)`)※
+2. `unmount` (a.k.a `umount(2)`)
2. `getxattr(2)`※
2. `setxattr(2)`※
2. `fgetxattr(2)`※
4. `pthread_kill`
4. `pthread_detach`
4. `pthread_sigmask`
+4. `getuid`
+4. `getgid`
+4. `geteuid`
+4. `getegid`
+4. `getgroups`
+4. `setuid`
+4. `setgid`
+4. `seteuid`
+4. `setegid`
+4. `setgroups`
+4. `chroot`
+4. `fchmodat`
+4. `fchownat`
+4. `faccessat`
**LunaixOS**
SYSCALL __lxsys_setgid
SYSCALL __lxsys_seteuid
SYSCALL __lxsys_setegid
-SYSCALL __lxsys_setgroups
\ No newline at end of file
+SYSCALL __lxsys_setgroups
+SYSCALL __lxsys_chroot
+SYSCALL __lxsys_fchmodat
+SYSCALL __lxsys_fchownat
+SYSCALL __lxsys_faccessat
\ No newline at end of file
struct load_context
{
struct exec_host* container;
+
ptr_t base;
ptr_t end;
ptr_t mem_sz;
ptr_t vms_mnt;
struct load_context exe;
+ struct v_inode* inode;
struct exec_arrptr argv;
struct exec_arrptr envp;
struct hstr* component,
int options);
+int
+vfs_walkat(int fd, const char* path, int at_opts,
+ struct v_dnode** dnode_out);
+
int
vfs_mount(const char* target,
const char* fs_name,
#define FSACL_WRITE 2
#define FSACL_EXEC 1
+#define FSACL_RWXMASK 0777
#define FSACL_U(x) (((x) & 0b111) << 6)
#define FSACL_G(x) (((x) & 0b111) << 3)
#define FSACL_O(x) ((x) & 0b111)
#define FSACL_oW FSACL_O(FSACL_WRITE)
#define FSACL_oX FSACL_O(FSACL_EXEC)
+#define FSACL_suid 04000
+#define FSACL_sgid 02000
+#define FSACL_svtx 01000
+
// permitted read (any usr or group matched)
#define FSACL_RD (FSACL_uRD | FSACL_gRD)
// permitted write (any usr or group matched)
#define FSACL_o(r, w, x) \
(v__(__fsacl_sel(o, r)) | v__(__fsacl_sel(o, w)) | v__(__fsacl_sel(o, x)))
+#define fsacl_test(acl, type) ((acl) & (FSACL_##type))
+
static inline bool must_inline
fsacl_allow_ops(unsigned int ops, unsigned int acl, uid_t uid, gid_t gid)
{
gid_t sgid;
struct user_scope uscope;
+ struct v_dnode* root;
int state;
int exit_code;
return __current->euid;
}
+static inline bool must_inline
+current_is_root()
+{
+ return current_euid() == 0;
+}
+
static inline gid_t must_inline
current_egid()
{
return __current->egid;
}
+static inline void must_inline
+current_set_egid(gid_t gid)
+{
+ __current->egid = gid;
+}
+
+static inline void must_inline
+current_set_euid(uid_t uid)
+{
+ __current->euid = uid;
+}
+
#endif /* __LUNAIX_PROCESS_H */
enum acl_match
check_current_acl(uid_t desired_u, gid_t desired_g);
+enum acl_match
+check_acl_between(uid_t u1, gid_t g1, uid_t u2, gid_t g2);
+
static inline bool
uscope_with_capability(const struct user_scope* proc_usr, caps_t cap)
{
#define O_RDWR FO_RDWR
#define O_TRUNC FO_TRUNC
+#define AT_SYMLINK_FOLLOW 0b0000
+#define AT_SYMLINK_NOFOLLOW 0b0001
+#define AT_FDCWD 0b0010
+#define AT_EACCESS 0b0100
+
+#define R_OK 0b100100100
+#define W_OK 0b010010010
+#define X_OK 0b001001001
+#define F_OK 0b111111111
+
/* Mount with read-only flag */
#define MNT_RO (1 << 0)
#define EDEADLK -31
#define EDQUOT -32
#define EPERM -33
+#define EACCESS -34
#endif /* __LUNAIX_STATUS_H */
// we set default access right to be 0660.
// TODO need a way to allow this to be changed
- fsapi_inode_setaccess(inode, FSACL_u(R, W, _) | FSACL_g(R, W, _));
+ fsapi_inode_setaccess(inode, FSACL_u(R, W, X) | FSACL_g(R, W, X) | FSACL_oX);
fsapi_inode_setowner(inode, 0, 0);
}
}
save_process_cmd(proc, argv);
+ container->inode = executable->inode;
errno = load_executable(&container->exe, executable);
if (errno) {
envp[])
{
int errno = 0;
+ int acl;
struct exec_host container;
if (!argv || !envp) {
signal_reset_context(¤t_thread->sigctx);
signal_reset_registry(__current->sigreg);
+ acl = container.inode->acl;
+ if (fsacl_test(acl, suid)) {
+ current_set_euid(container.inode->uid);
+ }
+
+ if (fsacl_test(acl, sgid)) {
+ current_set_egid(container.inode->gid);
+ }
+
done:
// set return value
store_retval(DO_STATUS(errno));
#include <lunaix/process.h>
#include <lunaix/spike.h>
+#include <usr/lunaix/fcntl_defs.h>
+
#include <klibc/string.h>
#define VFS_SYMLINK_DEPTH 16
if (path[0] == VFS_PATH_DELIM || !start) {
if ((walk_options & VFS_WALK_FSRELATIVE) && start) {
start = start->super_block->root;
- } else {
+ }
+ else if (unlikely(!__current)) {
start = vfs_sysroot;
- if (!vfs_sysroot->mnt) {
- fail("vfs: no root");
- }
+ }
+ else {
+ start = __current->root ?: vfs_sysroot;
+ }
+
+ if (unlikely(!start || !start->mnt)) {
+ fail("vfs: no root");
}
if (path[0] == VFS_PATH_DELIM) {
struct hstr name = HSTR(fname_buffer, 0);
char current = path[i++], lookahead;
- while (current) {
+ while (current)
+ {
lookahead = path[i++];
- if (current != VFS_PATH_DELIM) {
+
+ if (current != VFS_PATH_DELIM)
+ {
if (j >= VFS_NAME_MAXLEN - 1) {
return ENAMETOOLONG;
}
lock_dnode(current_level);
+ if (!check_allow_execute(current_inode)) {
+ errno = EACCESS;
+ goto error;
+ }
+
dnode = vfs_dcache_lookup(current_level, &name);
- if (!dnode) {
+ if (!dnode)
+ {
dnode = vfs_d_alloc(current_level, &name);
if (!dnode) {
assert(current_inode);
if (check_symlink_node(current_inode) &&
- !(walk_options & VFS_WALK_NOFOLLOW)) {
+ !(walk_options & VFS_WALK_NOFOLLOW))
+ {
const char* link;
struct v_inode_ops* iops;
cleanup:
vfs_d_free(dnode);
+
error:
*dentry = NULL;
return errno;
int options)
{
return vfs_walk(__current->cwd, path, dentry, component, options);
+}
+
+int
+vfs_walkat(int fd, const char* path, int at_opts, struct v_dnode** dnode_out)
+{
+ int errno, options = 0;
+ struct v_dnode *root_dnode;
+ struct v_fd* _fd;
+
+ if ((at_opts & AT_FDCWD)) {
+ root_dnode = __current->cwd;
+ }
+ else
+ {
+ errno = vfs_getfd(fd, &_fd);
+ if (errno) {
+ return errno;
+ }
+
+ root_dnode = _fd->file->dnode;
+ }
+
+ if ((at_opts & AT_SYMLINK_NOFOLLOW)) {
+ options |= VFS_WALK_NOFOLLOW;
+ }
+
+ errno = vfs_walk(root_dnode, path, dnode_out, NULL, options);
+ if (errno) {
+ return errno;
+ }
+
+ return 0;
}
\ No newline at end of file
{
vsb->ops.init_inode = ramfs_inode_init;
- return __ramfs_mknod(mount_point, NULL, RAMF_DIR);
+ int errno = __ramfs_mknod(mount_point, NULL, RAMF_DIR);
+
+ if (!errno) {
+ fsapi_inode_setaccess(mount_point->inode, FSACL_aX | FSACL_aR);
+ }
+
+ return errno;
}
int
#include <usr/lunaix/dirent_defs.h>
+#define INODE_ACCESSED 0
+#define INODE_MODIFY 1
+
static struct cake_pile* dnode_pile;
static struct cake_pile* inode_pile;
static struct cake_pile* file_pile;
static struct cake_pile* superblock_pile;
static struct cake_pile* fd_pile;
-struct v_dnode* vfs_sysroot;
+struct v_dnode* vfs_sysroot = NULL;
struct lru_zone *dnode_lru, *inode_lru;
return NULL;
}
+static void
+__vfs_touch_inode(struct v_inode* inode, const int type)
+{
+ if (type == INODE_MODIFY) {
+ inode->mtime = clock_unixtime();
+ }
+
+ else if (type == INODE_ACCESSED) {
+ inode->atime = clock_unixtime();
+ }
+
+ lru_use_one(inode_lru, &inode->lru);
+}
+
void
vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
{
return errno;
}
+
+static bool
+__check_unlinkable(struct v_dnode* dnode)
+{
+ int acl;
+ bool wr_self, wr_parent;
+ struct v_dnode* parent;
+
+ parent = dnode->parent;
+ acl = dnode->inode->acl;
+
+ wr_self = check_allow_write(dnode->inode);
+ wr_parent = check_allow_write(parent->inode);
+
+ if (!fsacl_test(acl, svtx)) {
+ return wr_self;
+ }
+
+ if (current_euid() == dnode->inode->uid) {
+ return true;
+ }
+
+ return wr_self && wr_parent;
+}
+
int
vfs_do_open(const char* path, int options)
{
goto unlock;
}
+ if (!check_allow_read(inode)) {
+ errno = EPERM;
+ goto unlock;
+ }
+
struct dir_context dctx = (struct dir_context) {
.cb_data = dent,
.read_complete_callback = __vfs_readdir_callback
{
int errno = 0;
struct v_fd* fd_s;
+ struct v_inode* inode;
+
if ((errno = vfs_getfd(fd, &fd_s))) {
goto done;
}
goto done;
}
- lock_inode(file->inode);
+ inode = file->inode;
+ lock_inode(inode);
- file->inode->atime = clock_unixtime();
+ __vfs_touch_inode(inode, INODE_ACCESSED);
- if (check_seqdev_node(file->inode) || (fd_s->flags & FO_DIRECT)) {
- errno = file->ops->read(file->inode, buf, count, file->f_pos);
+ if (check_seqdev_node(inode) || (fd_s->flags & FO_DIRECT)) {
+ errno = file->ops->read(inode, buf, count, file->f_pos);
} else {
- errno = pcache_read(file->inode, buf, count, file->f_pos);
+ errno = pcache_read(inode, buf, count, file->f_pos);
}
if (errno > 0) {
file->f_pos += errno;
- unlock_inode(file->inode);
+ unlock_inode(inode);
return errno;
}
- unlock_inode(file->inode);
+ unlock_inode(inode);
done:
return DO_STATUS(errno);
inode = file->inode;
lock_inode(inode);
- inode->mtime = clock_unixtime();
+ __vfs_touch_inode(inode, INODE_MODIFY);
if ((fd_s->flags & O_APPEND)) {
file->f_pos = inode->fsize;
}
lock_dnode(dnode);
+ if (!__check_unlinkable(dnode)) {
+ errno = EPERM;
+ goto done;
+ }
+
if ((errno = vfs_check_writable(dnode))) {
goto done;
}
return DO_STATUS(errno);
}
-int
+static int
__vfs_do_unlink(struct v_dnode* dnode)
{
int errno;
return EBUSY;
}
+ if (!__check_unlinkable(dnode)) {
+ return EPERM;
+ }
+
if ((errno = vfs_check_writable(dnode))) {
return errno;
}
return DO_STATUS(errno);
}
-int
-vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
+static int
+vfs_do_chdir_nolock(struct proc_info* proc, struct v_dnode* dnode)
{
- int errno = 0;
-
- lock_dnode(dnode);
-
if (!check_directory_node(dnode->inode)) {
- errno = ENOTDIR;
- goto done;
+ return ENOTDIR;
}
if (proc->cwd) {
vfs_ref_dnode(dnode);
proc->cwd = dnode;
+ return 0;
+}
+
+static int
+vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
+{
+ int errno = 0;
+
+ lock_dnode(dnode);
+
+ errno = vfs_do_chdir_nolock(proc, dnode);
+
unlock_dnode(dnode);
-done:
return errno;
}
return DO_STATUS(errno);
}
+
+__DEFINE_LXSYSCALL1(int, chroot, const char*, path)
+{
+ int errno;
+ struct v_dnode* dnode;
+ if ((errno = vfs_walk_proc(path, &dnode, NULL, 0))) {
+ return errno;
+ }
+
+ lock_dnode(dnode);
+
+ errno = vfs_do_chdir_nolock(__current, dnode);
+ if (errno) {
+ unlock_dnode(dnode);
+ goto done;
+ }
+
+ __current->root = dnode;
+
+ unlock_dnode(dnode);
+
+done:
+ return DO_STATUS(errno);
+}
+
__DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
{
int errno = 0;
.index = dev_uid(fdev) };
}
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL4(int, fchmodat, int, fd,
+ const char*, path, int, mode, int, flags)
+{
+ int errno;
+ struct v_dnode *dnode;
+ struct v_inode* inode;
+
+ errno = vfs_walkat(fd, path, flags, &dnode);
+ if (errno) {
+ goto done;
+ }
+
+ errno = vfs_check_writable(dnode);
+ if (errno) {
+ return errno;
+ }
+
+ inode = dnode->inode;
+ lock_inode(inode);
+
+ if (!current_is_root()) {
+ mode = mode & FSACL_RWXMASK;
+ }
+
+ inode->acl = mode;
+ __vfs_touch_inode(inode, INODE_MODIFY);
+
+ unlock_inode(inode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL5(int, fchownat, int, fd,
+ const char*, path, uid_t, uid, gid_t, gid, int, flags)
+{
+ int errno;
+ struct v_dnode *dnode;
+ struct v_inode *inode;
+
+ errno = vfs_walkat(fd, path, flags, &dnode);
+ if (errno) {
+ goto done;
+ }
+
+ errno = vfs_check_writable(dnode);
+ if (errno) {
+ return errno;
+ }
+
+ inode = dnode->inode;
+ lock_inode(inode);
+
+ inode->uid = uid;
+ inode->gid = gid;
+ __vfs_touch_inode(inode, INODE_MODIFY);
+
+ unlock_inode(inode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL4(int, faccessat, int, fd,
+ const char*, path, int, amode, int, flags)
+{
+ int errno, acl;
+ struct v_dnode *dnode;
+ struct v_inode *inode;
+ struct user_scope* uscope;
+
+ uid_t tuid;
+ gid_t tgid;
+
+ errno = vfs_walkat(fd, path, flags, &dnode);
+ if (errno) {
+ goto done;
+ }
+
+ if ((flags & AT_EACCESS)) {
+ tuid = current_euid();
+ tgid = current_egid();
+ }
+ else {
+ uscope = current_user_scope();
+ tuid = uscope->ruid;
+ tgid = uscope->rgid;
+ }
+
+ inode = dnode->inode;
+
+ acl = inode->acl;
+ acl &= amode;
+ acl &= check_acl_between(inode->uid, inode->gid, tuid, tgid);
+ if (!acl) {
+ errno = EACCESS;
+ }
+
done:
return DO_STATUS(errno);
}
\ No newline at end of file
}
return i + 1;
-}
\ No newline at end of file
+}
struct thread empty_thread_obj;
-volatile struct proc_info* __current;
+volatile struct proc_info* __current = NULL;
volatile struct thread* current_thread = &empty_thread_obj;
struct scheduler sched_ctx;
proc->created = clock_systime();
proc->pgid = proc->pid;
+ proc->root = vfs_sysroot;
+
proc->sigreg = vzalloc(sizeof(struct sigregistry));
proc->fdtable = vzalloc(sizeof(struct v_fdtable));
memcpy(to, from, sizeof(*to));
}
+enum acl_match
+check_acl_between(uid_t u1, gid_t g1, uid_t u2, gid_t g2)
+{
+ struct user_scope* uscope;
+
+ if (!u1 || u1 == u2)
+ return ACL_MATCH_U;
+
+ if (g1 == g2)
+ return ACL_MATCH_G;
+
+ return ACL_NO_MATCH;
+}
+
enum acl_match
check_current_acl(uid_t desired_u, gid_t desired_g)
{
+ enum acl_match match;
struct user_scope* uscope;
- if (!__current->euid || __current->euid == desired_u)
- {
- return ACL_MATCH_U;
+ if (unlikely(!__current)) {
+ return ACL_NO_MATCH;
}
- if (__current->egid == desired_g) {
- return ACL_MATCH_G;
+ match = check_acl_between(__current->euid, __current->egid,
+ desired_u, desired_g);
+
+ if (match != ACL_NO_MATCH) {
+ return match;
}
uscope = current_user_scope();