From: Lunaixsky Date: Tue, 18 Mar 2025 23:16:03 +0000 (+0000) Subject: basic user, group and capability housekeeping. X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/7bc179c25a1a0b7053959a7b7f2f530da1edbf13?ds=inline basic user, group and capability housekeeping. add usrscope for process-wise user management implement {get,set}*{uid,euid,gid,egid,groups} syscalls basic acl checking mechanism move common syscall table to arch/generic. --- diff --git a/lunaix-os/arch/generic/includes/asm-generic/syscall_nr.inc b/lunaix-os/arch/generic/includes/asm-generic/syscall_nr.inc new file mode 100644 index 0000000..7590c4b --- /dev/null +++ b/lunaix-os/arch/generic/includes/asm-generic/syscall_nr.inc @@ -0,0 +1,78 @@ +#ifndef SYSCALL +# error "SYSCALL missing pointer type" +#endif + +SYSCALL 0 +SYSCALL __lxsys_fork /* 1 */ +SYSCALL __lxsys_yield +SYSCALL __lxsys_sbrk +SYSCALL __lxsys_brk +SYSCALL __lxsys_getpid /* 5 */ +SYSCALL __lxsys_getppid +SYSCALL __lxsys_sleep +SYSCALL __lxsys_exit +SYSCALL __lxsys_wait +SYSCALL __lxsys_waitpid /* 10 */ +SYSCALL __lxsys_sigreturn +SYSCALL __lxsys_sigprocmask +SYSCALL __lxsys_sys_sigaction +SYSCALL __lxsys_pause +SYSCALL __lxsys_kill /* 15 */ +SYSCALL __lxsys_alarm +SYSCALL __lxsys_sigpending +SYSCALL __lxsys_sigsuspend +SYSCALL __lxsys_open +SYSCALL __lxsys_close /* 20 */ +SYSCALL __lxsys_read +SYSCALL __lxsys_write +SYSCALL __lxsys_sys_readdir +SYSCALL __lxsys_mkdir +SYSCALL __lxsys_lseek /* 25 */ +SYSCALL __lxsys_geterrno +SYSCALL __lxsys_readlink +SYSCALL __lxsys_readlinkat +SYSCALL __lxsys_rmdir +SYSCALL __lxsys_unlink /* 30 */ +SYSCALL __lxsys_unlinkat +SYSCALL __lxsys_link +SYSCALL __lxsys_fsync +SYSCALL __lxsys_dup +SYSCALL __lxsys_dup2 /* 35 */ +SYSCALL __lxsys_realpathat +SYSCALL __lxsys_symlink +SYSCALL __lxsys_chdir +SYSCALL __lxsys_fchdir +SYSCALL __lxsys_getcwd /* 40 */ +SYSCALL __lxsys_rename +SYSCALL __lxsys_mount +SYSCALL __lxsys_unmount +SYSCALL __lxsys_getxattr +SYSCALL __lxsys_setxattr /* 45 */ +SYSCALL __lxsys_fgetxattr +SYSCALL __lxsys_fsetxattr +SYSCALL __lxsys_ioctl +SYSCALL __lxsys_getpgid +SYSCALL __lxsys_setpgid /* 50 */ +SYSCALL __lxsys_syslog +SYSCALL __lxsys_sys_mmap +SYSCALL __lxsys_munmap +SYSCALL __lxsys_execve +SYSCALL __lxsys_fstat /* 55 */ +SYSCALL __lxsys_pollctl +SYSCALL __lxsys_th_create +SYSCALL __lxsys_th_self +SYSCALL __lxsys_th_exit +SYSCALL __lxsys_th_join /* 60 */ +SYSCALL __lxsys_th_kill +SYSCALL __lxsys_th_detach +SYSCALL __lxsys_th_sigmask +SYSCALL __lxsys_getuid +SYSCALL __lxsys_getgid +SYSCALL __lxsys_geteuid +SYSCALL __lxsys_getegid +SYSCALL __lxsys_getgroups +SYSCALL __lxsys_setuid +SYSCALL __lxsys_setgid +SYSCALL __lxsys_seteuid +SYSCALL __lxsys_setegid +SYSCALL __lxsys_setgroups \ No newline at end of file diff --git a/lunaix-os/arch/x86/LBuild b/lunaix-os/arch/x86/LBuild index 941453b..ed4b4f8 100644 --- a/lunaix-os/arch/x86/LBuild +++ b/lunaix-os/arch/x86/LBuild @@ -29,7 +29,8 @@ sources([ "gdbstub.c", "trace.c", "hart.c", - "failsafe.S" + "failsafe.S", + "syscall_lut.S" ]) sources({ diff --git a/lunaix-os/arch/x86/syscall32.S b/lunaix-os/arch/x86/syscall32.S index b8915ed..3fb96b4 100644 --- a/lunaix-os/arch/x86/syscall32.S +++ b/lunaix-os/arch/x86/syscall32.S @@ -1,6 +1,5 @@ #define __ASM__ #include -#include "syscall_nr.inc" .section .text .type syscall_hndlr, @function @@ -16,7 +15,7 @@ jae 2f shll $2, %eax - addl $syscall_table, %eax + addl $__syscall_table, %eax cmpl $0, (%eax) jne 1f 2: diff --git a/lunaix-os/arch/x86/syscall64.S b/lunaix-os/arch/x86/syscall64.S index 6125a84..cce528a 100644 --- a/lunaix-os/arch/x86/syscall64.S +++ b/lunaix-os/arch/x86/syscall64.S @@ -1,6 +1,5 @@ #define __ASM__ #include -#include "syscall_nr.inc" #include "asm/variants/interrupt64.S.inc" .section .text @@ -18,7 +17,7 @@ jae 2f shlq $3, %rax // %rax * 8 - movabsq $syscall_table, %r8 + movabsq $__syscall_table, %r8 addq %r8, %rax cmpq $0, (%rax) jne 1f diff --git a/lunaix-os/arch/x86/syscall_lut.S b/lunaix-os/arch/x86/syscall_lut.S new file mode 100644 index 0000000..4bee0b4 --- /dev/null +++ b/lunaix-os/arch/x86/syscall_lut.S @@ -0,0 +1,20 @@ +#define __ASM__ +#include + +#ifdef CONFIG_ARCH_X86_64 +# define SYSCALL .8byte +# define SIZE 8 +#else +# define SIZE 4 +# define SYSCALL .4byte +#endif + +.section .data + .global __syscall_table + __syscall_table: + 1: + #include "syscall_nr.inc" + 2: + .rept __SYSCALL_MAX - (2b - 1b) / SIZE + .long 0 + .endr \ No newline at end of file diff --git a/lunaix-os/arch/x86/syscall_nr.inc b/lunaix-os/arch/x86/syscall_nr.inc index c30a720..85762da 100644 --- a/lunaix-os/arch/x86/syscall_nr.inc +++ b/lunaix-os/arch/x86/syscall_nr.inc @@ -1,79 +1,3 @@ -#ifdef CONFIG_ARCH_X86_64 -# define PTR .8byte -# define SIZE 8 -#else -# define PTR .4byte -# define SIZE 4 -#endif +#include -.section .data - syscall_table: - 1: - PTR 0 - PTR __lxsys_fork /* 1 */ - PTR __lxsys_yield - PTR __lxsys_sbrk - PTR __lxsys_brk - PTR __lxsys_getpid /* 5 */ - PTR __lxsys_getppid - PTR __lxsys_sleep - PTR __lxsys_exit - PTR __lxsys_wait - PTR __lxsys_waitpid /* 10 */ - PTR __lxsys_sigreturn - PTR __lxsys_sigprocmask - PTR __lxsys_sys_sigaction - PTR __lxsys_pause - PTR __lxsys_kill /* 15 */ - PTR __lxsys_alarm - PTR __lxsys_sigpending - PTR __lxsys_sigsuspend - PTR __lxsys_open - PTR __lxsys_close /* 20 */ - PTR __lxsys_read - PTR __lxsys_write - PTR __lxsys_sys_readdir - PTR __lxsys_mkdir - PTR __lxsys_lseek /* 25 */ - PTR __lxsys_geterrno - PTR __lxsys_readlink - PTR __lxsys_readlinkat - PTR __lxsys_rmdir - PTR __lxsys_unlink /* 30 */ - PTR __lxsys_unlinkat - PTR __lxsys_link - PTR __lxsys_fsync - PTR __lxsys_dup - PTR __lxsys_dup2 /* 35 */ - PTR __lxsys_realpathat - PTR __lxsys_symlink - PTR __lxsys_chdir - PTR __lxsys_fchdir - PTR __lxsys_getcwd /* 40 */ - PTR __lxsys_rename - PTR __lxsys_mount - PTR __lxsys_unmount - PTR __lxsys_getxattr - PTR __lxsys_setxattr /* 45 */ - PTR __lxsys_fgetxattr - PTR __lxsys_fsetxattr - PTR __lxsys_ioctl - PTR __lxsys_getpgid - PTR __lxsys_setpgid /* 50 */ - PTR __lxsys_syslog - PTR __lxsys_sys_mmap - PTR __lxsys_munmap - PTR __lxsys_execve - PTR __lxsys_fstat /* 55 */ - PTR __lxsys_pollctl - PTR __lxsys_th_create - PTR __lxsys_th_self - PTR __lxsys_th_exit - PTR __lxsys_th_join /* 60 */ - PTR __lxsys_th_kill - PTR __lxsys_th_detach - PTR __lxsys_th_sigmask - 2: - .rept __SYSCALL_MAX - (2b - 1b) / SIZE - .long 0 - .endr \ No newline at end of file +// arch specifics syscalls goes here diff --git a/lunaix-os/includes/lunaix/limits.h b/lunaix-os/includes/lunaix/limits.h new file mode 100644 index 0000000..9855801 --- /dev/null +++ b/lunaix-os/includes/lunaix/limits.h @@ -0,0 +1,6 @@ +#ifndef __LUNAIX_LIMITS_H +#define __LUNAIX_LIMITS_H + +#define NGROUPS_MAX 128 + +#endif /* __LUNAIX_LIMITS_H */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index 86e485e..8d4c70b 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -13,6 +13,8 @@ #include #include #include +#include + #include @@ -113,7 +115,7 @@ struct thread { /* Any change to *critical section*, including layout, size - must be reflected in arch/x86/interrupt.S.inc to avoid + must be reflected in arch//interrupt.S.inc to avoid disaster! */ struct @@ -167,6 +169,13 @@ struct proc_info pid_t pgid; time_t created; + uid_t euid; + uid_t suid; + gid_t egid; + gid_t sgid; + + struct user_scope uscope; + int state; int exit_code; }; @@ -463,5 +472,22 @@ thread_stats_user_elapse(struct thread* thread) return stats->last_entry - stats->last_leave; } +static inline struct user_scope* +current_user_scope() +{ + return &__current->uscope; +} + +static inline uid_t must_inline +current_euid() +{ + return __current->euid; +} + +static inline gid_t must_inline +current_egid() +{ + return __current->egid; +} #endif /* __LUNAIX_PROCESS_H */ diff --git a/lunaix-os/includes/lunaix/types.h b/lunaix-os/includes/lunaix/types.h index e065273..fe06333 100644 --- a/lunaix-os/includes/lunaix/types.h +++ b/lunaix-os/includes/lunaix/types.h @@ -2,6 +2,7 @@ #define __LUNAIX_TYPES_H #include +#include #include #include @@ -15,6 +16,9 @@ typedef unsigned int u32_t; typedef unsigned long ptr_t; typedef unsigned long reg_t; +typedef unsigned int uid_t; +typedef unsigned int gid_t; + #ifndef CONFIG_ARCH_BITS_64 typedef unsigned long long u64_t; #else diff --git a/lunaix-os/includes/lunaix/usercaps.h b/lunaix-os/includes/lunaix/usercaps.h new file mode 100644 index 0000000..b30aea9 --- /dev/null +++ b/lunaix-os/includes/lunaix/usercaps.h @@ -0,0 +1,19 @@ +#ifndef __LUNAIX_USERCAPS_H +#define __LUNAIX_USERCAPS_H + +typedef unsigned long caps_t; + +/* + * Definition of user capabilities (withdrawn draft POSIX.1e) + */ + +#define CAP_SETUID 0 +#define CAP_SETGID 1 +#define CAP_CHOWN 2 +#define CAP_DAC_OVERRIDE 3 +#define CAP_FSETID 4 +#define CAP_KILL 5 +#define CAP_SYS_CHROOT 6 +#define CAP_SYS_TIM 7 + +#endif /* __LUNAIX_USERCAPS_H */ diff --git a/lunaix-os/includes/lunaix/usrscope.h b/lunaix-os/includes/lunaix/usrscope.h new file mode 100644 index 0000000..4d3c1f7 --- /dev/null +++ b/lunaix-os/includes/lunaix/usrscope.h @@ -0,0 +1,57 @@ +#ifndef __LUNAIX_USRSCOPE_H +#define __LUNAIX_USRSCOPE_H + +#include +#include "usercaps.h" + +struct ugroup_obj +{ + gid_t* list; + unsigned int maxcap; + unsigned int refs; +}; + +struct user_scope +{ + uid_t ruid; + gid_t rgid; + caps_t capabilities; + + struct ugroup_obj* grps; +}; + +/* + Process ACL check result. + The encoding here is designed to be the mask for file ACL value +*/ +enum acl_match +{ + ACL_MATCH_U = 0b111000000, // (U)ser + ACL_MATCH_G = 0b000111000, // (G)roup + ACL_NO_MATCH = 0b000000111, // (O)ther +}; + +#define user_groups(uscope) ((uscope)->grps) + +#define grp_list_end ((gid_t)-1) + +int +uscope_setgroups(struct user_scope* proc_usr, + const gid_t* grps, unsigned int len); + +void +uscope_copy(struct user_scope* from, struct user_scope* to); + +bool +uscope_membership(struct user_scope* proc_usr, gid_t gid); + +enum acl_match +check_current_acl(uid_t desired_u, gid_t desired_g); + +static inline bool +uscope_with_capability(const struct user_scope* proc_usr, caps_t cap) +{ + return !!(proc_usr->capabilities & (1UL << cap)); +} + +#endif /* __LUNAIX_USRSCOPE_H */ diff --git a/lunaix-os/includes/usr/lunaix/status.h b/lunaix-os/includes/usr/lunaix/status.h index df37b61..ce0a571 100644 --- a/lunaix-os/includes/usr/lunaix/status.h +++ b/lunaix-os/includes/usr/lunaix/status.h @@ -36,5 +36,6 @@ #define EAGAIN -30 #define EDEADLK -31 #define EDQUOT -32 +#define EPERM -33 #endif /* __LUNAIX_STATUS_H */ diff --git a/lunaix-os/kernel/LBuild b/lunaix-os/kernel/LBuild index 8e92773..3e0a7be 100644 --- a/lunaix-os/kernel/LBuild +++ b/lunaix-os/kernel/LBuild @@ -17,6 +17,7 @@ sources([ "bcache.c", "syscall.c", "changeling.c", + "usrscope.c", "kprint/kp_records.c", "kprint/kprintf.c", "time/clock.c", diff --git a/lunaix-os/kernel/process/process.c b/lunaix-os/kernel/process/process.c index bb5008d..e9fab24 100644 --- a/lunaix-os/kernel/process/process.c +++ b/lunaix-os/kernel/process/process.c @@ -17,46 +17,6 @@ LOG_MODULE("PROC") -__DEFINE_LXSYSCALL(pid_t, getpid) -{ - return __current->pid; -} - -__DEFINE_LXSYSCALL(pid_t, getppid) -{ - return __current->parent->pid; -} - -__DEFINE_LXSYSCALL(pid_t, getpgid) -{ - return __current->pgid; -} - -__DEFINE_LXSYSCALL2(int, setpgid, pid_t, pid, pid_t, pgid) -{ - struct proc_info* proc = pid ? get_process(pid) : __current; - - if (!proc) { - syscall_result(EINVAL); - return -1; - } - - pgid = pgid ? pgid : proc->pid; - - struct proc_info* gruppenfuhrer = get_process(pgid); - - if (!gruppenfuhrer || proc->pgid == gruppenfuhrer->pid) { - syscall_result(EINVAL); - return -1; - } - - llist_delete(&proc->grp_member); - llist_append(&gruppenfuhrer->grp_member, &proc->grp_member); - - proc->pgid = pgid; - return 0; -} - int spawn_process(struct thread** created, ptr_t entry, bool with_ustack) { @@ -130,4 +90,163 @@ fail: ptr_t proc_vmroot() { return __current->mm->vmroot; +} + +__DEFINE_LXSYSCALL(pid_t, getpid) +{ + return __current->pid; +} + +__DEFINE_LXSYSCALL(pid_t, getppid) +{ + return __current->parent->pid; +} + +__DEFINE_LXSYSCALL(pid_t, getpgid) +{ + return __current->pgid; +} + +__DEFINE_LXSYSCALL2(int, setpgid, pid_t, pid, pid_t, pgid) +{ + struct proc_info* proc = pid ? get_process(pid) : __current; + + if (!proc) { + syscall_result(EINVAL); + return -1; + } + + pgid = pgid ? pgid : proc->pid; + + struct proc_info* gruppenfuhrer = get_process(pgid); + + if (!gruppenfuhrer || proc->pgid == gruppenfuhrer->pid) { + syscall_result(EINVAL); + return -1; + } + + llist_delete(&proc->grp_member); + llist_append(&gruppenfuhrer->grp_member, &proc->grp_member); + + proc->pgid = pgid; + return 0; +} + +static inline bool +__can_change_real_id(const struct user_scope* procu, caps_t id_cap) { + if (uscope_with_capability(procu, id_cap)) { + return true; + } + + if (check_current_acl(0, 0) != ACL_NO_MATCH) { + return true; + } + + return false; +} + +__DEFINE_LXSYSCALL1(int, setuid, uid_t, uid) +{ + struct user_scope* procu; + + procu = current_user_scope(); + + if (__can_change_real_id(procu, CAP_SETUID)) + { + procu->ruid = uid; + } + + __current->suid = uid; + __current->euid = uid; + + return 0; +} + +__DEFINE_LXSYSCALL1(int, setgid, gid_t, gid) +{ + struct user_scope* procu; + + procu = current_user_scope(); + + if (__can_change_real_id(procu, CAP_SETGID)) + { + procu->rgid = gid; + } + + __current->sgid = gid; + __current->egid = gid; + + return 0; +} + +__DEFINE_LXSYSCALL1(int, seteuid, uid_t, euid) +{ + __current->euid = euid; + + return 0; +} + +__DEFINE_LXSYSCALL1(int, setegid, gid_t, egid) +{ + __current->egid = egid; + + return 0; +} + +__DEFINE_LXSYSCALL2(int, setgroups, const gid_t*, gids, unsigned int, len) +{ + struct user_scope* procu; + + procu = current_user_scope(); + + if (check_current_acl(0, 0) == ACL_NO_MATCH) { + return EPERM; + } + + if (uscope_with_capability(procu, CAP_SETGID)) { + return EPERM; + } + + return uscope_setgroups(procu, gids, len); +} + + +__DEFINE_LXSYSCALL(uid_t, getuid) +{ + return current_user_scope()->ruid; +} + +__DEFINE_LXSYSCALL(gid_t, getgid) +{ + return current_user_scope()->rgid; +} + +__DEFINE_LXSYSCALL(uid_t, geteuid) +{ + return __current->euid; +} + +__DEFINE_LXSYSCALL(gid_t, getegid) +{ + return __current->egid; +} + +__DEFINE_LXSYSCALL2(int, getgroups, gid_t*, out_buf, unsigned int, len) +{ + struct user_scope* procu; + struct ugroup_obj* gobj; + + procu = current_user_scope(); + gobj = user_groups(procu); + + assert(gobj); + len = MIN(gobj->maxcap, len); + + unsigned i = 0; + for (; i < len && gobj->list[i] != grp_list_end; i++) + { + out_buf[i] = gobj->list[i]; + } + + return i + 1; } \ No newline at end of file diff --git a/lunaix-os/kernel/usrscope.c b/lunaix-os/kernel/usrscope.c new file mode 100644 index 0000000..334cad7 --- /dev/null +++ b/lunaix-os/kernel/usrscope.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include + +#include + +#define GLIST_INIT_LEN 8 + +static struct ugroup_obj* +__alloc_groups_obj(unsigned int len) +{ + unsigned int size; + struct ugroup_obj* ugo; + + assert(len >= GLIST_INIT_LEN); + + ugo = valloc(sizeof(*ugo)); + ugo->refs = 1; + + size = len * sizeof(gid_t); + ugo->list = valloc(size); + ugo->maxcap = size; + + memset(ugo->list, grp_list_end, size); + return ugo; +} + +static inline void +__ref_groups_obj(struct ugroup_obj* ugo) +{ + ugo->refs++; +} + +static void +__unref_groups_obj(struct ugroup_obj* ugo) +{ + ugo->refs--; + if (ugo->refs) { + return; + } + + vfree_safe(ugo->list); + vfree(ugo); +} + +static struct ugroup_obj* +__modify_group_obj(struct user_scope* procu, unsigned int new_len) +{ + struct ugroup_obj* ugo; + + ugo = procu->grps; + if (!ugo) { + return __alloc_groups_obj(GLIST_INIT_LEN); + } + + __unref_groups_obj(ugo); + + new_len = MAX(new_len, ugo->maxcap); + ugo = __alloc_groups_obj(new_len); + procu->grps = ugo; + + return ugo; +} + +int +uscope_setgroups(struct user_scope* proc_usr, + const gid_t* grps, unsigned int len) +{ + struct ugroup_obj* ugo; + + if (len > NGROUPS_MAX) { + return E2BIG; + } + + ugo = __modify_group_obj(proc_usr, len); + memcpy(ugo->list, grps, len * sizeof(gid_t)); + + return 0; +} + +bool +uscope_membership(struct user_scope* proc_usr, gid_t gid) +{ + struct ugroup_obj* ugo; + + ugo = proc_usr->grps; + if (unlikely(!ugo)) { + return false; + } + + for (unsigned i = 0; i < ugo->maxcap; i++) + { + if (ugo->list[i] != grp_list_end) { + break; + } + + if (ugo->list[i] == gid) { + return true; + } + } + + return false; +} + +void +uscope_copy(struct user_scope* to, struct user_scope* from) +{ + __ref_groups_obj(from->grps); + memcpy(to, from, sizeof(*to)); +} + + +enum acl_match +check_current_acl(uid_t desired_u, gid_t desired_g) +{ + struct user_scope* uscope; + + if (!__current->euid || __current->euid == desired_u) + { + return ACL_MATCH_U; + } + + if (__current->egid == desired_g) { + return ACL_MATCH_G; + } + + uscope = current_user_scope(); + if (uscope_membership(uscope, desired_g)) { + return ACL_MATCH_G; + } + + return ACL_NO_MATCH; +} \ No newline at end of file