diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2002-07-19 02:01:00 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2002-07-19 02:01:00 -0700 |
| commit | 1c0fe622c8847e1caab384a81cf96de2f1ac05d8 (patch) | |
| tree | ea83fc894fbd386dba63ddeac33c7be5a729978d /kernel | |
| parent | 2b15fe6334aebd7d3340f8b826acb79b138afa74 (diff) | |
LSM: Enable the security framework. This includes basic task control hooks.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/capability.c | 19 | ||||
| -rw-r--r-- | kernel/exit.c | 11 | ||||
| -rw-r--r-- | kernel/fork.c | 13 | ||||
| -rw-r--r-- | kernel/kmod.c | 2 | ||||
| -rw-r--r-- | kernel/ptrace.c | 8 | ||||
| -rw-r--r-- | kernel/sched.c | 41 | ||||
| -rw-r--r-- | kernel/signal.c | 3 | ||||
| -rw-r--r-- | kernel/sys.c | 178 | ||||
| -rw-r--r-- | kernel/uid16.c | 8 |
9 files changed, 169 insertions, 114 deletions
diff --git a/kernel/capability.c b/kernel/capability.c index 5796b182005c..223d22dece42 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -63,6 +63,7 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) data.permitted = cap_t(target->cap_permitted); data.inheritable = cap_t(target->cap_inheritable); data.effective = cap_t(target->cap_effective); + ret = security_ops->capget(target, &data.effective, &data.inheritable, &data.permitted); out: read_unlock(&tasklist_lock); @@ -87,9 +88,7 @@ static inline void cap_set_pg(int pgrp, kernel_cap_t *effective, for_each_task(target) { if (target->pgrp != pgrp) continue; - target->cap_effective = *effective; - target->cap_inheritable = *inheritable; - target->cap_permitted = *permitted; + security_ops->capset_set(target, effective, inheritable, permitted); } } @@ -106,9 +105,7 @@ static inline void cap_set_all(kernel_cap_t *effective, for_each_task(target) { if (target == current || target->pid == 1) continue; - target->cap_effective = *effective; - target->cap_inheritable = *inheritable; - target->cap_permitted = *permitted; + security_ops->capset_set(target, effective, inheritable, permitted); } } @@ -166,7 +163,9 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) ret = -EPERM; - /* verify restrictions on target's new Inheritable set */ + if (security_ops->capset_check(target, &effective, &inheritable, &permitted)) + goto out; + if (!cap_issubset(inheritable, cap_combine(target->cap_inheritable, current->cap_permitted))) goto out; @@ -182,6 +181,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) ret = 0; + /* having verified that the proposed changes are legal, + we now put them into effect. */ if (pid < 0) { if (pid == -1) /* all procs other than current and init */ cap_set_all(&effective, &inheritable, &permitted); @@ -189,9 +190,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) else /* all procs in process group */ cap_set_pg(-pid, &effective, &inheritable, &permitted); } else { - target->cap_effective = effective; - target->cap_inheritable = inheritable; - target->cap_permitted = permitted; + security_ops->capset_set(target, &effective, &inheritable, &permitted); } out: diff --git a/kernel/exit.c b/kernel/exit.c index c47a4c045fea..f727a3c511c8 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -14,6 +14,7 @@ #include <linux/personality.h> #include <linux/tty.h> #include <linux/namespace.h> +#include <linux/security.h> #include <linux/acct.h> #include <linux/file.h> #include <linux/binfmts.h> @@ -61,6 +62,7 @@ static void release_task(struct task_struct * p) wait_task_inactive(p); #endif atomic_dec(&p->user->processes); + security_ops->task_free_security(p); free_uid(p->user); unhash_process(p); @@ -187,10 +189,7 @@ void reparent_to_init(void) /* cpus_allowed? */ /* rt_priority? */ /* signals? */ - current->cap_effective = CAP_INIT_EFF_SET; - current->cap_inheritable = CAP_INIT_INH_SET; - current->cap_permitted = CAP_FULL_SET; - current->keep_capabilities = 0; + security_ops->task_reparent_to_init(current); memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim))); current->user = INIT_USER; @@ -625,6 +624,10 @@ repeat: if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) && !(options & __WALL)) continue; + + if (security_ops->task_wait(p)) + continue; + flag = 1; switch (p->state) { case TASK_STOPPED: diff --git a/kernel/fork.c b/kernel/fork.c index c0fb979902fe..f99f9e69521a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -24,7 +24,7 @@ #include <linux/file.h> #include <linux/binfmts.h> #include <linux/fs.h> -#include <linux/mm.h> +#include <linux/security.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -618,6 +618,10 @@ struct task_struct *do_fork(unsigned long clone_flags, if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); + retval = security_ops->task_create(clone_flags); + if (retval) + goto fork_out; + retval = -ENOMEM; p = dup_task_struct(current); if (!p) @@ -697,13 +701,16 @@ struct task_struct *do_fork(unsigned long clone_flags, p->array = NULL; p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; + p->security = NULL; INIT_LIST_HEAD(&p->local_pages); retval = -ENOMEM; + if (security_ops->task_alloc_security(p)) + goto bad_fork_cleanup; /* copy all the process information */ if (copy_semundo(clone_flags, p)) - goto bad_fork_cleanup; + goto bad_fork_cleanup_security; if (copy_files(clone_flags, p)) goto bad_fork_cleanup_semundo; if (copy_fs(clone_flags, p)) @@ -812,6 +819,8 @@ bad_fork_cleanup_files: exit_files(p); /* blocking */ bad_fork_cleanup_semundo: exit_semundo(p); +bad_fork_cleanup_security: + security_ops->task_free_security(p); bad_fork_cleanup: put_exec_domain(p->thread_info->exec_domain); if (p->binfmt && p->binfmt->module) diff --git a/kernel/kmod.c b/kernel/kmod.c index 05388d9557fa..c3b7e90aecdc 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -134,7 +134,7 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[]) /* Give kmod all effective privileges.. */ curtask->euid = curtask->fsuid = 0; curtask->egid = curtask->fsgid = 0; - cap_set_full(curtask->cap_effective); + security_ops->task_kmod_set_label(); /* Allow execve args to be in kernel space. */ set_fs(KERNEL_DS); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 24d41164144e..1a64a0c03b95 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -41,7 +41,9 @@ int ptrace_check_attach(struct task_struct *child, int kill) int ptrace_attach(struct task_struct *task) { + int retval; task_lock(task); + retval = -EPERM; if (task->pid <= 1) goto bad; if (task == current) @@ -53,7 +55,6 @@ int ptrace_attach(struct task_struct *task) (current->uid != task->uid) || (current->gid != task->egid) || (current->gid != task->sgid) || - (!cap_issubset(task->cap_permitted, current->cap_permitted)) || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto bad; rmb(); @@ -62,6 +63,9 @@ int ptrace_attach(struct task_struct *task) /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) goto bad; + retval = security_ops->ptrace(current, task); + if (retval) + goto bad; /* Go */ task->ptrace |= PT_PTRACED; @@ -82,7 +86,7 @@ int ptrace_attach(struct task_struct *task) bad: task_unlock(task); - return -EPERM; + return retval; } int ptrace_detach(struct task_struct *child, unsigned int data) diff --git a/kernel/sched.c b/kernel/sched.c index 3b1d88b61521..c8a11b29794e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/completion.h> #include <linux/kernel_stat.h> +#include <linux/security.h> /* * Convert user-nice values [ -20 ... 0 ... 19 ] @@ -1123,6 +1124,7 @@ out_unlock: asmlinkage long sys_nice(int increment) { + int retval; long nice; /* @@ -1144,6 +1146,11 @@ asmlinkage long sys_nice(int increment) nice = -20; if (nice > 19) nice = 19; + + retval = security_ops->task_setnice(current, nice); + if (retval) + return retval; + set_user_nice(current, nice); return 0; } @@ -1236,6 +1243,10 @@ static int setscheduler(pid_t pid, int policy, struct sched_param *param) !capable(CAP_SYS_NICE)) goto out_unlock; + retval = security_ops->task_setscheduler(p, policy, &lp); + if (retval) + goto out_unlock; + array = p->array; if (array) deactivate_task(p, task_rq(p)); @@ -1280,8 +1291,11 @@ asmlinkage long sys_sched_getscheduler(pid_t pid) retval = -ESRCH; read_lock(&tasklist_lock); p = find_process_by_pid(pid); - if (p) - retval = p->policy; + if (p) { + retval = security_ops->task_getscheduler(p); + if (!retval) + retval = p->policy; + } read_unlock(&tasklist_lock); out_nounlock: @@ -1302,6 +1316,11 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param) retval = -ESRCH; if (!p) goto out_unlock; + + retval = security_ops->task_getscheduler(p); + if (retval) + goto out_unlock; + lp.sched_priority = p->rt_priority; read_unlock(&tasklist_lock); @@ -1509,14 +1528,22 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) retval = -ESRCH; read_lock(&tasklist_lock); p = find_process_by_pid(pid); - if (p) - jiffies_to_timespec(p->policy & SCHED_FIFO ? - 0 : TASK_TIMESLICE(p), &t); + if (!p) + goto out_unlock; + + retval = security_ops->task_getscheduler(p); + if (retval) + goto out_unlock; + + jiffies_to_timespec(p->policy & SCHED_FIFO ? + 0 : TASK_TIMESLICE(p), &t); read_unlock(&tasklist_lock); - if (p) - retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; + retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; out_nounlock: return retval; +out_unlock: + read_unlock(&tasklist_lock); + return retval; } static void show_task(task_t * p) diff --git a/kernel/signal.c b/kernel/signal.c index c08c89e9a62c..90ae5af97bf7 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -548,6 +548,9 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); ret = -EPERM; if (bad_signal(sig, info, t)) goto out_nolock; + ret = security_ops->task_kill(t, info, sig); + if (ret) + goto out_nolock; /* The null signal is a permissions and process existence probe. No signal is actually delivered. Same goes for zombies. */ diff --git a/kernel/sys.c b/kernel/sys.c index 2559bef8ed09..37a9525b3f1d 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -19,6 +19,7 @@ #include <linux/tqueue.h> #include <linux/device.h> #include <linux/times.h> +#include <linux/security.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -234,6 +235,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) read_lock(&tasklist_lock); for_each_task(p) { + int no_nice; if (!proc_sel(p, which, who)) continue; if (p->uid != current->euid && @@ -243,10 +245,17 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) } if (error == -ESRCH) error = 0; - if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) + if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) { error = -EACCES; - else - set_user_nice(p, niceval); + continue; + } + no_nice = security_ops->task_setnice(p, niceval); + if (no_nice) { + error = no_nice; + continue; + } + set_user_nice(p, niceval); + } read_unlock(&tasklist_lock); @@ -416,6 +425,11 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) int old_egid = current->egid; int new_rgid = old_rgid; int new_egid = old_egid; + int retval; + + retval = security_ops->task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); + if (retval) + return retval; if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || @@ -457,6 +471,11 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) asmlinkage long sys_setgid(gid_t gid) { int old_egid = current->egid; + int retval; + + retval = security_ops->task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); + if (retval) + return retval; if (capable(CAP_SETGID)) { @@ -481,52 +500,6 @@ asmlinkage long sys_setgid(gid_t gid) return 0; } -/* - * cap_emulate_setxuid() fixes the effective / permitted capabilities of - * a process after a call to setuid, setreuid, or setresuid. - * - * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of - * {r,e,s}uid != 0, the permitted and effective capabilities are - * cleared. - * - * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective - * capabilities of the process are cleared. - * - * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective - * capabilities are set to the permitted capabilities. - * - * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should - * never happen. - * - * -astor - * - * cevans - New behaviour, Oct '99 - * A process may, via prctl(), elect to keep its capabilities when it - * calls setuid() and switches away from uid==0. Both permitted and - * effective sets will be retained. - * Without this change, it was impossible for a daemon to drop only some - * of its privilege. The call to setuid(!=0) would drop all privileges! - * Keeping uid 0 is not an option because uid 0 owns too many vital - * files.. - * Thanks to Olaf Kirch and Peter Benie for spotting this. - */ -static inline void cap_emulate_setxuid(int old_ruid, int old_euid, - int old_suid) -{ - if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && - (current->uid != 0 && current->euid != 0 && current->suid != 0) && - !current->keep_capabilities) { - cap_clear(current->cap_permitted); - cap_clear(current->cap_effective); - } - if (old_euid == 0 && current->euid != 0) { - cap_clear(current->cap_effective); - } - if (old_euid != 0 && current->euid == 0) { - current->cap_effective = current->cap_permitted; - } -} - static int set_user(uid_t new_ruid, int dumpclear) { struct user_struct *new_user, *old_user; @@ -572,6 +545,11 @@ static int set_user(uid_t new_ruid, int dumpclear) asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) { int old_ruid, old_euid, old_suid, new_ruid, new_euid; + int retval; + + retval = security_ops->task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); + if (retval) + return retval; new_ruid = old_ruid = current->uid; new_euid = old_euid = current->euid; @@ -608,11 +586,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) current->suid = current->euid; current->fsuid = current->euid; - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - cap_emulate_setxuid(old_ruid, old_euid, old_suid); - } - - return 0; + return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); } @@ -632,6 +606,11 @@ asmlinkage long sys_setuid(uid_t uid) { int old_euid = current->euid; int old_ruid, old_suid, new_ruid, new_suid; + int retval; + + retval = security_ops->task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); + if (retval) + return retval; old_ruid = new_ruid = current->uid; old_suid = current->suid; @@ -652,11 +631,7 @@ asmlinkage long sys_setuid(uid_t uid) current->fsuid = current->euid = uid; current->suid = new_suid; - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - cap_emulate_setxuid(old_ruid, old_euid, old_suid); - } - - return 0; + return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); } @@ -669,6 +644,11 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) int old_ruid = current->uid; int old_euid = current->euid; int old_suid = current->suid; + int retval; + + retval = security_ops->task_setuid(ruid, euid, suid, LSM_SETID_RES); + if (retval) + return retval; if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && @@ -697,11 +677,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) if (suid != (uid_t) -1) current->suid = suid; - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - cap_emulate_setxuid(old_ruid, old_euid, old_suid); - } - - return 0; + return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); } asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) @@ -720,6 +696,12 @@ asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) */ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + int retval; + + retval = security_ops->task_setgid(rgid, egid, sgid, LSM_SETID_RES); + if (retval) + return retval; + if (!capable(CAP_SETGID)) { if ((rgid != (gid_t) -1) && (rgid != current->gid) && (rgid != current->egid) && (rgid != current->sgid)) @@ -768,6 +750,11 @@ asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) asmlinkage long sys_setfsuid(uid_t uid) { int old_fsuid; + int retval; + + retval = security_ops->task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); + if (retval) + return retval; old_fsuid = current->fsuid; if (uid == current->uid || uid == current->euid || @@ -782,24 +769,9 @@ asmlinkage long sys_setfsuid(uid_t uid) current->fsuid = uid; } - /* We emulate fsuid by essentially doing a scaled-down version - * of what we did in setresuid and friends. However, we only - * operate on the fs-specific bits of the process' effective - * capabilities - * - * FIXME - is fsuser used for all CAP_FS_MASK capabilities? - * if not, we might be a bit too harsh here. - */ - - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - if (old_fsuid == 0 && current->fsuid != 0) { - cap_t(current->cap_effective) &= ~CAP_FS_MASK; - } - if (old_fsuid != 0 && current->fsuid == 0) { - cap_t(current->cap_effective) |= - (cap_t(current->cap_permitted) & CAP_FS_MASK); - } - } + retval = security_ops->task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); + if (retval) + return retval; return old_fsuid; } @@ -810,6 +782,11 @@ asmlinkage long sys_setfsuid(uid_t uid) asmlinkage long sys_setfsgid(gid_t gid) { int old_fsgid; + int retval; + + retval = security_ops->task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS); + if (retval) + return retval; old_fsgid = current->fsgid; if (gid == current->gid || gid == current->egid || @@ -904,6 +881,10 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) } ok_pgid: + err = security_ops->task_setpgid(p, pgid); + if (err) + goto out; + p->pgrp = pgid; err = 0; out: @@ -924,8 +905,11 @@ asmlinkage long sys_getpgid(pid_t pid) p = find_task_by_pid(pid); retval = -ESRCH; - if (p) - retval = p->pgrp; + if (p) { + retval = security_ops->task_getpgid(p); + if (!retval) + retval = p->pgrp; + } read_unlock(&tasklist_lock); return retval; } @@ -949,8 +933,11 @@ asmlinkage long sys_getsid(pid_t pid) p = find_task_by_pid(pid); retval = -ESRCH; - if(p) - retval = p->session; + if(p) { + retval = security_ops->task_getsid(p); + if (!retval) + retval = p->session; + } read_unlock(&tasklist_lock); return retval; } @@ -1008,12 +995,19 @@ asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist) asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist) { + gid_t groups[NGROUPS]; + int retval; + if (!capable(CAP_SETGID)) return -EPERM; if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; - if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t))) + if(copy_from_user(groups, grouplist, gidsetsize * sizeof(gid_t))) return -EFAULT; + retval = security_ops->task_setgroups(gidsetsize, groups); + if (retval) + return retval; + memcpy(current->groups, groups, gidsetsize * sizeof(gid_t)); current->ngroups = gidsetsize; return 0; } @@ -1158,6 +1152,7 @@ asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim) asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim) { struct rlimit new_rlim, *old_rlim; + int retval; if (resource >= RLIM_NLIMITS) return -EINVAL; @@ -1172,6 +1167,11 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim) if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN) return -EPERM; } + + retval = security_ops->task_setrlimit(resource, &new_rlim); + if (retval) + return retval; + *old_rlim = new_rlim; return 0; } @@ -1243,6 +1243,10 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, int error = 0; int sig; + error = security_ops->task_prctl(option, arg2, arg3, arg4, arg5); + if (error) + return error; + switch (option) { case PR_SET_PDEATHSIG: sig = arg2; diff --git a/kernel/uid16.c b/kernel/uid16.c index f76e4fd706e5..63b24096f8c3 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c @@ -12,6 +12,7 @@ #include <linux/prctl.h> #include <linux/init.h> #include <linux/highuid.h> +#include <linux/security.h> #include <asm/uaccess.h> @@ -128,6 +129,7 @@ asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t *grouplist) asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t *grouplist) { old_gid_t groups[NGROUPS]; + gid_t new_groups[NGROUPS]; int i; if (!capable(CAP_SETGID)) @@ -137,7 +139,11 @@ asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t *grouplist) if (copy_from_user(groups, grouplist, gidsetsize * sizeof(old_gid_t))) return -EFAULT; for (i = 0 ; i < gidsetsize ; i++) - current->groups[i] = (gid_t)groups[i]; + new_groups[i] = (gid_t)groups[i]; + i = security_ops->task_setgroups(gidsetsize, new_groups); + if (i) + return i; + memcpy(current->groups, new_groups, gidsetsize * sizeof(gid_t)); current->ngroups = gidsetsize; return 0; } |
