[PATCH 4/4] MultiAdmin module

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[PATCH 4/4] MultiAdmin module

    -   Add the MultiAdmin to the mainline tree.
        I hope the rest is self-explanatory.

Please do not mention CodingStyle for multiadm.c. I already know it. :)
And I will get to it should it really be merged.


Signed-off-by: Jan Engelhardt <[email protected]>

diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/security/Kconfig linux-2.6.17-rc3+/security/Kconfig
--- linux-2.6.17-rc3~/security/Kconfig	2006-05-01 12:47:01.382832000 +0200
+++ linux-2.6.17-rc3+/security/Kconfig	2006-05-01 15:04:08.482832000 +0200
@@ -99,6 +99,22 @@ config SECURITY_SECLVL
 
 	  If you are unsure how to answer this question, answer N.
 
+config SECURITY_MULTIADM
+    tristate "MultiAdmin secuirty module"
+    depends on SECURITY
+    ---help---
+        The MultiAdmin security kernel module provides means to have multiple
+        "root" users with unique UIDs. This fixes collation order problems
+        which for example appear with NSCD, allows to have files with
+        determinable owner and allows to track the quota usage for every
+        user, since they now have a unique uid.
+        
+        It also implements a "sub-admin", a partially restricted root user
+        (or enhanced normal user, depending on the way you see it), who has
+        full read-only access to most subsystems, and additional write rights
+        only to a limited subset, e.g. writing to files or killing processes
+        only of certain users.
+
 source security/selinux/Kconfig
 
 endmenu
diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/security/Makefile linux-2.6.17-rc3+/security/Makefile
--- linux-2.6.17-rc3~/security/Makefile	2006-05-01 12:47:01.382832000 +0200
+++ linux-2.6.17-rc3+/security/Makefile	2006-05-01 15:04:08.482832000 +0200
@@ -17,3 +17,4 @@ obj-$(CONFIG_SECURITY_SELINUX)		+= selin
 obj-$(CONFIG_SECURITY_CAPABILITIES)	+= commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)		+= commoncap.o root_plug.o
 obj-$(CONFIG_SECURITY_SECLVL)		+= seclvl.o
+obj-$(CONFIG_SECURITY_MULTIADM)		+= commoncap.o multiadm.o
diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/security/loadme linux-2.6.17-rc3+/security/loadme
--- linux-2.6.17-rc3~/security/loadme	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc3+/security/loadme	2006-05-01 15:16:27.662832000 +0200
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+rmmod multiadm;
+modprobe commoncap;
+insmod ./multiadm.ko Supergid=0 Subuid_start=4000 \
+	Subuid_end=4000 Wrtuid_start=4003 Wrtuid_end=4004;
diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/security/multiadm.c linux-2.6.17-rc3+/security/multiadm.c
--- linux-2.6.17-rc3~/security/multiadm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.17-rc3+/security/multiadm.c	2006-05-01 15:39:13.042832000 +0200
@@ -0,0 +1,618 @@
+/*=============================================================================
+| MultiAdmin Security Module                                                  |
+| Copyright © Jan Engelhardt <jengelh [at] gmx de>, 2005 - 2006               |
+| v1.0.5, May 2006                                                            |
+| http://alphagate.hopto.org/                                                 |
+`-----------------------------------------------------------------------------'
+
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License
+    version 2 as published by the Free Software Foundation.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program kit; if not, write to:
+    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+    Boston, MA  02110-1301  USA
+=============================================================================*/
+#include <asm/siginfo.h>
+#include <linux/binfmts.h>
+#include <linux/capability.h>
+#include <linux/config.h>
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ipc.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/namei.h>
+#include <linux/sched.h>
+#include <linux/securebits.h>
+#include <linux/security.h>
+#include <linux/sem.h>
+#include <linux/types.h>
+
+#if !defined(CONFIG_SECURITY_CAPABILITIES) && \
+    !defined(CONFIG_SECURITY_CAPABILITIES_MODULE)
+#        error You need to have CONFIG_SECURITY_CAPABILITIES=y or =m \
+               for MultiAdmin to compile successfully.
+#endif
+
+#define BASENAME "multiadm"
+#define PREFIX BASENAME ": "
+
+/*
+This typedef is used to mark functions a littile without interfering
+with the ABI:
+    bool for  0=failure, !0=success
+    int  for  0=success, <0=failure, >0=failure or some val
+    int  for  0=eof,     <0=failure, >0=value
+*/
+typedef int bool;
+
+static int mt_bprm_set_security(struct linux_binprm *);
+static int mt_cap_extra(int);
+static int mt_inode_permission(struct inode *, int, struct nameidata *);
+static int mt_inode_setattr(struct dentry *, struct iattr *);
+static int mt_ipc_permission(struct kern_ipc_perm *, short);
+static int mt_msq_msgctl(struct msg_queue *, int);
+static int mt_ptrace(task_t *, task_t *);
+static int mt_quotactl(int, int, int, struct super_block *);
+static int mt_sem_semctl(struct sem_array *, int);
+static int mt_shm_shmctl(struct shmid_kernel *, int);
+static int mt_task_kill(task_t *, struct siginfo *, int);
+static int mt_task_post_setuid(uid_t, uid_t, uid_t, int);
+static int mt_task_post_setgid(gid_t, gid_t, gid_t, int);
+static int mt_task_setnice(task_t *, int);
+static int mt_task_setscheduler(task_t *, int, struct sched_param *);
+static int mt_task_setuid(uid_t, uid_t, uid_t, int);
+
+static inline void chg2_superadm(kernel_cap_t *);
+static inline void chg2_subadm(kernel_cap_t *);
+static inline void chg2_netadm(kernel_cap_t *);
+static inline bool is_any_superadm(uid_t, gid_t);
+static inline bool is_uid_superadm(uid_t);
+static inline bool is_gid_superadm(gid_t);
+static inline bool is_any_subadm(uid_t, gid_t);
+static inline bool is_uid_subadm(uid_t);
+static inline bool is_gid_subadm(gid_t);
+static inline bool is_uid_netadm(uid_t);
+static inline bool is_uid_user(uid_t);
+static inline bool is_task1_user(const task_t *);
+static inline bool is_task_user(const task_t *);
+static inline bool range_intersect(uid_t, uid_t, uid_t, uid_t);
+static inline bool range_intersect_wrt(uid_t, uid_t, uid_t, uid_t);
+
+static struct security_operations mt_secops = {
+    .bprm_apply_creds      = cap_bprm_apply_creds,
+    .bprm_set_security     = mt_bprm_set_security,
+    .cap_extra             = mt_cap_extra,
+    .capable               = cap_capable,
+    .capget                = cap_capget,
+    .capset_check          = cap_capset_check,
+    .capset_set            = cap_capset_set,
+    .inode_permission      = mt_inode_permission,
+    .inode_setattr         = mt_inode_setattr,
+    .ipc_permission        = mt_ipc_permission,
+    .msg_queue_msgctl      = mt_msq_msgctl,
+    .ptrace                = mt_ptrace,
+    .quotactl              = mt_quotactl,
+    .sem_semctl            = mt_sem_semctl,
+    .shm_shmctl            = mt_shm_shmctl,
+    .task_kill             = mt_task_kill,
+    .task_post_setuid      = mt_task_post_setuid,
+    .task_post_setgid      = mt_task_post_setgid,
+    .task_setnice          = mt_task_setnice,
+    .task_setscheduler     = mt_task_setscheduler,
+    .task_setuid           = mt_task_setuid,
+};
+static gid_t Supergid = -1, Subgid = -1;
+static uid_t Superuid_start = 0,  Superuid_end = 0,
+             Subuid_start   = -1, Subuid_end   = -1,
+             Netuid         = -1,
+             Wrtuid_start   = -1, Wrtuid_end   = -1;
+static int Secondary = 0;
+
+MODULE_DESCRIPTION("MultiAdmin Security Module; http://alphagate.hopto.org/";);
+MODULE_AUTHOR("Jan Engelhardt <jengelh [at] gmx de>");
+MODULE_LICENSE("GPL");
+module_param(Supergid,       int, S_IRUSR | S_IWUSR);
+module_param(Superuid_start, int, S_IRUSR | S_IWUSR);
+module_param(Superuid_end,   int, S_IRUSR | S_IWUSR);
+module_param(Subuid_start,   int, S_IRUSR | S_IWUSR);
+module_param(Subuid_end,     int, S_IRUSR | S_IWUSR);
+module_param(Subgid,         int, S_IRUSR | S_IWUSR);
+module_param(Netuid,         int, S_IRUSR | S_IWUSR);
+module_param(Wrtuid_start,   int, S_IRUGO | S_IWUSR);
+module_param(Wrtuid_end,     int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(Wrtuid_start,   "First UID of the write-enabled user range");
+MODULE_PARM_DESC(Wrtuid_end,     "Last UID of the write-enabled user range");
+MODULE_PARM_DESC(Superuid_start, "First UIDs of the superadmin range");
+MODULE_PARM_DESC(Superuid_end,   "Last UID of the superadmin range");
+MODULE_PARM_DESC(Supergid,       "Superadmin GID");
+MODULE_PARM_DESC(Subuid_start,   "First UIDs of the subadmin range");
+MODULE_PARM_DESC(Subuid_end,     "Last UID of the subadmin range");
+MODULE_PARM_DESC(Subgid,         "Subadmin GID");
+MODULE_PARM_DESC(Netuid,         "Netadmin UID");
+
+//-----------------------------------------------------------------------------
+__init static int multiadm_init(void) {
+    int eax = 0, ebx = 0;
+    if((eax = register_security(&mt_secops)) != 0) {
+        if((ebx = mod_reg_security(BASENAME, &mt_secops)) != 0) {
+            printk(KERN_WARNING PREFIX
+            "Could not register with kernel: %d, %d\n", eax, ebx);
+            return ebx;
+        }
+        Secondary = 1;
+    }
+
+    if(range_intersect(Superuid_start, Superuid_end, Subuid_start, Subuid_end))
+        printk(KERN_WARNING PREFIX
+          "Superadmin and Subadmin ranges intersect! Unpredictable behavior"
+          " may result: some operations may classify you as a superadmin,"
+          " others as a subadmin. Security leak: subadmin could possibly"
+          " change into superadmin!\n"
+        );
+    if(range_intersect(Superuid_start, Superuid_end, Netuid, Netuid))
+        printk(KERN_WARNING PREFIX "Netuid within superadmin range! -Has more "
+               "powers than intended!\n");
+    if(range_intersect(Superuid_start, Superuid_end, Wrtuid_start, Wrtuid_end))
+        printk(KERN_WARNING PREFIX "Superadmin and write-enabled user range "
+               "intersect! A subadmin could setuid() into a superadmin!\n");
+    if(range_intersect(Subuid_start, Subuid_end, Netuid, Netuid))
+        printk(KERN_WARNING PREFIX "Netuid within subadmin range! -Has more "
+               "powers than intended!\n");
+    if(range_intersect_wrt(Subuid_start, Subuid_end, Wrtuid_start, Wrtuid_end))
+        printk(KERN_WARNING PREFIX "Subadmin and write-enabled user range "
+               "intersect! Subadmins are able to poke on other subadmins!\n");
+    if(range_intersect_wrt(Netuid, Netuid, Wrtuid_start, Wrtuid_end))
+        printk(KERN_WARNING PREFIX "Netuid within write-enabled user range! "
+               "Subadmin may gain CAP_NET_ADMIN!\n");
+    printk(KERN_INFO "MultiAdmin loaded\n");
+    return 0;
+}
+
+__exit static void multiadm_exit(void) {
+    int ret = 0;
+
+    if(Secondary)
+        ret = mod_unreg_security(BASENAME, &mt_secops);
+    else
+        ret = unregister_security(&mt_secops);
+
+    if(ret != 0)
+        printk(KERN_WARNING PREFIX
+               "Could not unregister with kernel: %d\n", ret);
+
+    return;
+}
+
+module_init(multiadm_init);
+module_exit(multiadm_exit);
+
+//-----------------------------------------------------------------------------
+static int mt_bprm_set_security(struct linux_binprm *bp) {
+    /* In the function chain of exec(), we eventually get here, which is the
+    place to set up new privileges. */
+    cap_bprm_set_security(bp);
+
+    /* All of the following is nicely inlined. The capability raising is
+    resolved to only one instruction for each set. */
+    if(is_any_superadm(bp->e_uid, bp->e_gid)) {
+        chg2_superadm(&bp->cap_permitted);
+        chg2_superadm(&bp->cap_effective);
+    } else if(is_any_superadm(current->uid, current->gid)) {
+        chg2_superadm(&bp->cap_permitted);
+    } else if(is_any_subadm(bp->e_uid, bp->e_gid)) {
+        chg2_subadm(&bp->cap_permitted);
+        chg2_subadm(&bp->cap_effective);
+    } else if(is_any_subadm(current->uid, current->gid)) {
+        chg2_subadm(&bp->cap_permitted);
+    } else if(is_uid_netadm(bp->e_uid)) {
+        chg2_netadm(&bp->cap_permitted);
+        chg2_netadm(&bp->cap_effective);
+    } else if(is_uid_netadm(current->uid)) {
+        chg2_netadm(&bp->cap_permitted);
+    }
+    return 0;
+}
+
+static int mt_cap_extra(int capability) {
+    if(capability == CAP_SYS_ADMIN)
+        /* Subadmin also has CAP_SYS_ADMIN, but if we get here, we did so
+        by capable() -- not capable_light(). */
+        return is_any_superadm(current->euid, current->egid);
+    else
+        /* Subadmin/Netadmin also has other capabilities, but they
+        are -- I hope -- ok. */
+        return 1;
+}
+
+static int mt_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+    /* Check for superadmin is not done, since the only users that can get
+    here is either superadmin or subadmin. By omitting the check for
+    superadmin, only two comparisons need to be done for the subadmin case.
+    This method is done almost throughout the entire module. */
+
+    if(is_any_subadm(current->euid, current->egid) && (mask & MAY_WRITE)) {
+        int ret;
+        if(inode->i_uid == current->fsuid || is_uid_user(inode->i_uid))
+            return 0;
+
+        /* Since we practically jumped over the checks to get here (because of
+        CAP_DAC_OVERRIDE), we need to do it again. Without CAP_DAC_OVERRIDE
+        this time. Temporarily drop it. */
+        cap_lower(current->cap_effective, CAP_DAC_OVERRIDE);
+
+        // Copied from fs/namei.c
+        if(inode->i_op != NULL && inode->i_op->permission != NULL)
+            ret = inode->i_op->permission(inode, mask & ~MAY_APPEND, nd);
+        else
+            ret = generic_permission(inode, mask & ~MAY_APPEND, NULL);
+
+        cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
+        return ret;
+    }
+    return 0;
+}
+
+static int mt_inode_setattr(struct dentry *dentry, struct iattr *attr) {
+    if(is_any_subadm(current->euid, current->egid)) {
+        /* Change is only allowed if either the inode belongs to us, or does
+        belond, _and_ will belong in case of ATTR_UID, to a WRT user. */
+        const struct inode *inode = dentry->d_inode;
+        if(inode->i_uid != current->fsuid && !is_uid_user(inode->i_uid))
+            return -EPERM;
+
+        if((attr->ia_valid & ATTR_UID) && attr->ia_uid != current->fsuid &&
+         !is_uid_user(attr->ia_uid))
+                return -EPERM;
+    }
+    return 0;
+}
+
+static int mt_ipc_permission(struct kern_ipc_perm *perm, short flag) {
+    if(is_any_subadm(current->euid, current->egid)) {
+        int req, grant;
+
+        if(perm->uid == current->euid || perm->cuid == current->euid ||
+         is_uid_user(perm->uid) || is_uid_user(perm->cuid))
+                return 0;
+
+        /* Copied and modified from ipc/util.c. Subadmin always has read
+        permission so add S_IRUGO to granted. Checking the owner permission
+        part is not done anymore, because it is done above. */
+        req   = (flag >> 6) | (flag >> 3) | flag;
+        grant = (perm->mode | S_IRUGO) >> 3;
+        if(in_group_p(perm->gid) || in_group_p(perm->cgid))
+            grant >>= 3;
+        if(req & ~grant & 0007)
+            return -EPERM;
+    }
+    return 0;
+}
+
+static int mt_msq_msgctl(struct msg_queue *msq, int cmd) {
+    if(is_any_subadm(current->euid, current->egid)) {
+        if(cmd == MSG_INFO || cmd == MSG_STAT || cmd == IPC_INFO ||
+         cmd == IPC_STAT)
+                return 0;
+
+        // UID or CUID (creator UID) must fit
+        if(msq != NULL && msq->q_perm.uid != current->euid &&
+         msq->q_perm.cuid != current->euid && !is_uid_user(msq->q_perm.uid) &&
+         !is_uid_user(msq->q_perm.cuid))
+                return -EPERM;
+    }
+    return 0;
+}
+
+static int mt_ptrace(task_t *tracer, task_t *task) {
+    if(is_any_subadm(tracer->euid, tracer->egid)) {
+        /* Ownership check according to kernel/ptrace.c:
+        all of [RES][UG]ID must match the tracer's R[UG]ID. */
+        if(task->euid == tracer->uid && task->uid == tracer->uid &&
+         task->suid == tracer->uid && task->egid == tracer->gid &&
+         task->gid == tracer->gid && task->sgid == tracer->gid)
+                return 0;
+
+        // ...or all [RES]UIDs must match a WRT user
+        if(!is_task_user(task))
+            return -EPERM;
+    }
+    return 0;
+}
+
+static int mt_quotactl(int cmd, int type, int id, struct super_block *sb) {
+    if(is_any_subadm(current->euid, current->egid))
+        switch(cmd) {
+            case Q_SYNC:
+            case Q_GETFMT:
+            case Q_GETINFO:
+            case Q_GETQUOTA:
+            case Q_XGETQUOTA:
+            case Q_XGETQSTAT:
+            case Q_XQUOTASYNC:
+                return 0;
+            default:
+                return -EPERM;
+        }
+    return 0;
+}
+
+static int mt_sem_semctl(struct sem_array *sem, int cmd) {
+    if(is_any_subadm(current->euid, current->euid)) {
+        if(cmd == SEM_INFO || cmd == IPC_INFO || cmd == SEM_STAT)
+            return 0;
+        if(sem != NULL) {
+            const struct kern_ipc_perm *perm = &sem->sem_perm;
+            if(perm->uid != current->euid && perm->cuid != current->euid &&
+             !is_uid_user(perm->uid) && !is_uid_user(perm->cuid))
+                    return -EPERM;
+        }
+    }
+    return 0;
+}
+
+static int mt_shm_shmctl(struct shmid_kernel *shp, int cmd) {
+    if(is_any_subadm(current->euid, current->egid)) {
+        if(cmd == SHM_INFO || cmd == SHM_STAT ||
+         cmd == IPC_INFO || cmd == IPC_STAT)
+                return 0;
+        if(shp != NULL) {
+            const struct kern_ipc_perm *perm = &shp->shm_perm;
+            if(perm->uid != current->euid && perm->cuid != current->euid &&
+             !is_uid_user(perm->uid) && !is_uid_user(perm->cuid))
+                    return -EPERM;
+        }
+    }
+    return 0;
+}
+
+static int mt_task_kill(task_t *task, struct siginfo *si, int sig) {
+    if(is_any_subadm(current->euid, current->egid)) {
+        // As tricky as the ptrace() permission net.
+        if(is_uid_user(task->uid) || is_uid_user(task->suid))
+            return 0;
+
+        // Subadmin's own process
+        if(task->uid == current->euid || task->suid == current->euid ||
+         task->uid == current->uid || task->suid == current->uid)
+            return 0;
+
+        // SIG_IGN or a kernel-generated signal
+        if(si != NULL && ((long)si == 1 || (long)si == 2 || !SI_FROMUSER(si)))
+            return 0;
+
+        // For the case of a privileged subshell, but with the same tty
+        if(sig == SIGCONT && task->signal->session == current->signal->session)
+            return 0;
+
+        return -EPERM;
+    }
+    return 0;
+}
+
+static int mt_task_post_setuid(uid_t old_ruid, uid_t old_euid,
+ uid_t old_suid, int flags)
+{
+    int ret = cap_task_post_setuid(old_ruid, old_euid, old_suid, flags);
+    if(ret != 0)
+        return ret;
+
+    switch(flags) {
+        case LSM_SETID_ID:
+        case LSM_SETID_RE:
+        case LSM_SETID_RES:
+            // Unlike bprm_set_security(), effective must be set independently.
+            if(is_uid_superadm(current->uid))
+                chg2_superadm(&current->cap_permitted);
+            else if(is_uid_subadm(current->uid))
+                chg2_subadm(&current->cap_permitted);
+            else if(is_uid_netadm(current->uid))
+                chg2_netadm(&current->cap_permitted);
+
+            if(is_uid_superadm(current->euid))
+                chg2_superadm(&current->cap_effective);
+            else if(is_uid_subadm(current->euid))
+                chg2_subadm(&current->cap_effective);
+            else if(is_uid_netadm(current->euid))
+                chg2_netadm(&current->cap_effective);
+            break;
+    }
+    return 0;
+}
+
+static int mt_task_post_setgid(gid_t old_rgid, gid_t old_egid,
+ gid_t old_sgid, int flags)
+{
+    switch(flags) {
+        case LSM_SETID_ID:
+        case LSM_SETID_RE:
+        case LSM_SETID_RES:
+            if(is_gid_superadm(current->gid))
+                chg2_superadm(&current->cap_permitted);
+            else if(is_gid_subadm(current->gid))
+                chg2_subadm(&current->cap_permitted);
+
+            if(is_gid_superadm(current->egid))
+                chg2_superadm(&current->cap_effective);
+            else if(is_gid_subadm(current->egid))
+                chg2_subadm(&current->cap_effective);
+            break;
+    }
+    return 0;
+}
+
+static int mt_task_setuid(uid_t ruid, uid_t euid, uid_t suid, int flags) {
+    if(is_any_superadm(current->euid, current->egid))
+        return 0;
+
+    if(is_any_subadm(current->euid, current->egid))
+        if((ruid == -1 || is_uid_user(ruid)) && (euid == -1 ||
+         is_uid_user(euid)) && (suid == -1 || is_uid_user(suid)))
+                return 0;
+
+    switch(flags) {
+        case LSM_SETID_ID:
+            if(current->uid == ruid || current->suid == ruid)
+                return 0;
+            break;
+        case LSM_SETID_RE:
+            if(current->euid == ruid || current->euid == euid ||
+             current->uid == ruid || current->uid == euid ||
+             current->suid == euid)
+                    return 0;
+            break;
+        case LSM_SETID_RES:
+            if(current->euid == ruid || current->euid == euid ||
+             current->euid == suid || current->uid == ruid ||
+             current->uid == euid || current->uid == suid ||
+             current->suid == ruid || current->suid == euid ||
+             current->suid == suid)
+                    return 0;
+            break;
+        case LSM_SETID_FS:
+            if(current->euid == ruid)
+                return 0;
+            break;
+        default:
+            printk(KERN_WARNING PREFIX "Unsupported case %d in %s\n",
+                   flags, __FUNCTION__);
+            break;
+    }
+    return -EIO;
+}
+
+static int mt_task_setnice(task_t *task, int nice) {
+    if(is_any_subadm(current->euid, current->egid)) {
+        if(task->euid != current->euid && task->uid != current->euid &&
+         !is_task1_user(task))
+                return -EPERM;
+        if(nice < 0)
+                return -EACCES;
+    }
+    return 0;
+}
+
+static int mt_task_setscheduler(task_t *task, int policy,
+ struct sched_param *param)
+{
+    /* Return 0 for superuser and normal users. The latters' checks are
+    performed in sched.c. */
+    if(is_any_subadm(current->euid, current->egid)) {
+        // Copied from kernel/sched.c:sched_setscheduler()
+        if(task->policy != policy)
+            return -EPERM;
+
+        if(policy != SCHED_NORMAL && param->sched_priority > task->rt_priority &&
+         param->sched_priority > task->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
+                return -EPERM;
+
+        if(task->uid != current->euid && task->suid != current->euid &&
+         !is_task1_user(task))
+                return -EPERM;
+    }
+    return 0;
+}
+
+//-----------------------------------------------------------------------------
+static inline void chg2_superadm(kernel_cap_t *c) {
+    cap_set_full(*c);
+    cap_lower(*c, CAP_SETPCAP);
+    cap_lower(*c, 31); // currently unused
+    return;
+}
+
+static inline void chg2_subadm(kernel_cap_t *c) {
+    cap_clear(*c);
+    cap_raise(*c, CAP_CHOWN);
+    cap_raise(*c, CAP_DAC_OVERRIDE);
+    cap_raise(*c, CAP_DAC_READ_SEARCH);
+    cap_raise(*c, CAP_FOWNER);
+    cap_raise(*c, CAP_KILL);
+    cap_raise(*c, CAP_SETUID);
+    cap_raise(*c, CAP_IPC_OWNER);
+    cap_raise(*c, CAP_SYS_PTRACE);
+    cap_raise(*c, CAP_SYS_ADMIN);
+    cap_raise(*c, CAP_SYS_NICE);
+    return;
+}
+
+static inline void chg2_netadm(kernel_cap_t *c) {
+    cap_clear(*c);
+    cap_raise(*c, CAP_NET_ADMIN);
+    return;
+}
+
+static inline bool is_any_superadm(uid_t u, gid_t g) {
+    return is_uid_superadm(u) || is_gid_superadm(g);
+}
+
+static inline bool is_uid_superadm(uid_t u) {
+    return
+      (!issecure(SECURE_NOROOT) && u == 0) ||
+      (Superuid_start != -1 && Superuid_end != -1 &&
+      u >= Superuid_start && u <= Superuid_end);
+}
+
+static inline bool is_gid_superadm(gid_t g) {
+    return Supergid != -1 && g == Supergid;
+}
+
+static inline bool is_any_subadm(uid_t u, gid_t g) {
+    return is_uid_subadm(u) || is_gid_subadm(g);
+}
+
+static inline bool is_uid_subadm(uid_t u) {
+    return Subuid_start != -1 && Subuid_end != -1 &&
+           u >= Subuid_start && u <= Subuid_end;
+}
+
+static inline bool is_gid_subadm(gid_t g) {
+    return Subgid != -1 && g == Subgid;
+}
+
+static inline bool is_uid_netadm(uid_t u) {
+    return Netuid != -1 && u == Netuid;
+}
+
+static inline bool is_uid_user(uid_t u) {
+    /* Special case Wrtuid_end == (unsigned) -1 means what it means: everything
+    until the end. This is why there is no Wrtuid_end != -1 check. */
+    return Wrtuid_start != -1 && u >= Wrtuid_start && u <= Wrtuid_end;
+}
+
+static inline bool is_task1_user(const task_t *task) {
+    return is_uid_user(task->uid) || is_uid_user(task->suid);
+}
+
+static inline bool is_task_user(const task_t *task) {
+    return is_uid_user(task->euid) && is_uid_user(task->uid) &&
+           is_uid_user(task->suid);
+}
+
+static inline bool range_intersect(uid_t as, uid_t ae, uid_t bs, uid_t be) {
+    if(as == -1 || ae == -1 || bs == -1 || be == -1)
+        return 0;
+    return (long)ae >= (long)bs && (long)as <= (long)be;
+}
+
+static inline bool range_intersect_wrt(uid_t as, uid_t ae,
+ uid_t bs, uid_t be)
+{
+    if(as == -1 || ae == -1 || bs == -1)
+        return 0;
+    return (long)ae >= (long)bs && (long)as <= (long)be;
+}
+
+//=============================================================================
#<<eof>>


Jan Engelhardt
-- 

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux