[BACK]Return to secmodel_extensions.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / secmodel / extensions

Annotation of src/sys/secmodel/extensions/secmodel_extensions.c, Revision 1.1

1.1     ! jym         1: /* $NetBSD$ */
        !             2: /*-
        !             3:  * Copyright (c) 2011 Elad Efrat <elad@NetBSD.org>
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. The name of the author may not be used to endorse or promote products
        !            15:  *    derived from this software without specific prior written permission.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            19:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            20:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            21:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            22:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            23:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            24:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            25:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            26:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            27:  */
        !            28:
        !            29: #include <sys/cdefs.h>
        !            30: __KERNEL_RCSID(0, "$NetBSD$");
        !            31:
        !            32: #include <sys/types.h>
        !            33: #include <sys/param.h>
        !            34: #include <sys/kauth.h>
        !            35:
        !            36: #include <sys/mount.h>
        !            37: #include <sys/vnode.h>
        !            38: #include <sys/socketvar.h>
        !            39: #include <sys/sysctl.h>
        !            40: #include <sys/proc.h>
        !            41: #include <sys/module.h>
        !            42:
        !            43: #include <secmodel/secmodel.h>
        !            44: #include <secmodel/extensions/extensions.h>
        !            45:
        !            46: MODULE(MODULE_CLASS_SECMODEL, extensions, NULL);
        !            47:
        !            48: /* static */ int dovfsusermount;
        !            49: static int curtain;
        !            50: static int user_set_cpu_affinity;
        !            51:
        !            52: static kauth_listener_t l_system, l_process, l_network;
        !            53:
        !            54: static secmodel_t extensions_sm;
        !            55: static struct sysctllog *extensions_sysctl_log;
        !            56:
        !            57: static void secmodel_extensions_init(void);
        !            58: static void secmodel_extensions_start(void);
        !            59: static void secmodel_extensions_stop(void);
        !            60:
        !            61: static void sysctl_security_extensions_setup(struct sysctllog **);
        !            62: static int  sysctl_extensions_user_handler(SYSCTLFN_PROTO);
        !            63: static int  sysctl_extensions_curtain_handler(SYSCTLFN_PROTO);
        !            64: static bool is_securelevel_above(int);
        !            65:
        !            66: static int secmodel_extensions_system_cb(kauth_cred_t, kauth_action_t,
        !            67:     void *, void *, void *, void *, void *);
        !            68: static int secmodel_extensions_process_cb(kauth_cred_t, kauth_action_t,
        !            69:     void *, void *, void *, void *, void *);
        !            70: static int secmodel_extensions_network_cb(kauth_cred_t, kauth_action_t,
        !            71:     void *, void *, void *, void *, void *);
        !            72:
        !            73: static void
        !            74: sysctl_security_extensions_setup(struct sysctllog **clog)
        !            75: {
        !            76:        const struct sysctlnode *rnode;
        !            77:
        !            78:        sysctl_createv(clog, 0, NULL, &rnode,
        !            79:                       CTLFLAG_PERMANENT,
        !            80:                       CTLTYPE_NODE, "security", NULL,
        !            81:                       NULL, 0, NULL, 0,
        !            82:                       CTL_SECURITY, CTL_EOL);
        !            83:
        !            84:        sysctl_createv(clog, 0, &rnode, &rnode,
        !            85:                       CTLFLAG_PERMANENT,
        !            86:                       CTLTYPE_NODE, "models", NULL,
        !            87:                       NULL, 0, NULL, 0,
        !            88:                       CTL_CREATE, CTL_EOL);
        !            89:
        !            90:        sysctl_createv(clog, 0, &rnode, &rnode,
        !            91:                       CTLFLAG_PERMANENT,
        !            92:                       CTLTYPE_NODE, "extensions", NULL,
        !            93:                       NULL, 0, NULL, 0,
        !            94:                       CTL_CREATE, CTL_EOL);
        !            95:
        !            96:        sysctl_createv(clog, 0, &rnode, NULL,
        !            97:                       CTLFLAG_PERMANENT,
        !            98:                       CTLTYPE_STRING, "name", NULL,
        !            99:                       NULL, 0, __UNCONST(SECMODEL_EXTENSIONS_NAME), 0,
        !           100:                       CTL_CREATE, CTL_EOL);
        !           101:
        !           102:        sysctl_createv(clog, 0, &rnode, NULL,
        !           103:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
        !           104:                       CTLTYPE_INT, "usermount",
        !           105:                       SYSCTL_DESCR("Whether unprivileged users may mount "
        !           106:                                    "filesystems"),
        !           107:                       sysctl_extensions_user_handler, 0, &dovfsusermount, 0,
        !           108:                       CTL_CREATE, CTL_EOL);
        !           109:
        !           110:        sysctl_createv(clog, 0, &rnode, NULL,
        !           111:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
        !           112:                       CTLTYPE_INT, "curtain",
        !           113:                       SYSCTL_DESCR("Curtain information about objects to "\
        !           114:                                    "users not owning them."),
        !           115:                       sysctl_extensions_curtain_handler, 0, &curtain, 0,
        !           116:                       CTL_CREATE, CTL_EOL);
        !           117:
        !           118:        sysctl_createv(clog, 0, &rnode, NULL,
        !           119:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
        !           120:                       CTLTYPE_INT, "user_set_cpu_affinity",
        !           121:                       SYSCTL_DESCR("Whether unprivileged users may control "\
        !           122:                                    "CPU affinity."),
        !           123:                       sysctl_extensions_user_handler, 0,
        !           124:                       &user_set_cpu_affinity, 0,
        !           125:                       CTL_CREATE, CTL_EOL);
        !           126:
        !           127:        /* Compatibility: vfs.generic.usermount */
        !           128:        sysctl_createv(clog, 0, NULL, NULL,
        !           129:                       CTLFLAG_PERMANENT,
        !           130:                       CTLTYPE_NODE, "vfs", NULL,
        !           131:                       NULL, 0, NULL, 0,
        !           132:                       CTL_VFS, CTL_EOL);
        !           133:
        !           134:        sysctl_createv(clog, 0, NULL, NULL,
        !           135:                       CTLFLAG_PERMANENT,
        !           136:                       CTLTYPE_NODE, "generic",
        !           137:                       SYSCTL_DESCR("Non-specific vfs related information"),
        !           138:                       NULL, 0, NULL, 0,
        !           139:                       CTL_VFS, VFS_GENERIC, CTL_EOL);
        !           140:
        !           141:        sysctl_createv(clog, 0, NULL, NULL,
        !           142:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
        !           143:                       CTLTYPE_INT, "usermount",
        !           144:                       SYSCTL_DESCR("Whether unprivileged users may mount "
        !           145:                                    "filesystems"),
        !           146:                       sysctl_extensions_user_handler, 0, &dovfsusermount, 0,
        !           147:                       CTL_VFS, VFS_GENERIC, VFS_USERMOUNT, CTL_EOL);
        !           148:
        !           149:        /* Compatibility: security.curtain */
        !           150:        sysctl_createv(clog, 0, NULL, &rnode,
        !           151:                       CTLFLAG_PERMANENT,
        !           152:                       CTLTYPE_NODE, "security", NULL,
        !           153:                       NULL, 0, NULL, 0,
        !           154:                       CTL_SECURITY, CTL_EOL);
        !           155:
        !           156:        sysctl_createv(clog, 0, &rnode, NULL,
        !           157:                       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
        !           158:                       CTLTYPE_INT, "curtain",
        !           159:                       SYSCTL_DESCR("Curtain information about objects to "\
        !           160:                                    "users not owning them."),
        !           161:                       sysctl_extensions_curtain_handler, 0, &curtain, 0,
        !           162:                       CTL_CREATE, CTL_EOL);
        !           163: }
        !           164:
        !           165: static int
        !           166: sysctl_extensions_curtain_handler(SYSCTLFN_ARGS)
        !           167: {
        !           168:        struct sysctlnode node;
        !           169:        int val, error;
        !           170:
        !           171:        val = *(int *)rnode->sysctl_data;
        !           172:
        !           173:        node = *rnode;
        !           174:        node.sysctl_data = &val;
        !           175:
        !           176:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
        !           177:        if (error || newp == NULL)
        !           178:                return error;
        !           179:
        !           180:        /* shortcut */
        !           181:        if (val == *(int *)rnode->sysctl_data)
        !           182:                return 0;
        !           183:
        !           184:        /* curtain cannot be disabled when securelevel is above 0 */
        !           185:        if (val == 0 && is_securelevel_above(0)) {
        !           186:                return EPERM;
        !           187:        }
        !           188:
        !           189:        *(int *)rnode->sysctl_data = val;
        !           190:        return 0;
        !           191: }
        !           192:
        !           193: /*
        !           194:  * Generic sysctl extensions handler for user mount and set CPU affinity
        !           195:  * rights. Checks the following conditions:
        !           196:  * - setting value to 0 is always permitted (decrease user rights)
        !           197:  * - setting value != 0 is not permitted when securelevel is above 0 (increase
        !           198:  *   user rights).
        !           199:  */
        !           200: static int
        !           201: sysctl_extensions_user_handler(SYSCTLFN_ARGS)
        !           202: {
        !           203:        struct sysctlnode node;
        !           204:        int val, error;
        !           205:
        !           206:        val = *(int *)rnode->sysctl_data;
        !           207:
        !           208:        node = *rnode;
        !           209:        node.sysctl_data = &val;
        !           210:
        !           211:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
        !           212:        if (error || newp == NULL)
        !           213:                return error;
        !           214:
        !           215:        /* shortcut */
        !           216:        if (val == *(int *)rnode->sysctl_data)
        !           217:                return 0;
        !           218:
        !           219:        /* we cannot grant more rights to users when securelevel is above 0 */
        !           220:        if (val != 0 && is_securelevel_above(0)) {
        !           221:                return EPERM;
        !           222:        }
        !           223:
        !           224:        *(int *)rnode->sysctl_data = val;
        !           225:        return 0;
        !           226: }
        !           227:
        !           228: /*
        !           229:  * Query secmodel_securelevel(9) to know whether securelevel is strictly
        !           230:  * above 'level' or not.
        !           231:  * Returns true if it is, false otherwise (when securelevel is absent or
        !           232:  * securelevel is at or below 'level').
        !           233:  */
        !           234: static bool
        !           235: is_securelevel_above(int level)
        !           236: {
        !           237:        bool above;
        !           238:        int error;
        !           239:
        !           240:        error = secmodel_eval("org.netbsd.secmodel.securelevel",
        !           241:            "is-securelevel-above", KAUTH_ARG(level), &above);
        !           242:        if (error == 0 && above)
        !           243:                return true;
        !           244:        else
        !           245:                return false;
        !           246: }
        !           247:
        !           248: static void
        !           249: secmodel_extensions_init(void)
        !           250: {
        !           251:
        !           252:        curtain = 0;
        !           253:        user_set_cpu_affinity = 0;
        !           254: }
        !           255:
        !           256: static void
        !           257: secmodel_extensions_start(void)
        !           258: {
        !           259:
        !           260:        l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
        !           261:            secmodel_extensions_system_cb, NULL);
        !           262:        l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
        !           263:            secmodel_extensions_process_cb, NULL);
        !           264:        l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
        !           265:            secmodel_extensions_network_cb, NULL);
        !           266: }
        !           267:
        !           268: static void
        !           269: secmodel_extensions_stop(void)
        !           270: {
        !           271:
        !           272:        kauth_unlisten_scope(l_system);
        !           273:        kauth_unlisten_scope(l_process);
        !           274:        kauth_unlisten_scope(l_network);
        !           275: }
        !           276:
        !           277: static int
        !           278: extensions_modcmd(modcmd_t cmd, void *arg)
        !           279: {
        !           280:        int error = 0;
        !           281:
        !           282:        switch (cmd) {
        !           283:        case MODULE_CMD_INIT:
        !           284:                error = secmodel_register(&extensions_sm,
        !           285:                    SECMODEL_EXTENSIONS_ID, SECMODEL_EXTENSIONS_NAME,
        !           286:                    NULL, NULL, NULL);
        !           287:                if (error != 0)
        !           288:                        printf("extensions_modcmd::init: secmodel_register "
        !           289:                            "returned %d\n", error);
        !           290:
        !           291:                secmodel_extensions_init();
        !           292:                secmodel_extensions_start();
        !           293:                sysctl_security_extensions_setup(&extensions_sysctl_log);
        !           294:                break;
        !           295:
        !           296:        case MODULE_CMD_FINI:
        !           297:                sysctl_teardown(&extensions_sysctl_log);
        !           298:                secmodel_extensions_stop();
        !           299:
        !           300:                error = secmodel_deregister(extensions_sm);
        !           301:                if (error != 0)
        !           302:                        printf("extensions_modcmd::fini: secmodel_deregister "
        !           303:                            "returned %d\n", error);
        !           304:
        !           305:                break;
        !           306:
        !           307:        case MODULE_CMD_AUTOUNLOAD:
        !           308:                error = EPERM;
        !           309:                break;
        !           310:
        !           311:        default:
        !           312:                error = ENOTTY;
        !           313:                break;
        !           314:        }
        !           315:
        !           316:        return (error);
        !           317: }
        !           318:
        !           319: static int
        !           320: secmodel_extensions_system_cb(kauth_cred_t cred, kauth_action_t action,
        !           321:     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
        !           322: {
        !           323:        struct mount *mp;
        !           324:        u_long flags;
        !           325:        int result;
        !           326:        enum kauth_system_req req;
        !           327:
        !           328:        req = (enum kauth_system_req)arg0;
        !           329:        result = KAUTH_RESULT_DEFER;
        !           330:
        !           331:        if (action != KAUTH_SYSTEM_MOUNT || dovfsusermount == 0)
        !           332:                return result;
        !           333:
        !           334:        switch (req) {
        !           335:        case KAUTH_REQ_SYSTEM_MOUNT_NEW:
        !           336:                mp = ((struct vnode *)arg1)->v_mount;
        !           337:                flags = (u_long)arg2;
        !           338:
        !           339:                if (usermount_common_policy(mp, flags) == 0)
        !           340:                        result = KAUTH_RESULT_ALLOW;
        !           341:
        !           342:                break;
        !           343:
        !           344:        case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT:
        !           345:                mp = arg1;
        !           346:
        !           347:                /* Must own the mount. */
        !           348:                if (mp->mnt_stat.f_owner == kauth_cred_geteuid(cred))
        !           349:                        result = KAUTH_RESULT_ALLOW;
        !           350:
        !           351:                break;
        !           352:
        !           353:        case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
        !           354:                mp = arg1;
        !           355:                flags = (u_long)arg2;
        !           356:
        !           357:                /* Must own the mount. */
        !           358:                if (mp->mnt_stat.f_owner == kauth_cred_geteuid(cred) &&
        !           359:                    usermount_common_policy(mp, flags) == 0)
        !           360:                        result = KAUTH_RESULT_ALLOW;
        !           361:
        !           362:                break;
        !           363:
        !           364:        default:
        !           365:                break;
        !           366:        }
        !           367:
        !           368:        return (result);
        !           369: }
        !           370:
        !           371: static int
        !           372: secmodel_extensions_process_cb(kauth_cred_t cred, kauth_action_t action,
        !           373:     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
        !           374: {
        !           375:        int result;
        !           376:        enum kauth_process_req req;
        !           377:
        !           378:        result = KAUTH_RESULT_DEFER;
        !           379:        req = (enum kauth_process_req)arg1;
        !           380:
        !           381:        switch (action) {
        !           382:        case KAUTH_PROCESS_CANSEE:
        !           383:                switch (req) {
        !           384:                case KAUTH_REQ_PROCESS_CANSEE_ARGS:
        !           385:                case KAUTH_REQ_PROCESS_CANSEE_ENTRY:
        !           386:                case KAUTH_REQ_PROCESS_CANSEE_OPENFILES:
        !           387:                        if (curtain != 0) {
        !           388:                                struct proc *p = arg0;
        !           389:
        !           390:                                /*
        !           391:                                 * Only process' owner and root can see
        !           392:                                 * through curtain
        !           393:                                 */
        !           394:                                if (!kauth_cred_uidmatch(cred, p->p_cred)) {
        !           395:                                        int error;
        !           396:                                        bool isroot = false;
        !           397:
        !           398:                                        error = secmodel_eval(
        !           399:                                            "org.netbsd.secmodel.suser",
        !           400:                                            "is-root", cred, &isroot);
        !           401:                                        if (error == 0 && !isroot)
        !           402:                                                result = KAUTH_RESULT_DENY;
        !           403:                                }
        !           404:                        }
        !           405:
        !           406:                        break;
        !           407:
        !           408:                default:
        !           409:                        break;
        !           410:                }
        !           411:
        !           412:                break;
        !           413:
        !           414:        case KAUTH_PROCESS_SCHEDULER_SETAFFINITY:
        !           415:                if (user_set_cpu_affinity != 0) {
        !           416:                        result = KAUTH_RESULT_ALLOW;
        !           417:                }
        !           418:                break;
        !           419:
        !           420:        default:
        !           421:                break;
        !           422:        }
        !           423:
        !           424:        return (result);
        !           425: }
        !           426:
        !           427: static int
        !           428: secmodel_extensions_network_cb(kauth_cred_t cred, kauth_action_t action,
        !           429:     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
        !           430: {
        !           431:        int result;
        !           432:        enum kauth_network_req req;
        !           433:
        !           434:        result = KAUTH_RESULT_DEFER;
        !           435:        req = (enum kauth_network_req)arg0;
        !           436:
        !           437:        if (action != KAUTH_NETWORK_SOCKET ||
        !           438:            req != KAUTH_REQ_NETWORK_SOCKET_CANSEE)
        !           439:                return result;
        !           440:
        !           441:        if (curtain != 0) {
        !           442:                struct socket *so = (struct socket *)arg1;
        !           443:
        !           444:                if (!kauth_cred_uidmatch(cred, so->so_cred)) {
        !           445:                        int error;
        !           446:                        bool isroot = false;
        !           447:
        !           448:                        error = secmodel_eval("org.netbsd.secmodel.suser",
        !           449:                            "is-root", cred, &isroot);
        !           450:                        if (error == 0 && !isroot)
        !           451:                                result = KAUTH_RESULT_DENY;
        !           452:                }
        !           453:        }
        !           454:
        !           455:        return (result);
        !           456: }

CVSweb <webmaster@jp.NetBSD.org>