From john.weeks at sun.com Tue Sep 2 00:39:45 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 02 Sep 2008 00:39:45 -0700 Subject: [fmac-discuss] [ANNOUNCE] onnv_97 Rebase/Alpha2 Available Message-ID: <48BCEDC1.8090401@sun.com> The push of the merged fmac/onnv_97 to the fmac-gate repo is complete. Now that the FMAC code base has been upgraded to onnv_97, you should be using the corresponding ON Specific Build Tools and ON Binary-Only Components from: http://dlc.sun.com/osol/on/downloads/b97/ If building on SPARC, please grab the new Studio 11 compiler from: http://opensolaris.org/os/community/tools/sun_studio_tools/sun_studio_11_SPARC_special_May2008/ If you run into problems running the Studio 11 SPARC installer with the default Java 1.6, try the following workaround: # PATH=/usr/jdk/jdk1.5.0_15/bin:${PATH} # export PATH # ./installer Then patchadd the following Studio 11 SPARC patches: 121015-04 120760-11 121017-07 122135-02 The following build error on x86 seems to be due by a reference to htonll & ntohll in pkcs11_softtoken.so.1 that's not resolved in the b97 libc: ==== Check ELF runtime attributes ==== ./usr/lib/security/amd64/pkcs11_softtoken.so.1: symbol not found: htonll (/builds/jweeks/onnv_97/proto/root_i386/usr/lib/security/amd64/pkcs11_softtoken.so.1) ./usr/lib/security/amd64/pkcs11_softtoken.so.1: symbol not found: ntohll (/builds/jweeks/onnv_97/proto/root_i386/usr/lib/security/amd64/pkcs11_softtoken.so.1) ./usr/lib/security/pkcs11_softtoken.so.1: symbol not found: htonll (/builds/jweeks/onnv_97/proto/root_i386/usr/lib/security/pkcs11_softtoken.so.1) ./usr/lib/security/pkcs11_softtoken.so.1: symbol not found: ntohll (/builds/jweeks/onnv_97/proto/root_i386/usr/lib/security/pkcs11_softtoken.so.1) ==== Diff ELF runtime attributes (since last build) ==== I've posted the issue it to opensolaris-help. It will generate an error during boot, but the system still functions. This milestone also marks our Alpha 2 functional release now that the base process context support has been integrated. We have been making great progress and I would like to extend my appreciation to all those that have contributing to and/or supported the project :-) Hg tag: fmac_alpha2 New library interfaces: int getcon(security_context_t *context); int getpidcon(pid_t pid, security_context_t *context); int getexeccon(security_context_t *context); int setexeccon(security_context_t context); int getprevcon(security_context_t *context); void freecon(security_context_t context); New commands: getenforce setenforce pcon Cheers, John From sds at tycho.nsa.gov Wed Sep 3 10:24:54 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 03 Sep 2008 13:24:54 -0400 Subject: [fmac-discuss] [RFC][PATCH] Prototype file security context support In-Reply-To: <488E1DF1.8060508@Sun.COM> References: <488CD182.5060902@Sun.COM> <1217268420.20373.88.camel@moss-spartans.epoch.ncsc.mil> <488E140F.5000907@Sun.COM> <1217272865.20373.121.camel@moss-spartans.epoch.ncsc.mil> <488E1DF1.8060508@Sun.COM> Message-ID: <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> Hi, Based on our earlier exchange about FMAC support in the filesystem, I've prototyped file security context support via a new "secctx" system attribute. This patch isn't intended for production use but is just a prototype to investigate what is required, to help identify issues with this approach, and to enable us to make progress on developing other parts of FMAC that depend on file security contexts. In the kernel, this patch adds support for a "secctx" system attribute, fetches this attribute on the lookup path and maps it to an in-core vnode secid (a non-persistent handle to a context) for internal use by FMAC, and attempts to compute and set this attribute on the create path (this last part doesn't appear to work though - see below). In userland, this patch implements getfilecon() and setfilecon() libc interfaces and corresponding utilities for getting and setting the file security context. With the patch applied, I can successfully set file contexts via setfilecon (e.g. setfilecon system_u:object_r:shadow_t /etc/shadow) and get them via getfilecon (e.g. getfilecon /etc/shadow) on a zfs filesystem. The limitations of this patch include: 1) Storage of the secctx is presently limited to 56 bytes since it is stored directly in the bonus buffer and is exclusive of the av scanstamp. I expect that this limitation can be addressed by storing the secctx externally as with the external acl support and/or by using the more extensible mechanism you are developing for system attributes. We also need a more flexible way of passing it internally as a variable-length string in the xoptattr rather than as a fixed size buffer. 2) It appears that we can only set attributes on regular files and directories, whereas we need security contexts on all file types. As I recall, Linux also had limitations in what file types supported attributes originally but these limitations were removed by the time we migrated SELinux to using Linux xattrs. Hopefully this limitation can also be removed from Solaris. 3) Although the code seems to be successfully computing a secctx for new files and setting up an xvattr to convey it to the filesystem create and mkdir operations (see fmac_vnode_create as called by fop_create and fop_mkdir) and we later see that xvattr in the subsequent secpolicy_xvattr call, the attribute is not being set on the new files by zfs. I'm not clear as to whether support for setting system attribute at creation exists in zfs presently or if I have missed some crucial step there. I'd appreciate any comments you have on the above limitations or on the code below. Webrev available at: http://cr.opensolaris.org/~sds/secctx/ diff --git a/usr/src/cmd/fmac/Makefile b/usr/src/cmd/fmac/Makefile --- a/usr/src/cmd/fmac/Makefile +++ b/usr/src/cmd/fmac/Makefile @@ -32,7 +32,9 @@ loadpolicy \ setenforce \ getenforce \ - pcon + pcon \ + getfilecon \ + setfilecon SUBDIR_POLICY = \ policy diff --git a/usr/src/cmd/fmac/getfilecon/Makefile b/usr/src/cmd/fmac/getfilecon/Makefile new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/getfilecon/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +PROG= getfilecon + +include ../../Makefile.cmd + +.KEEP_STATE: + +all: $(PROG) + +install: all $(ROOTPROG) + +clean: + +lint: lint_PROG + +include ../../Makefile.targ diff --git a/usr/src/cmd/fmac/getfilecon/getfilecon.c b/usr/src/cmd/fmac/getfilecon/getfilecon.c new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/getfilecon/getfilecon.c @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Display context for specified files. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + int i, error; + char *secctx; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ +#endif + (void) textdomain(TEXT_DOMAIN); + + if (argc <= 1) { + (void) fprintf(stderr, gettext("usage: getfilecon path ...\n")); + return (1); + } + + for (i = 1; i < argc; i++) { + error = getfilecon(argv[i], &secctx); + if (error) { + (void) fprintf(stderr, + gettext("getfilecon: getting file context of %s failed: %s\n"), + argv[i], strerror(errno)); + exit(1); + } + (void) printf("%s: %s\n", argv[i], secctx); + free(secctx); + } + + return (0); +} diff --git a/usr/src/cmd/fmac/policy/Makefile b/usr/src/cmd/fmac/policy/Makefile --- a/usr/src/cmd/fmac/policy/Makefile +++ b/usr/src/cmd/fmac/policy/Makefile @@ -130,8 +130,6 @@ fs_use$(MLS_SUFFIX) \ net_contexts$(MLS_SUFFIX) -FILECONTEXT_FILE = file_contexts$(MLS_SUFFIX) - MLS_FILE = $(MLS_FLAG:yes=mls) MLS_SUFFIX = $(MLS_FLAG:yes=.mls) @@ -179,19 +177,17 @@ users.mls: users $(SED) 's/;/ ranges u;/' $^ > $@ -install: policy +install: policy file_contexts install -s -m 744 -d $(ROOT)/etc/security/fmac cp policy ss_policy install -s -m 644 -f $(ROOT)/etc/security/fmac ss_policy + install -s -m 644 -f $(ROOT)/etc/security/fmac file_contexts load: install - load_policy /ss_policy + load_policy $(ROOT)/etc/security/fmac/ss_policy -file_contexts.mls: file_contexts - $(SED) 's/_t/_t:u/g' $^ > $@ - -relabel: $(FILECONTEXT_FILE) - $(SETFILES) -v $(FILECONTEXT_FILE) `mount -p | awk '/ufs/{print $$3}; /zfs/{print $$3}'` +relabel: file_contexts + $(SETFILES) -v file_contexts `mount -p | awk '/zfs/{print $$3}'` $(TOUCH) relabel all.te: macros.te attrib.te all_types.te all_domains.te assert.te diff --git a/usr/src/cmd/fmac/setfilecon/Makefile b/usr/src/cmd/fmac/setfilecon/Makefile new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/setfilecon/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +PROG= setfilecon + +include ../../Makefile.cmd + +.KEEP_STATE: + +all: $(PROG) + +install: all $(ROOTPROG) + +clean: + +lint: lint_PROG + +include ../../Makefile.targ diff --git a/usr/src/cmd/fmac/setfilecon/setfilecon.c b/usr/src/cmd/fmac/setfilecon/setfilecon.c new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/setfilecon/setfilecon.c @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Set context for specified files. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + int i, error; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ +#endif + (void) textdomain(TEXT_DOMAIN); + + if (argc < 3) { + (void) fprintf(stderr, gettext("usage: %s context path...\n"), argv[0]); + exit(1); + } + + for (i = 2; i < argc; i++) { + error = setfilecon(argv[i], argv[1]); + if (error) { + (void) fprintf(stderr, + gettext("setfilecon: setting file context of %s to %s failed: %s\n"), + argv[i], argv[1], strerror(errno)); + exit(1); + } + } + return (0); +} diff --git a/usr/src/cmd/fmac/setfiles/Makefile b/usr/src/cmd/fmac/setfiles/Makefile --- a/usr/src/cmd/fmac/setfiles/Makefile +++ b/usr/src/cmd/fmac/setfiles/Makefile @@ -37,7 +37,7 @@ all: $(PROG) -install: all $(ROOTSBINPROG) +install: all $(ROOTPROG) clean: diff --git a/usr/src/cmd/fmac/setfiles/setfiles.c b/usr/src/cmd/fmac/setfiles/setfiles.c --- a/usr/src/cmd/fmac/setfiles/setfiles.c +++ b/usr/src/cmd/fmac/setfiles/setfiles.c @@ -94,37 +94,7 @@ #include #include #include -#ifdef jweeks #include -#endif - -/* jweeks - until we have library support */ -int -lgetfilecon(const char *c, char **context) -{ - *context = strdup("system_u:object_r:file_t"); - return (0); -} - -int -lsetfilecon(const char *c, const char *context) -{ - return (0); -} - -void -freecon(char *context) -{ - if (context != NULL) - free(context); -} - -int -security_check_context(const char *context) -{ - return (0); -} -/* jweeks - until we have library support */ static int add_assoc = 1; @@ -370,14 +340,6 @@ return (i); } -/* Used with qsort to sort specs from lowest to highest hasMetaChars value */ -int -spec_compare(const void* specA, const void* specB) -{ - return (((struct spec *)specB)->hasMetaChars - - ((struct spec *)specA)->hasMetaChars); -} - /* * Check for duplicate specifications. If a duplicate specification is found * and the context is the same, give a warning to the user. If a duplicate @@ -501,6 +463,14 @@ return (0); } + /* + * At present only regular files and directories can be labeled. + * XXX This needs to be fixed in the kernel. + */ + if (flag == FTW_SL || + (!S_ISDIR(sb->st_mode) && !S_ISREG(sb->st_mode))) + return (0); + i = match(my_file, &my_sb); if (i < 0) /* No matching specification. */ @@ -539,16 +509,15 @@ } /* Get the current context of the file. */ - ret = lgetfilecon(my_file, &context); + ret = getfilecon(my_file, &context); if (ret < 0) { if (errno == ENODATA) { context = malloc(10); strcpy(context, "<>"); } else { - perror(my_file); fprintf(stderr, "%s: unable to obtain attribute for " - "file %s\n", - progname, my_file); + "file %s: %s\n", + progname, my_file, strerror(errno)); return (-1); } } @@ -580,7 +549,7 @@ /* * Relabel the file to the specified context. */ - ret = lsetfilecon(my_file, spec[i].context); + ret = setfilecon(my_file, spec[i].context); if (ret) { perror(my_file); fprintf(stderr, "%s: unable to relabel %s to %s\n", @@ -599,7 +568,8 @@ char buf[255 + 1], *buf_p; char regex[256], type[256], context[256]; char *anchored_regex; - int opt, items, len, lineno, pass, nerr, regerr, i; + int opt, items, len, lineno, pass, nerr, regerr, i, j; + spec_t *spec_copy; /* Process any options. */ while ((opt = getopt(argc, argv, "dnpqvxW")) > 0) { @@ -819,8 +789,25 @@ } fclose(fp); - /* Sort the specifications with most general first */ - qsort(spec, nspec, sizeof (struct spec), spec_compare); + /* Move exact pathname specifications to the end. */ + spec_copy = malloc(sizeof (spec_t) * nspec); + if (!spec_copy) { + fprintf(stderr, + "%s: insufficient memory for specifications\n", + argv[0]); + exit(1); + } + j = 0; + for (i = 0; i < nspec; i++) { + if (spec[i].hasMetaChars) + memcpy(&spec_copy[j++], &spec[i], sizeof (spec_t)); + } + for (i = 0; i < nspec; i++) { + if (!spec[i].hasMetaChars) + memcpy(&spec_copy[j++], &spec[i], sizeof (spec_t)); + } + free(spec); + spec = spec_copy; /* Verify no exact duplicates */ if (nodups_specs() != 0) { diff --git a/usr/src/common/fmac/ss/services.c b/usr/src/common/fmac/ss/services.c --- a/usr/src/common/fmac/ss/services.c +++ b/usr/src/common/fmac/ss/services.c @@ -502,9 +502,6 @@ return (0); } } - (void) printf("security_context_to_sid: called before initial " - "load_policy on unknown context %s\n", - scontext); return (EINVAL); } *sid = SECSID_NULL; diff --git a/usr/src/common/xattr/xattr_common.c b/usr/src/common/xattr/xattr_common.c --- a/usr/src/common/xattr/xattr_common.c +++ b/usr/src/common/xattr/xattr_common.c @@ -63,6 +63,7 @@ { A_OWNERSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST }, { A_GROUPSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST }, { A_FSID, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT64 }, + { A_SECCTX, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_STRING }, }; const char * diff --git a/usr/src/head/fmac/fmac.h b/usr/src/head/fmac/fmac.h --- a/usr/src/head/fmac/fmac.h +++ b/usr/src/head/fmac/fmac.h @@ -55,7 +55,8 @@ int setexeccon(security_context_t context); int getprevcon(security_context_t *context); void freecon(security_context_t context); - +int getfilecon(const char *path, char **secctxp); +int setfilecon(const char *path, char *secctx); #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -107,6 +107,7 @@ cuexit.o \ ecvt.o \ errlst.o \ + filecon.o \ amd64_data.o \ ldivide.o \ lock.o \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -426,6 +426,7 @@ fattach.o \ fdetach.o \ fdopendir.o \ + filecon.o \ fmtmsg.o \ ftime.o \ ftok.o \ diff --git a/usr/src/lib/libc/inc/libc.h b/usr/src/lib/libc/inc/libc.h --- a/usr/src/lib/libc/inc/libc.h +++ b/usr/src/lib/libc/inc/libc.h @@ -72,8 +72,11 @@ extern void callout_lock_exit(void); extern void *lmalloc(size_t); extern void lfree(void *, size_t); +extern int libc_nvlist_alloc(nvlist_t **,uint_t, int); extern void libc_nvlist_free(nvlist_t *); extern int libc_nvlist_lookup_uint64(nvlist_t *, const char *, uint64_t *); +extern int libc_nvlist_lookup_string(nvlist_t *, const char *, char **); +extern int libc_nvlist_add_string(nvlist_t *, const char *, const char *); extern void *libc_malloc(size_t); extern void *libc_realloc(void *, size_t); extern void libc_free(void *); diff --git a/usr/src/lib/libc/port/gen/attrat.c b/usr/src/lib/libc/port/gen/attrat.c --- a/usr/src/lib/libc/port/gen/attrat.c +++ b/usr/src/lib/libc/port/gen/attrat.c @@ -44,8 +44,11 @@ static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int); static int (*nvsize)(nvlist_t *, size_t *, int); static int (*nvunpacker)(char *, size_t, nvlist_t **); +static int (*nvalloc)(nvlist_t **, uint_t, int); static int (*nvfree)(nvlist_t *); static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *); +static int (*nvlookupstring)(nvlist_t *, const char *, char **); +static int (*nvaddstring)(nvlist_t *, const char *, const char *); static mutex_t attrlock = DEFAULTMUTEX; static int initialized; @@ -62,8 +65,11 @@ void *packer; void *sizer; void *unpacker; + void *allocer; void *freer; void *looker; + void *lookupstr; + void *addstr; if (initialized == 0) { void *handle = dlopen("libnvpair.so.1", RTLD_LAZY); @@ -72,8 +78,12 @@ (packer = dlsym(handle, "nvlist_pack")) == NULL || (sizer = dlsym(handle, "nvlist_size")) == NULL || (unpacker = dlsym(handle, "nvlist_unpack")) == NULL || + (allocer = dlsym(handle, "nvlist_alloc")) == NULL || (freer = dlsym(handle, "nvlist_free")) == NULL || - (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) { + (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL || + (lookupstr = dlsym(handle, "nvlist_lookup_string")) + == NULL || + (addstr = dlsym(handle, "nvlist_add_string")) == NULL) { if (handle) dlclose(handle); return (-1); @@ -93,10 +103,16 @@ sizer; nvunpacker = (int (*)(char *, size_t, nvlist_t **)) unpacker; + nvalloc = (int (*)(nvlist_t **, uint_t, int)) + allocer; nvfree = (int (*)(nvlist_t *)) freer; nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *)) looker; + nvlookupstring = (int (*)(nvlist_t *, const char *, char **)) + lookupstr; + nvaddstring = (int (*)(nvlist_t *, const char *, const char *)) + addstr; membar_producer(); initialized = 1; @@ -303,6 +319,15 @@ return (error); } +int +libc_nvlist_alloc(nvlist_t **nvp, uint_t nvflag, int flag) +{ + int error; + if (error = attrat_init()) + return (error); + return (nvalloc(nvp, nvflag, flag)); +} + void libc_nvlist_free(nvlist_t *nvp) { @@ -314,3 +339,15 @@ { return (nvlookupint64(nvp, name, value)); } + +int +libc_nvlist_lookup_string(nvlist_t *nvp, const char *name, char **value) +{ + return (nvlookupstring(nvp, name, value)); +} + +int +libc_nvlist_add_string(nvlist_t *nvp, const char *name, const char *value) +{ + return (nvaddstring(nvp, name, value)); +} diff --git a/usr/src/lib/libc/port/gen/filecon.c b/usr/src/lib/libc/port/gen/filecon.c new file mode 100644 --- /dev/null +++ b/usr/src/lib/libc/port/gen/filecon.c @@ -0,0 +1,90 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma weak _getfilecon = getfilecon +#pragma weak _setfilecon = setfilecon + +#include "lint.h" +#include "libc.h" +#include +#include +#include +#include +#include +#include +#include + +#ifndef A_SECCTX +#define A_SECCTX "secctx" +#endif + +int +getfilecon(const char *path, char **secctxp) +{ + nvlist_t *nvp; + int error; + char *secctx; + + error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, path, &nvp); + if (error) + return (-1); + error = libc_nvlist_lookup_string(nvp, A_SECCTX, &secctx); + if (error) { + errno = ENODATA; + libc_nvlist_free(nvp); + return (-1); + } + *secctxp = strdup(secctx); + libc_nvlist_free(nvp); + if (!(*secctxp)) + return (-1); + return (0); +} + +int +setfilecon(const char *path, char *secctx) +{ + nvlist_t *nvp; + int error; + + error = libc_nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0); + if (error) { + errno = error; + return (-1); + } + + error = libc_nvlist_add_string(nvp, A_SECCTX, secctx); + if (error) { + errno = error; + error = -1; + goto out; + } + + error = setattrat(AT_FDCWD, XATTR_VIEW_READWRITE, path, nvp); +out: + libc_nvlist_free(nvp); + return (error); +} diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -82,6 +82,7 @@ getattrat; getcon; getexeccon; + getfilecon; getpagesizes2; getpidcon; getprevcon; @@ -137,6 +138,7 @@ sem_wait; setattrat; setexeccon; + setfilecon; _sharefs; shm_open; shm_unlink; diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile --- a/usr/src/lib/libc/sparc/Makefile +++ b/usr/src/lib/libc/sparc/Makefile @@ -450,6 +450,7 @@ fattach.o \ fdetach.o \ fdopendir.o \ + filecon.o \ fmtmsg.o \ ftime.o \ ftok.o \ diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile --- a/usr/src/lib/libc/sparcv9/Makefile +++ b/usr/src/lib/libc/sparcv9/Makefile @@ -411,6 +411,7 @@ fattach.o \ fdetach.o \ fdopendir.o \ + filecon.o \ fmtmsg.o \ ftime.o \ ftok.o \ diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -286,6 +286,7 @@ f none etc/security/dev/st1 400 root bin d none etc/security/fmac 755 root bin f none etc/security/fmac/ss_policy 644 root sys +f none etc/security/fmac/file_contexts 644 root sys f none etc/security/kmfpolicy.xml 644 root bin d none etc/security/lib 755 root sys f none etc/security/lib/audio_clean 555 root sys diff --git a/usr/src/pkgdefs/SUNWesu/prototype_com b/usr/src/pkgdefs/SUNWesu/prototype_com --- a/usr/src/pkgdefs/SUNWesu/prototype_com +++ b/usr/src/pkgdefs/SUNWesu/prototype_com @@ -66,6 +66,7 @@ f none usr/bin/dos2unix 555 root bin f none usr/bin/expand 555 root bin f none usr/bin/factor 555 root bin +f none usr/bin/getfilecon 555 root bin f none usr/bin/graph 555 root bin f none usr/bin/kstat 555 root bin f none usr/bin/last 555 root bin @@ -103,6 +104,8 @@ l none usr/bin/pwait=../../usr/lib/isaexec l none usr/bin/pwdx=../../usr/lib/isaexec f none usr/bin/sdiff 555 root bin +f none usr/bin/setfilecon 555 root bin +f none usr/bin/setfiles 555 root bin l none usr/bin/sort=../../usr/lib/isaexec f none usr/bin/spell 555 root bin f none usr/bin/spline 555 root bin diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -34,8 +34,11 @@ #include #include #include +#include #include #include +#include +#include /* Tunables */ int fmac_enabled = 1; /* policy enabled */ @@ -125,3 +128,183 @@ return (0); } + +security_class_t +fmac_vtype_to_sclass(vtype_t vtype) +{ + switch (vtype) { + case VREG: + return (SECCLASS_FILE); + case VDIR: + return (SECCLASS_DIR); + case VBLK: + return (SECCLASS_BLK_FILE); + case VCHR: + return (SECCLASS_CHR_FILE); + case VLNK: + return (SECCLASS_LNK_FILE); + case VFIFO: + return (SECCLASS_FIFO_FILE); + case VSOCK: + return (SECCLASS_SOCK_FILE); + case VDOOR: + /* TBD */ + case VPROC: + /* TBD */ + case VPORT: + /* TBD */ + case VNON: + return (SECCLASS_NULL); + } + return (SECCLASS_NULL); +} + +int +fmac_vnode_lookup(vnode_t *vp, cred_t *cr, caller_context_t *ct) +{ + int error; + xvattr_t xvattr; + xoptattr_t *xoap; + security_id_t secid; + + if (!fmac_enabled) + return (0); + if (vp->v_secid != SECINITSID_UNLABELED) + return (0); /* already set */ + + xva_init(&xvattr); + if ((xoap = xva_getxoptattr(&xvattr)) == NULL) + return (EINVAL); + XVA_SET_REQ(&xvattr, XAT_SECCTX); + + error = VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct); + if (error) + return (error); + + if (XVA_ISSET_RTN(&xvattr, XAT_SECCTX)) { + error = security_context_to_sid(xoap->xoa_secctx, + strlen(xoap->xoa_secctx), &secid); + if (error) + return (error); + } else { + /* default SID for files without a secctx. */ + secid = SECINITSID_FILE; + } + + mutex_enter(&(vp->v_lock)); + if (vp->v_secid == SECINITSID_UNLABELED) + vp->v_secid = secid; + mutex_exit(&(vp->v_lock)); + + return (0); +} + +int +fmac_vnode_set_secctx(char *secctx, cred_t *cr, vtype_t vtype, vnode_t *vp) +{ + security_id_t cr_secid, old_secid, new_secid; + security_class_t sclass; + int error; + + if (!fmac_enabled) + return (EINVAL); + + cr_secid = crgetsecid(cr); + + sclass = fmac_vtype_to_sclass(vtype); + if (!sclass) + return (EINVAL); + + error = security_context_to_sid(secctx, strlen(secctx), &new_secid); + if (error) + return (error); + + if (vp) { + /* + * Relabeling an existing file. + */ + mutex_enter(&(vp->v_lock)); + old_secid = vp->v_secid; + error = avc_has_perm(cr_secid, old_secid, sclass, + FILE__RELABELFROM); + if (!error) + error = avc_has_perm(cr_secid, new_secid, sclass, + FILE__RELABELTO); + vp->v_secid = new_secid; + mutex_exit(&(vp->v_lock)); + } else { + /* Creating a new file. */ + error = avc_has_perm(cr_secid, new_secid, sclass, + FILE__CREATE); + } + + return (error); +} + +int +fmac_vnode_create(vnode_t *dvp, char *name, xvattr_t *xvap, vattr_t **vapp, + cred_t *cr, security_id_t *secidp) +{ + security_id_t cr_secid, secid; + security_class_t sclass; + security_context_t scontext; + uint32_t scontext_len; + xoptattr_t *xoap; + int error; + + _NOTE(ARGUNUSED(name)); /* future use in audit message */ + + if (!fmac_enabled) + return (0); + + *secidp = SECINITSID_FILE; + + sclass = fmac_vtype_to_sclass((*vapp)->va_type); + if (!sclass) + return (0); + + cr_secid = crgetsecid(cr); + + if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR) == 0) + return (0); + + /* + * Wrap the vattr with an xvattr so we can pass the + * secctx to the fs code. + */ + xva_init(xvap); + (void) memcpy(&xvap->xva_vattr, *vapp, sizeof (vattr_t)); + xvap->xva_vattr.va_mask |= AT_XVATTR; + XVA_SET_REQ(xvap, XAT_SECCTX); + + error = security_transition_sid(cr_secid, dvp->v_secid, sclass, + &secid); + if (error) + return (error); + + error = security_sid_to_context(secid, &scontext, &scontext_len); + if (error) + return (error); + + if (scontext_len > sizeof (xoap->xoa_secctx)) + return (EINVAL); + + xoap = xva_getxoptattr(xvap); + if (!xoap) + return (EINVAL); + (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx)); + + *secidp = secid; + *vapp = &xvap->xva_vattr; + return (0); +} + +void +fmac_vnode_post_create(vnode_t *vp, security_id_t secid) +{ + if (!fmac_enabled) + return; + mutex_enter(&(vp->v_lock)); + vp->v_secid = secid; + mutex_exit(&(vp->v_lock)); +} diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include #include #include @@ -2309,6 +2311,7 @@ vp->v_flag = 0; vp->v_type = VNON; vp->v_rdev = NODEV; + vp->v_secid = SECINITSID_UNLABELED; vp->v_filocks = NULL; vp->v_shrlocks = NULL; @@ -3333,6 +3336,7 @@ (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp); } if (ret == 0 && *vpp) { + (void) fmac_vnode_lookup(*vpp, cr, ct); VOPSTATS_UPDATE(*vpp, lookup); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, nm, strlen(nm)); @@ -3356,6 +3360,8 @@ vsecattr_t *vsecp) /* ACL to set during create */ { int ret; + xvattr_t xvattr; + security_id_t secid; if (vsecp != NULL && vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) { @@ -3369,12 +3375,17 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) return (EINVAL); + + ret = fmac_vnode_create(dvp, name, &xvattr, &vap, cr, &secid); + if (ret) + return (ret); VOPXID_MAP_CR(dvp, cr); ret = (*(dvp)->v_op->vop_create) (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp); if (ret == 0 && *vpp) { + fmac_vnode_post_create(*vpp, secid); VOPSTATS_UPDATE(*vpp, create); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, name, strlen(name)); @@ -3477,6 +3488,8 @@ int flags, vsecattr_t *vsecp) /* ACL to set during create */ { + xvattr_t xvattr; + security_id_t secid; int ret; if (vsecp != NULL && @@ -3491,12 +3504,17 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) return (EINVAL); + + ret = fmac_vnode_create(dvp, dirname, &xvattr, &vap, cr, &secid); + if (ret) + return (ret); VOPXID_MAP_CR(dvp, cr); ret = (*(dvp)->v_op->vop_mkdir) (dvp, dirname, vap, vpp, cr, ct, flags, vsecp); if (ret == 0 && *vpp) { + fmac_vnode_post_create(*vpp, secid); VOPSTATS_UPDATE(*vpp, mkdir); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, dirname, diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c --- a/usr/src/uts/common/fs/xattr.c +++ b/usr/src/uts/common/fs/xattr.c @@ -214,6 +214,9 @@ VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr), fsid) == 0); break; + case F_SECCTX: + XVA_SET_REQ(&xvattr, XAT_SECCTX); + break; default: break; } @@ -288,6 +291,11 @@ attr_to_name(F_AV_SCANSTAMP), xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp)) == 0); + } + if (XVA_ISSET_RTN(&xvattr, XAT_SECCTX)) { + VERIFY(nvlist_add_string(nvlp, + attr_to_name(F_SECCTX), + xoap->xoa_secctx) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) { VERIFY(nvlist_add_uint64_array(nvlp, @@ -511,6 +519,7 @@ uint_t elem, nelems; nvlist_t *nvp_sid; uint8_t *scanstamp; + char *secctx = NULL; /* * Validate the name and type of each attribute. @@ -569,6 +578,12 @@ case DATA_TYPE_UINT8_ARRAY: if (nvpair_value_uint8_array(pair, &scanstamp, &nelems)) { + nvlist_free(nvp); + return (EINVAL); + } + break; + case DATA_TYPE_STRING: + if (nvpair_value_string(pair, &secctx)) { nvlist_free(nvp); return (EINVAL); } @@ -665,6 +680,16 @@ nvlist_free(nvp); return (EINVAL); } + break; + case F_SECCTX: + if (!secctx || + strlen(secctx) >= sizeof (xoap->xoa_secctx)) { + nvlist_free(nvp); + return (EINVAL); + } + XVA_SET_REQ(&xvattr, XAT_SECCTX); + (void) strncpy(xoap->xoa_secctx, secctx, + sizeof (xoap->xoa_secctx)); break; default: break; diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h --- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h @@ -77,6 +77,7 @@ #define ZFS_ACL_DEFAULTED 0x20 /* ACL should be defaulted */ #define ZFS_ACL_AUTO_INHERIT 0x40 /* ACL should be inherited */ #define ZFS_BONUS_SCANSTAMP 0x80 /* Scanstamp in bonus area */ +#define ZFS_BONUS_SECCTX 0x100 /* Secctx in bonus area */ /* * Is ID ephemeral? @@ -159,6 +160,7 @@ * At present, we use this space for the following: * - symbolic links * - 32-byte anti-virus scanstamp (regular files only) + * - security context */ } znode_phys_t; diff --git a/usr/src/uts/common/fs/zfs/sys/zil.h b/usr/src/uts/common/fs/zfs/sys/zil.h --- a/usr/src/uts/common/fs/zfs/sys/zil.h +++ b/usr/src/uts/common/fs/zfs/sys/zil.h @@ -98,13 +98,13 @@ * size of xvattr log section. * its composed of lr_attr_t + xvattr bitmap + 2 64 bit timestamps * for create time and a single 64 bit integer for all of the attributes, - * and 4 64 bit integers (32 bytes) for the scanstamp. - * + * and either 4 64 bit integers (32 bytes) for the scanstamp or + * 56 bytes for the security context. */ #define ZIL_XVAT_SIZE(mapsize) \ sizeof (lr_attr_t) + (sizeof (uint32_t) * (mapsize - 1)) + \ - (sizeof (uint64_t) * 7) + (sizeof (uint64_t) * 7) + 24 /* * Size of ACL in log. The ACE data is padded out to properly align diff --git a/usr/src/uts/common/fs/zfs/zfs_log.c b/usr/src/uts/common/fs/zfs/zfs_log.c --- a/usr/src/uts/common/fs/zfs/zfs_log.c +++ b/usr/src/uts/common/fs/zfs/zfs_log.c @@ -101,7 +101,7 @@ uint64_t *attrs; uint64_t *crtime; xoptattr_t *xoap; - void *scanstamp; + void *extradata; /* scanstamp or secctx */ int i; xoap = xva_getxoptattr(xvap); @@ -116,7 +116,7 @@ /* Now pack the attributes up in a single uint64_t */ attrs = (uint64_t *)bitmap; crtime = attrs + 1; - scanstamp = (caddr_t)(crtime + 2); + extradata = (caddr_t)(crtime + 2); *attrs = 0; if (XVA_ISSET_REQ(xvap, XAT_READONLY)) *attrs |= (xoap->xoa_readonly == 0) ? 0 : @@ -154,7 +154,9 @@ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime); if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) - bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ); + bcopy(xoap->xoa_av_scanstamp, extradata, AV_SCANSTAMP_SZ); + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) + bcopy(xoap->xoa_secctx, extradata, SECCTX_SZ); } static void * diff --git a/usr/src/uts/common/fs/zfs/zfs_replay.c b/usr/src/uts/common/fs/zfs/zfs_replay.c --- a/usr/src/uts/common/fs/zfs/zfs_replay.c +++ b/usr/src/uts/common/fs/zfs/zfs_replay.c @@ -83,7 +83,7 @@ uint64_t *attrs; uint64_t *crtime; uint32_t *bitmap; - void *scanstamp; + void *extradata; /* scanstamp or secctx */ int i; xvap->xva_vattr.va_mask |= AT_XVATTR; @@ -100,7 +100,7 @@ attrs = (uint64_t *)(lrattr + lrattr->lr_attr_masksize - 1); crtime = attrs + 1; - scanstamp = (caddr_t)(crtime + 2); + extradata = (caddr_t)(crtime + 2); if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) xoap->xoa_hidden = ((*attrs & XAT0_HIDDEN) != 0); @@ -128,7 +128,9 @@ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime); if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) - bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); + bcopy(extradata, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) + bcopy(extradata, xoap->xoa_secctx, SECCTX_SZ); } static int diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -1182,7 +1182,7 @@ if (vap->va_mask & AT_XVATTR) { if ((error = secpolicy_xvattr((xvattr_t *)vap, - crgetuid(cr), cr, vap->va_type)) != 0) { + crgetuid(cr), cr, vap->va_type, NULL)) != 0) { ZFS_EXIT(zfsvfs); return (error); } @@ -1637,7 +1637,7 @@ if (vap->va_mask & AT_XVATTR) if ((error = secpolicy_xvattr((xvattr_t *)vap, - crgetuid(cr), cr, vap->va_type)) != 0) { + crgetuid(cr), cr, vap->va_type, NULL)) != 0) { ZFS_EXIT(zfsvfs); return (error); } @@ -2316,6 +2316,28 @@ pzp + 1, sizeof (xoap->xoa_av_scanstamp)); XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); + } + } + + if (XVA_ISSET_REQ(xvap, XAT_SECCTX) && + vp->v_type != VLNK && + (pzp->zp_flags & ZFS_BONUS_SECCTX)) { + size_t len = 0; + dmu_object_info_t doi; + + dmu_object_info_from_db(zp->z_dbuf, &doi); + len = sizeof (xoap->xoa_secctx) + + sizeof (znode_phys_t); + if (len <= doi.doi_bonus_size) { + /* + * pzp points to the start of the + * znode_phys_t. pzp + 1 points to the + * first byte after the znode_phys_t. + */ + (void) memcpy(xoap->xoa_secctx, + pzp + 1, + sizeof (xoap->xoa_secctx)); + XVA_SET_RTN(xvap, XAT_SECCTX); } } @@ -2570,6 +2592,7 @@ xoap->xoa_av_quarantined != ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)))) || (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) || + (XVA_ISSET_REQ(xvap, XAT_SECCTX)) || (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { need_policy = TRUE; } @@ -2763,7 +2786,8 @@ */ if (xoap && (mask & AT_XVATTR)) { - if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { + if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) && + (!(zp->z_phys->zp_flags & ZFS_BONUS_SECCTX))) { size_t len; dmu_object_info_t doi; @@ -2772,6 +2796,20 @@ /* Grow the bonus buffer if necessary. */ dmu_object_info_from_db(zp->z_dbuf, &doi); len = sizeof (xoap->xoa_av_scanstamp) + + sizeof (znode_phys_t); + if (len > doi.doi_bonus_size) + VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); + } + if (XVA_ISSET_REQ(xvap, XAT_SECCTX) && + (!(zp->z_phys->zp_flags & ZFS_BONUS_SCANSTAMP))) { + size_t len; + dmu_object_info_t doi; + + ASSERT(vp->v_type != VLNK); + + /* Grow the bonus buffer if necessary. */ + dmu_object_info_from_db(zp->z_dbuf, &doi); + len = sizeof (xoap->xoa_secctx) + sizeof (znode_phys_t); if (len > doi.doi_bonus_size) VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c --- a/usr/src/uts/common/fs/zfs/zfs_znode.c +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c @@ -913,6 +913,12 @@ zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP; XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); } + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) { + (void) memcpy(zp->z_phys + 1, xoap->xoa_secctx, + sizeof (xoap->xoa_secctx)); + zp->z_phys->zp_flags |= ZFS_BONUS_SECCTX; + XVA_SET_RTN(xvap, XAT_SECCTX); + } } int diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1060,7 +1061,8 @@ * Check privileges for setting xvattr attributes */ int -secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) +secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype, + vnode_t *vp) { xoptattr_t *xoap; int error = 0; @@ -1112,6 +1114,12 @@ xoap->xoa_av_scanstamp, cr); if (error == 0 && vtype != VREG) error = EINVAL; + } + if (error == 0 && XVA_ISSET_REQ(xvap, XAT_SECCTX)) { + error = secpolicy_vnode_owner(cr, owner); + if (!error) + error = fmac_vnode_set_secctx(xoap->xoa_secctx, cr, + vtype, vp); } return (error); } @@ -1268,7 +1276,7 @@ */ if (mask & AT_XVATTR) error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr, - vp->v_type); + vp->v_type, vp); out: return (error); } diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h --- a/usr/src/uts/common/sys/attr.h +++ b/usr/src/uts/common/sys/attr.h @@ -56,6 +56,7 @@ #define A_AV_SCANSTAMP "av_scanstamp" #define A_OWNERSID "ownersid" #define A_GROUPSID "groupsid" +#define A_SECCTX "secctx" /* Attribute option for utilities */ #define O_HIDDEN "H" @@ -92,6 +93,7 @@ F_OWNERSID, F_GROUPSID, F_FSID, + F_SECCTX, F_ATTR_ALL } f_attr_t; diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -33,6 +33,7 @@ #if defined(_KERNEL) #include +#include #else #include #endif /* _KERNEL */ @@ -83,6 +84,11 @@ extern char *fmac_default_policy_file; void fmac_init(void); int fmac_load_policy(char *file); +int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); +int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *); +int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, + security_id_t *); +void fmac_vnode_post_create(vnode_t *, security_id_t); #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h --- a/usr/src/uts/common/sys/policy.h +++ b/usr/src/uts/common/sys/policy.h @@ -32,6 +32,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -160,7 +161,7 @@ void secpolicy_fs_mount_clearopts(cred_t *, struct vfs *); int secpolicy_setid_setsticky_clear(vnode_t *, vattr_t *, const vattr_t *, cred_t *); -int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t); +int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t, vnode_t *); int secpolicy_xvm_control(const cred_t *); int secpolicy_basic_exec(const cred_t *, vnode_t *); diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h --- a/usr/src/uts/common/sys/vnode.h +++ b/usr/src/uts/common/sys/vnode.h @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef _KERNEL #include #endif /* _KERNEL */ @@ -195,6 +196,7 @@ * v_path * v_vsd * v_xattrdir + * v_secid * * A special lock (implemented by vn_vfswlock in vnode.c) protects: * v_vfsmountedhere @@ -233,6 +235,7 @@ struct stdata *v_stream; /* associated stream */ enum vtype v_type; /* vnode type */ dev_t v_rdev; /* device (VCHR, VBLK) */ + security_id_t v_secid; /* FMAC security identifier */ /* PRIVATE FIELDS BELOW - DO NOT USE */ @@ -364,6 +367,8 @@ } vattr_t; #define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */ +#define SECCTX_SZ 56 /* length of secctx */ +/* XXX: This should be variable sized and support large sizes. TBD. */ /* * Structure of all optional attributes. @@ -382,6 +387,7 @@ uint8_t xoa_av_quarantined; uint8_t xoa_av_modified; uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ]; + char xoa_secctx[SECCTX_SZ]; } xoptattr_t; /* @@ -560,11 +566,12 @@ #define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */ #define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */ #define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */ +#define XAT0_SECCTX 0x00002000 /* security context */ #define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \ XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \ XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| \ - XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP) + XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP|XAT0_SECCTX) /* Support for XAT_* optional attributes */ #define XVA_MASK 0xffffffff /* Used to mask off 32 bits */ @@ -597,6 +604,7 @@ #define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED) #define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED) #define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP) +#define XAT_SECCTX ((XAT0_INDEX << XVA_SHFT) | XAT0_SECCTX) /* * The returned attribute map array (xva_rtnattrmap[]) is located past the -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Sep 3 10:49:07 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 03 Sep 2008 13:49:07 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support Message-ID: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> This patch adds basic security context transition support to FMAC. It depends on the prior patch for file security context support in order to obtain the security context for executables. With this patch applied and a suitably labeled filesystem and policy, processes will automatically transition into a suitable security context when they execute a program based on the program file's security context, and a process may explicitly transition to a given security context if authorized. This patch implements the execute_no_trans, transition, and entrypoint permission checks. The execute check will be handled by a separate change to fop_access. Other checks applied upon security context transitions in SELinux such as inheritance of open file descriptors and other state will be introduced to FMAC by subsequent patches. The checks applied here are: - If not transitioning, may the process execute the file without transitioning to a new security context? - If transitioning, may the process transition to the new security context and may the new security context be entered via the program? Webrev available at: http://cr.opensolaris.org/~sds/exec/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -308,3 +308,46 @@ vp->v_secid = secid; mutex_exit(&(vp->v_lock)); } + +int +fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, + security_id_t *prev_secidp, security_id_t *secidp) +{ + security_id_t prev_secid, secid; + int error; + + if (!fmac_enabled) + return (0); + + prev_secid = crgetsecid(cr); + secid = crgetexecsecid(cr); + if (!secid) { + error = security_transition_sid(prev_secid, vp->v_secid, + SECCLASS_PROCESS, &secid); + if (error) + return (error); + } + + if (prev_secid == secid) { + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, + FILE__EXECUTE_NO_TRANS); + if (error) + return (error); + *setsecid = 0; + return (0); + } + + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, + PROCESS__TRANSITION); + if (error) + return (error); + + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, + FILE__ENTRYPOINT); + if (error) + return (error); + *setsecid = 1; + *prev_secidp = prev_secid; + *secidp = secid; + return (0); +} diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -68,6 +68,7 @@ #include #include #include +#include #include @@ -522,6 +523,8 @@ int suidflags = 0; ssize_t resid; uid_t uid, gid; + security_id_t prev_secid, secid; + int setsecid = 0; struct vattr vattr; char magbuf[MAGIC_BYTES]; int setid; @@ -562,10 +565,25 @@ if ((eswp = findexec_by_hdr(magbuf)) == NULL) goto bad; - if (level == 0 && - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { + if (level == 0) { + privflags = execsetid(vp, &vattr, &uid, &gid); + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); + if (error) + goto bad; + + if (setsecid) + privflags |= PRIV_SETUGID; + } + + if (level == 0 && privflags != 0) { newcred = cred = crdup(cred); + + if (setsecid) { + cred->cr_prev_secid = prev_secid; + cred->cr_secid = secid; + cred->cr_exec_secid = SECSID_NULL; + } /* If we can, drop the PA bit */ if ((privflags & PRIV_RESET) != 0) diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -89,6 +89,8 @@ int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, security_id_t *); void fmac_vnode_post_create(vnode_t *, security_id_t); +int fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, + security_id_t *prev_secidp, security_id_t *secidp); #endif /* _KERNEL */ #ifdef __cplusplus -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Sep 3 11:06:54 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 03 Sep 2008 14:06:54 -0400 Subject: [fmac-discuss] [PATCH] File contexts and policy changes Message-ID: <1220465214.6034.168.camel@moss-spartans.epoch.ncsc.mil> This patch updates the file contexts and policy configurations to allow the preceding prototype file security context support and basic security context transition support to be demonstrated. After applying all three patches, one can do the following: # Label filesystems $ setfiles /etc/security/fmac/file_contexts / $ getfilecon /sbin/init /usr/lib/ssh/sshd /bin/bash /sbin/init: system_u:object_r:init_exec_t /usr/lib/ssh/sshd: system_u:object_r:sshd_exec_t /bin/bash: system_u:object_r:shell_exec_t $ reboot and then upon logging into the system via ssh, the processes should have typical domains for the user shell, sshd daemon, and init processes: $ pcon $$ $PPID 1 : system_u:system_r:user_t:unclassified : system_u:system_r:sshd_t:unclassified 1: system_u:system_r:init_t:unclassified Webrev available at: http://cr.opensolaris.org/~sds/policy/ diff --git a/usr/src/cmd/fmac/policy/assert.te b/usr/src/cmd/fmac/policy/assert.te --- a/usr/src/cmd/fmac/policy/assert.te +++ b/usr/src/cmd/fmac/policy/assert.te @@ -77,9 +77,8 @@ # Verify that the authentication domains are the only other domains # that can read this file. # -neverallow ~{ admin passwd_t } etc_auth_t:dir { add_name remove_name rename }; -neverallow ~{ admin passwd_t } etc_auth_t:file { write append unlink rename }; -neverallow ~{ admin auth } etc_auth_t:file { read }; +neverallow ~{ admin passwd_t } shadow_t:file { write append unlink rename }; +neverallow ~{ admin auth } shadow_t:file { read }; # # Verify that only the administrator domain and the diff --git a/usr/src/cmd/fmac/policy/domains/every.te b/usr/src/cmd/fmac/policy/domains/every.te --- a/usr/src/cmd/fmac/policy/domains/every.te +++ b/usr/src/cmd/fmac/policy/domains/every.te @@ -179,7 +179,7 @@ # Inherit and use descriptors from login. allow domain local_login_t:fd inherit_fd_perms; allow domain remote_login_t:fd inherit_fd_perms; -allow domain sshd_login_t:fd inherit_fd_perms; +allow domain sshd_t:fd inherit_fd_perms; # Create and use NFS files. # FIXME! Only grant to domains that truly need this access. diff --git a/usr/src/cmd/fmac/policy/domains/program/newrole.te b/usr/src/cmd/fmac/policy/domains/program/newrole.te --- a/usr/src/cmd/fmac/policy/domains/program/newrole.te +++ b/usr/src/cmd/fmac/policy/domains/program/newrole.te @@ -51,8 +51,7 @@ allow newrole_t self:capability { setuid setgid net_bind_service dac_override }; # Read password files -allow newrole_t etc_auth_t:dir r_dir_perms; -allow newrole_t etc_auth_t:file r_file_perms; +allow newrole_t shadow_t:file r_file_perms; # Write to utmp allow newrole_t initrc_var_run_t:file rw_file_perms; diff --git a/usr/src/cmd/fmac/policy/domains/program/passwd.te b/usr/src/cmd/fmac/policy/domains/program/passwd.te --- a/usr/src/cmd/fmac/policy/domains/program/passwd.te +++ b/usr/src/cmd/fmac/policy/domains/program/passwd.te @@ -44,17 +44,10 @@ allow passwd_t local_login_t:fd inherit_fd_perms; allow passwd_t remote_login_t:fd inherit_fd_perms; -# Execute /usr/bin/{passwd,chfn,chsh}. -can_exec(passwd_t, bin_t) - # Update /etc/passwd. allow passwd_t etc_t:dir rw_dir_perms; allow passwd_t etc_t:file create_file_perms; -# Update /etc/auth/shadow. -allow passwd_t etc_auth_t:dir rw_dir_perms; -allow passwd_t etc_auth_t:file create_file_perms; - -# /usr/bin/passwd asks for w access to utmp, but it will operate -# correctly without it. Do not audit write denials to utmp. -auditdeny passwd_t initrc_var_run_t:file ~write; +# Update /etc/shadow. +allow passwd_t shadow_t:file create_file_perms; +file_type_auto_trans(passwd_t, etc_t, shadow_t) diff --git a/usr/src/cmd/fmac/policy/domains/program/su.te b/usr/src/cmd/fmac/policy/domains/program/su.te --- a/usr/src/cmd/fmac/policy/domains/program/su.te +++ b/usr/src/cmd/fmac/policy/domains/program/su.te @@ -60,9 +60,8 @@ allow $1_su_t $1_gph_t:fd inherit_fd_perms; allow $1_t $1_gph_t:fd inherit_fd_perms; -# Read /etc/auth/shadow. -allow $1_su_t etc_auth_t:dir r_dir_perms; -allow $1_su_t etc_auth_t:file r_file_perms; +# Read /etc/shadow. +allow $1_su_t shadow_t:file r_file_perms; # Write to utmp. allow $1_su_t initrc_var_run_t:file rw_file_perms; diff --git a/usr/src/cmd/fmac/policy/domains/system/ftpd.te b/usr/src/cmd/fmac/policy/domains/system/ftpd.te --- a/usr/src/cmd/fmac/policy/domains/system/ftpd.te +++ b/usr/src/cmd/fmac/policy/domains/system/ftpd.te @@ -55,9 +55,8 @@ # Create pid files. file_type_auto_trans(ftpd_t, var_run_t, ftpd_var_run_t) -# Read /etc/auth/shadow. -allow ftpd_t etc_auth_t:dir r_dir_perms; -allow ftpd_t etc_auth_t:file r_file_perms; +# Read /etc/shadow. +allow ftpd_t shadow_t:file r_file_perms; # Append to /var/log/wtmp. allow ftpd_t wtmp_t:file append; diff --git a/usr/src/cmd/fmac/policy/domains/system/init.te b/usr/src/cmd/fmac/policy/domains/system/init.te --- a/usr/src/cmd/fmac/policy/domains/system/init.te +++ b/usr/src/cmd/fmac/policy/domains/system/init.te @@ -46,8 +46,7 @@ # Run /etc/rc.sysinit, /etc/rc, /etc/rc.local in the initrc_t domain. domain_auto_trans(init_t, initrc_exec_t, initrc_t) -# Run the shell or sulogin in the sysadm_t domain for single-user mode. -domain_auto_trans(init_t, shell_exec_t, sysadm_t) +# Run sulogin in the sysadm_t domain for single-user mode. domain_auto_trans(init_t, sulogin_exec_t, sysadm_t) # Run mingetty in its own domain. diff --git a/usr/src/cmd/fmac/policy/domains/system/login.te b/usr/src/cmd/fmac/policy/domains/system/login.te --- a/usr/src/cmd/fmac/policy/domains/system/login.te +++ b/usr/src/cmd/fmac/policy/domains/system/login.te @@ -75,9 +75,8 @@ allow local_login_t var_lock_t:dir rw_dir_perms; allow local_login_t var_lock_t:file create_file_perms; -# Read /etc/auth/shadow. -allow local_login_t etc_auth_t:dir r_dir_perms; -allow local_login_t etc_auth_t:file r_file_perms; +# Read /etc/shadow. +allow local_login_t shadow_t:file r_file_perms; # Search for mail spool file. allow local_login_t mail_spool_t:dir r_dir_perms; @@ -123,9 +122,8 @@ # Write to /var/log/lastlog. allow remote_login_t var_log_t:file rw_file_perms; -# Read /etc/auth/shadow. -allow remote_login_t etc_auth_t:dir r_dir_perms; -allow remote_login_t etc_auth_t:file r_file_perms; +# Read /etc/shadow. +allow remote_login_t shadow_t:file r_file_perms; # Search for mail spool file. allow remote_login_t mail_spool_t:dir r_dir_perms; diff --git a/usr/src/cmd/fmac/policy/domains/system/rlogind.te b/usr/src/cmd/fmac/policy/domains/system/rlogind.te --- a/usr/src/cmd/fmac/policy/domains/system/rlogind.te +++ b/usr/src/cmd/fmac/policy/domains/system/rlogind.te @@ -64,7 +64,6 @@ # Modify /var/log/wtmp. allow rlogind_t wtmp_t:file rw_file_perms; -# Read /etc/auth/shadow. -allow rlogind_t etc_auth_t:dir r_dir_perms; -allow rlogind_t etc_auth_t:file r_file_perms; +# Read /etc/shadow. +allow rlogind_t shadow_t:file r_file_perms; diff --git a/usr/src/cmd/fmac/policy/domains/system/rshd.te b/usr/src/cmd/fmac/policy/domains/system/rshd.te --- a/usr/src/cmd/fmac/policy/domains/system/rshd.te +++ b/usr/src/cmd/fmac/policy/domains/system/rshd.te @@ -44,18 +44,10 @@ can_network(rshd_t) # Run shells in user_t. -# Commented out - modified rshd removed from distribution for now. -#domain_auto_trans(rshd_t, shell_exec_t, user_t) +domain_auto_trans(rshd_t, shell_exec_t, user_t) # Send SIGCHLD to inetd on death. allow rshd_t inetd_t:process sigchld; # Allow socket ioctls not handled by other, more specific permissions. allow rshd_t kernel_t:system net_io_control; - -# in.rshd likes to search /etc/auth and read & getattr /etc/auth/shadow. -# in.rshd will operate correctly without these (dangerous) permissions, -# so the rshd_t domain does not provide them. We tell the avc not to -# log failures for these permissions. -auditdeny rshd_t etc_auth_t:dir ~search; -auditdeny rshd_t etc_auth_t:file ~{read getattr}; diff --git a/usr/src/cmd/fmac/policy/domains/system/sshd.te b/usr/src/cmd/fmac/policy/domains/system/sshd.te --- a/usr/src/cmd/fmac/policy/domains/system/sshd.te +++ b/usr/src/cmd/fmac/policy/domains/system/sshd.te @@ -33,8 +33,7 @@ # sshd_exec_t is the type of the sshd executable. # sshd_key_t is the type of the ssh private key files # -type sshd_t, domain, privlog; -type sshd_login_t, domain, privuser, privrole, privlog, auth, privowner; +type sshd_t, domain, privuser, privrole, privlog, auth; type sshd_exec_t, file_type, exec_type; type sshd_key_t, file_type; @@ -46,9 +45,6 @@ # Can create pty's can_create_pty(sshd) - -# Execute Login -domain_auto_trans(sshd_t, login_exec_t, sshd_login_t) # Fetch shell attributes allow sshd_t shell_exec_t:file { getattr }; @@ -72,46 +68,15 @@ # Append to wtmp allow sshd_t wtmp_t:file append; +# Run shells in user_t by default +domain_auto_trans(sshd_t, shell_exec_t, user_t) -################################# -# -# Rules for the sshd_login_t domain -# -# sshd_login_t is the domain of a login process -# spawned by sshd +# Read /etc/shadow +allow sshd_t shadow_t:file r_file_perms; -# Use capabilities -allow sshd_login_t self:capability { setuid setgid chown fowner fsetid net_bind_service sys_tty_config dac_override }; - -# Use the network -can_network(sshd_login_t) - -# Run shells in user_t by default -domain_auto_trans(sshd_login_t, shell_exec_t, user_t) - -# Use the pty created by sshd -allow sshd_login_t sshd_devpts_t:chr_file rw_file_perms; - -# Write to /var/run/utmp -allow sshd_login_t initrc_var_run_t:file rw_file_perms; - -# Write to /var/log/wtmp -allow sshd_login_t wtmp_t:file rw_file_perms; - -# Write to /var/log/lastlog -allow sshd_login_t var_log_t:file rw_file_perms; - -# Read /etc/auth/shadow -allow sshd_login_t etc_auth_t:dir r_dir_perms; -allow sshd_login_t etc_auth_t:file r_file_perms; - -# Search for mail spool file -allow sshd_login_t mail_spool_t:dir r_dir_perms; -allow sshd_login_t mail_spool_t:file getattr; - -# Relabel ptys created by sshd -allow sshd_login_t sshd_devpts_t:chr_file { relabelfrom relabelto }; -allow sshd_login_t user_devpts_t:chr_file { relabelto relabelfrom getattr }; +# Relabel ptys. +allow sshd_t sshd_devpts_t:chr_file { relabelfrom relabelto }; +allow sshd_t user_devpts_t:chr_file { relabelto relabelfrom getattr }; allow sshd_devpts_t user_devpts_t:chr_file transition; allow user_devpts_t sshd_devpts_t:chr_file transition; diff --git a/usr/src/cmd/fmac/policy/file_contexts b/usr/src/cmd/fmac/policy/file_contexts --- a/usr/src/cmd/fmac/policy/file_contexts +++ b/usr/src/cmd/fmac/policy/file_contexts @@ -69,49 +69,25 @@ # / system_u:object_r:root_t -# -# The policy configuration and its sources. -# -/etc/security/fmac/ss_policy system_u:object_r:policy_config_t - # # The superuser home directory. # -/root(|/.*) system_u:object_r:sysadm_home_t -/root/\.netscape(|/.*) system_u:object_r:sysadm_netscape_rw_t -/root/\.mime\.types system_u:object_r:sysadm_netscape_rw_t -/root/\.mailcap system_u:object_r:sysadm_netscape_rw_t - +/root(/.*)? system_u:object_r:sysadm_home_t # # Other user home directories. # -/home(|/.*) system_u:object_r:user_home_t -/home/.*/\.netscape(|/.*) system_u:object_r:user_netscape_rw_t -/home/.*/\.mime\.types system_u:object_r:user_netscape_rw_t -/home/.*/\.mailcap system_u:object_r:user_netscape_rw_t - -# -# /bin -# -/bin(|/.*) system_u:object_r:bin_t -/bin/login system_u:object_r:login_exec_t -/bin/tcsh system_u:object_r:shell_exec_t -/bin/bash system_u:object_r:shell_exec_t -/bin/ash system_u:object_r:shell_exec_t -/bin/su system_u:object_r:su_exec_t -/bin/ls system_u:object_r:ls_exec_t +/home(/.*)? system_u:object_r:user_home_t # # /boot # -/boot(|/.*) system_u:object_r:boot_t -/boot/kernel.h system_u:object_r:boot_runtime_t +/boot(/.*)? system_u:object_r:boot_t # -# /dev +# /dev # -/dev(|/.*) system_u:object_r:device_t +/dev(/.*)? system_u:object_r:device_t /dev/null system_u:object_r:null_device_t /dev/zero system_u:object_r:zero_device_t /dev/console system_u:object_r:console_device_t @@ -142,238 +118,141 @@ # # /etc # -/etc(|/.*) system_u:object_r:etc_t -/etc/rc.d/rc system_u:object_r:initrc_exec_t -/etc/rc.d/rc.sysinit system_u:object_r:initrc_exec_t -/etc/rc.d/rc.local system_u:object_r:initrc_exec_t -/etc/auth(|/.*) system_u:object_r:etc_auth_t +/etc(/.*)? system_u:object_r:etc_t +/etc/shadow system_u:object_r:shadow_t +/etc/security/fmac/ss_policy system_u:object_r:policy_config_t /etc/aliases system_u:object_r:etc_aliases_t -/etc/aliases.db system_u:object_r:etc_aliases_t -/etc/mail(|/.*) system_u:object_r:etc_mail_t -/etc/conf.modules system_u:object_r:modules_conf_t -/etc/HOSTNAME system_u:object_r:etc_runtime_t -/etc/ioctl.save system_u:object_r:etc_runtime_t -/etc/mtab system_u:object_r:etc_runtime_t -/etc/issue system_u:object_r:etc_runtime_t -/etc/issue.net system_u:object_r:etc_runtime_t -/etc/crontab system_u:object_r:system_crond_script_t -/etc/cron.d(|/.*) system_u:object_r:system_crond_script_t -/etc/security/cron_context.* system_u:object_r:cron_context_t -/etc/ssh_host_key system_u:object_r:sshd_key_t -/etc/ssh_random_seed system_u:object_r:sshd_key_t +/etc/mail(/.*)? system_u:object_r:etc_mail_t +/etc/mail/aliases system_u:object_r:etc_aliases_t +/etc/mail/aliases.db system_u:object_r:etc_aliases_t +/etc/cron.d(/.*)? system_u:object_r:system_crond_script_t +/etc/ssh/ssh_host_dsa_key system_u:object_r:sshd_key_t +/etc/ssh/ssh_host_rsa_key system_u:object_r:sshd_key_t # # /lib # -/lib(|/.*) system_u:object_r:lib_t +/lib(/.*)? system_u:object_r:lib_t +/lib/svc/bin/svc.startd system_u:object_r:initrc_exec_t +/lib/svc/bin/svc.configd system_u:object_r:initrc_exec_t /lib/ld.*\.so.* system_u:object_r:ld_so_t /lib/lib.*\.so.* system_u:object_r:shlib_t -/lib/security/.*\.so.* system_u:object_r:shlib_t -/lib/modules(|/.*) system_u:object_r:modules_object_t -/lib/modules/[^/]*/modules\.dep system_u:object_r:modules_dep_t # # /sbin # -/sbin(|/.*) system_u:object_r:sbin_t +/sbin(/.*)? system_u:object_r:sbin_t +/sbin/sh system_u:object_r:shell_exec_t /sbin/ifconfig system_u:object_r:ifconfig_exec_t -/sbin/depmod system_u:object_r:depmod_exec_t -/sbin/modprobe system_u:object_r:modprobe_exec_t -/sbin/insmod system_u:object_r:insmod_exec_t -/sbin/insmod.static system_u:object_r:insmod_exec_t -/sbin/rmmod system_u:object_r:rmmod_exec_t -/sbin/rmmod.static system_u:object_r:rmmod_exec_t /sbin/init system_u:object_r:init_exec_t /sbin/sulogin system_u:object_r:sulogin_exec_t -/sbin/mingetty system_u:object_r:getty_exec_t -/sbin/getty system_u:object_r:getty_exec_t -/sbin/uugetty system_u:object_r:getty_exec_t -/sbin/syslogd system_u:object_r:syslogd_exec_t -/sbin/minilogd system_u:object_r:syslogd_exec_t -/sbin/klogd system_u:object_r:klogd_exec_t -/sbin/ypbind system_u:object_r:ypbind_exec_t -/sbin/portmap system_u:object_r:portmap_exec_t -/sbin/rpc\..* system_u:object_r:rpcd_exec_t -/sbin/cardmgr system_u:object_r:cardmgr_exec_t -/sbin/fsck system_u:object_r:fsadm_exec_t -/sbin/fsck\.ext2 system_u:object_r:fsadm_exec_t -/sbin/e2fsck system_u:object_r:fsadm_exec_t -/sbin/e2label system_u:object_r:fsadm_exec_t -/sbin/mkfs system_u:object_r:fsadm_exec_t -/sbin/mke2fs system_u:object_r:fsadm_exec_t -/sbin/mkfs.ext2 system_u:object_r:fsadm_exec_t -/sbin/mkswap system_u:object_r:fsadm_exec_t -/sbin/scsi_info system_u:object_r:fsadm_exec_t -/sbin/sfdisk system_u:object_r:fsadm_exec_t -/sbin/cfdisk system_u:object_r:fsadm_exec_t -/sbin/fdisk system_u:object_r:fsadm_exec_t -/sbin/tune2fs system_u:object_r:fsadm_exec_t -/sbin/dumpe2fs system_u:object_r:fsadm_exec_t -/sbin/swapon system_u:object_r:fsadm_exec_t -/sbin/pwdb_chkpwd system_u:object_r:chkpwd_exec_t # # /tmp # -/tmp(|/.*) system_u:object_r:tmp_t +/tmp(/.*)? system_u:object_r:tmp_t /tmp/orbit.* system_u:object_r:user_tmp_t -/tmp/.ICE-unix(|/.*) system_u:object_r:user_tmp_t -/tmp/.X11-unix(|/.*) system_u:object_r:user_xserver_tmp_t +/tmp/.ICE-unix(/.*)? system_u:object_r:user_tmp_t +/tmp/.X11-unix(/.*)? system_u:object_r:user_xserver_tmp_t /tmp/.X0-lock system_u:object_r:user_xserver_tmp_t -/tmp/.font-unix(|/.*) system_u:object_r:xfs_tmp_t +/tmp/.font-unix(/.*)? system_u:object_r:xfs_tmp_t # # /usr # -/usr(|/.*) system_u:object_r:usr_t -/usr/etc(|/.*) system_u:object_r:etc_t -/usr/libexec(|/.*) system_u:object_r:lib_t -/usr/src(|/.*) system_u:object_r:src_t -/usr/tmp(|/.*) system_u:object_r:tmp_t -/usr/man(|/.*) system_u:object_r:man_t +/usr(/.*)? system_u:object_r:usr_t +/usr/src(/.*)? system_u:object_r:src_t +/usr/tmp(/.*)? system_u:object_r:tmp_t +/usr/share/man(/.*)? system_u:object_r:man_t # # /usr/bin # -/usr/bin(|/.*) system_u:object_r:bin_t +/usr/bin(/.*)? system_u:object_r:bin_t +/usr/bin/login system_u:object_r:login_exec_t +/usr/bin/csh system_u:object_r:shell_exec_t +/usr/bin/tcsh system_u:object_r:shell_exec_t +/usr/bin/bash system_u:object_r:shell_exec_t +/usr/bin/ksh system_u:object_r:shell_exec_t +/usr/bin/zsh system_u:object_r:shell_exec_t +/usr/bin/su system_u:object_r:su_exec_t +/usr/bin/ls system_u:object_r:ls_exec_t /usr/bin/lpr system_u:object_r:lpr_exec_t /usr/bin/lpq system_u:object_r:lpr_exec_t /usr/bin/lprm system_u:object_r:lpr_exec_t -/usr/bin/makemap system_u:object_r:sbin_t -/usr/bin/netscape system_u:object_r:netscape_exec_t /usr/bin/crontab system_u:object_r:crontab_exec_t +/usr/bin/passwd system_u:object_r:passwd_exec_t # # /usr/lib # -/usr/lib(|/.*) system_u:object_r:lib_t +/usr/lib(/.*)? system_u:object_r:lib_t +/usr/lib/ssh/sshd system_u:object_r:sshd_exec_t +/usr/lib/saf/ttymon system_u:object_r:getty_exec_t /usr/lib/lib.*\.so.* system_u:object_r:shlib_t -/usr/lib/perl5/man(|/.*) system_u:object_r:man_t - -# -# /usr/local -# -/usr/local/etc(|/.*) system_u:object_r:etc_t -/usr/local/etc/ssh_host_key system_u:object_r:sshd_key_t -/usr/local/etc/ssh_host_dsa_key system_u:object_r:sshd_key_t -/usr/local/src(|/.*) system_u:object_r:src_t -/usr/local/sbin(|/.*) system_u:object_r:sbin_t -/usr/local/sbin/sshd system_u:object_r:sshd_exec_t -/usr/local/man(|/.*) system_u:object_r:man_t - -# -# /usr/local/bin -# -/usr/local/bin(|/.*) system_u:object_r:bin_t -/usr/local/bin/tcsh system_u:object_r:shell_exec_t - -# -# /usr/local/lib -# -/usr/local/lib(|/.*) system_u:object_r:lib_t -/usr/local/lib/lib.*\.so.* system_u:object_r:shlib_t +/usr/lib/inet/inetd system_u:object_r:inetd_exec_t +/usr/lib/inet/in\..*d system_u:object_r:inetd_child_exec_t +/usr/lib/sendmail system_u:object_r:sendmail_exec_t # # /usr/sbin # -/usr/sbin(|/.*) system_u:object_r:sbin_t +/usr/sbin(/.*)? system_u:object_r:sbin_t +/usr/sbin/fsck system_u:object_r:fsadm_exec_t +/usr/sbin/mkfs system_u:object_r:fsadm_exec_t +/usr/sbin/fdisk system_u:object_r:fsadm_exec_t /usr/sbin/syslogd system_u:object_r:syslogd_exec_t -/usr/sbin/klogd system_u:object_r:klogd_exec_t -/usr/sbin/apmd system_u:object_r:apmd_exec_t -/usr/sbin/crond system_u:object_r:crond_exec_t -/usr/sbin/atd system_u:object_r:atd_exec_t -/usr/sbin/lpd system_u:object_r:lpd_exec_t -/usr/sbin/inetd system_u:object_r:inetd_exec_t -/usr/sbin/tcpd system_u:object_r:tcpd_exec_t -/usr/sbin/identd system_u:object_r:inetd_child_exec_t +/usr/sbin/cron system_u:object_r:crond_exec_t /usr/sbin/in\..*d system_u:object_r:inetd_child_exec_t /usr/sbin/in.rlogind system_u:object_r:rlogind_exec_t /usr/sbin/in.telnetd system_u:object_r:rlogind_exec_t /usr/sbin/in.rshd system_u:object_r:rshd_exec_t /usr/sbin/in.ftpd system_u:object_r:ftpd_exec_t -/usr/sbin/in.ftpd-stage2 system_u:object_r:ftpd_stage2_exec_t -/usr/sbin/sendmail system_u:object_r:sendmail_exec_t +/usr/sbin/rpcbind system_u:object_r:portmap_exec_t /usr/sbin/rpc\..* system_u:object_r:rpcd_exec_t -/usr/sbin/gpm system_u:object_r:gpm_exec_t /usr/sbin/makemap system_u:object_r:sbin_t -/usr/sbin/utempter system_u:object_r:utempter_exec_t -/usr/sbin/gnome-pty-helper system_u:object_r:gph_exec_t -/usr/sbin/logrotate system_u:object_r:logrotate_exec_t # -# /usr/X11R6/bin +# /usr/sadm # -/usr/X11R6/bin(|/.*) system_u:object_r:bin_t -/usr/X11R6/bin/xfs system_u:object_r:xfs_exec_t -/usr/X11R6/bin/Xwrapper system_u:object_r:xserver_exec_t +/usr/sadm/bin(/.*)? system_u:object_r:bin_t +/usr/sadm/admin/bin(/.*)? system_u:object_r:bin_t +/usr/sadm/lib(/.*)? system_u:object_r:lib_t # -# /usr/X11R6/lib +# /usr/X11 # -/usr/X11R6/lib(|/.*) system_u:object_r:lib_t -/usr/X11R6/lib/lib.*\.so.* system_u:object_r:shlib_t - -# -# /usr/X11R6/man -# -/usr/X11R6/man(|/.*) system_u:object_r:man_t - -# -# /usr/flask -# -/usr/flask/bin(|/.*) system_u:object_r:bin_t -/usr/flask/sbin(|/.*) system_u:object_r:bin_t -/usr/flask/libexec(|/.*) system_u:object_r:lib_t -/usr/flask/bin/spasswd system_u:object_r:passwd_exec_t -/usr/flask/bin/schsh system_u:object_r:passwd_exec_t -/usr/flask/bin/schfn system_u:object_r:passwd_exec_t -/usr/flask/bin/newrole system_u:object_r:newrole_exec_t +/usr/X11/bin(/.*)? system_u:object_r:bin_t +/usr/X11/bin/Xorg system_u:object_r:xserver_exec_t +/usr/X11/lib(/.*)? system_u:object_r:lib_t +/usr/X11/lib/lib.*\.so.* system_u:object_r:shlib_t +/usr/X11/share/man(/.*)? system_u:object_r:man_t # # /var # -/var(|/.*) system_u:object_r:var_t -/var/catman(|/.*) system_u:object_r:catman_t -/var/yp(|/.*) system_u:object_r:var_yp_t -/var/lib(|/.*) system_u:object_r:var_lib_t -/var/lock(|/.*) system_u:object_r:var_lock_t -/var/tmp(|/.*) system_u:object_r:tmp_t +/var(/.*)? system_u:object_r:var_t +/var/yp(/.*)? system_u:object_r:var_yp_t +/var/lib(/.*)? system_u:object_r:var_lib_t +/var/tmp(/.*)? system_u:object_r:tmp_t # # /var/run # -/var/run(|/.*) system_u:object_r:var_run_t -/var/run/utmp system_u:object_r:initrc_var_run_t -/var/run/runlevel.dir system_u:object_r:initrc_var_run_t -/var/run/random-seed system_u:object_r:initrc_var_run_t +/var/run(/.*)? system_u:object_r:var_run_t /var/run/.*\.*pid <> # # /var/spool # -/var/spool(|/.*) system_u:object_r:var_spool_t -/var/spool/at(|/.*) system_u:object_r:at_spool_t -/var/spool/cron(|/.*) system_u:object_r:cron_spool_t -/var/spool/lpd(|/.*) system_u:object_r:lpd_spool_t -/var/spool/mail(|/.*) system_u:object_r:mail_spool_t -/var/spool/mqueue(|/.*) system_u:object_r:mqueue_spool_t +/var/spool(/.*)? system_u:object_r:var_spool_t +/var/spool/cron(/.*)? system_u:object_r:cron_spool_t +/var/spool/lp(/.*)? system_u:object_r:lpd_spool_t +/var/mail(/.*)? system_u:object_r:mail_spool_t +/var/spool/mqueue(/.*)? system_u:object_r:mqueue_spool_t # # /var/log # -/var/log(|/.*) system_u:object_r:var_log_t -/var/log/wtmp system_u:object_r:wtmp_t -/var/log/sendmail.st system_u:object_r:sendmail_var_log_t -/var/log/cron system_u:object_r:cron_log_t - -# -# Persistent label mappings. -# -.*/\.\.\.security(|/.*) system_u:object_r:file_labels_t - -# -# Lost and found directories. -# -.*/lost\+found(|/.*) system_u:object_r:lost_found_t - +/var/log(/.*)? system_u:object_r:var_log_t diff --git a/usr/src/cmd/fmac/policy/rbac b/usr/src/cmd/fmac/policy/rbac --- a/usr/src/cmd/fmac/policy/rbac +++ b/usr/src/cmd/fmac/policy/rbac @@ -77,7 +77,6 @@ xfs_t local_login_t remote_login_t - sshd_login_t depmod_t modprobe_t insmod_t @@ -87,6 +86,7 @@ logrotate_t sysadm_t # single-user mode user_mail_t # mail sent by crond + user_t }; # diff --git a/usr/src/cmd/fmac/policy/types/file.te b/usr/src/cmd/fmac/policy/types/file.te --- a/usr/src/cmd/fmac/policy/types/file.te +++ b/usr/src/cmd/fmac/policy/types/file.te @@ -97,10 +97,9 @@ type etc_runtime_t, file_type, sysadmfile; # -# etc_auth_t is the type of /etc/auth, -# which contains the shadow password file. +# shadow_t is the type of /etc/shadow. # -type etc_auth_t, file_type, sysadmfile; +type shadow_t, file_type, sysadmfile; # # etc_aliases_t is the type of the aliases database. -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Wed Sep 3 12:11:41 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Wed, 03 Sep 2008 12:11:41 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48BEE16D.4010403@sun.com> Stephen, I have a general question about automatic process context transitions, not about this patch, in particular. When specifying policy rules for such transitions, is the normal behavior that the process's new domain type depends on the new executable's type, but that the process retains its MLS label? Is it possible to express either behavior (retain MLS label or transition to MLS label of the executable)? --Glenn Stephen Smalley wrote: > This patch adds basic security context transition support to FMAC. It > depends on the prior patch for file security context support in order to > obtain the security context for executables. With this patch applied > and a suitably labeled filesystem and policy, processes will > automatically transition into a suitable security context when they > execute a program based on the program file's security context, and a > process may explicitly transition to a given security context if > authorized. This patch implements the execute_no_trans, transition, and > entrypoint permission checks. The execute check will be handled by a > separate change to fop_access. Other checks applied upon security > context transitions in SELinux such as inheritance of open file > descriptors and other state will be introduced to FMAC by subsequent > patches. > > The checks applied here are: > - If not transitioning, may the process execute the file without > transitioning to a new security context? > - If transitioning, may the process transition to the new security > context and may the new security context be entered via the program? > > Webrev available at: http://cr.opensolaris.org/~sds/exec/ > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -308,3 +308,46 @@ > vp->v_secid = secid; > mutex_exit(&(vp->v_lock)); > } > + > +int > +fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp) > +{ > + security_id_t prev_secid, secid; > + int error; > + > + if (!fmac_enabled) > + return (0); > + > + prev_secid = crgetsecid(cr); > + secid = crgetexecsecid(cr); > + if (!secid) { > + error = security_transition_sid(prev_secid, vp->v_secid, > + SECCLASS_PROCESS, &secid); > + if (error) > + return (error); > + } > + > + if (prev_secid == secid) { > + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, > + FILE__EXECUTE_NO_TRANS); > + if (error) > + return (error); > + *setsecid = 0; > + return (0); > + } > + > + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, > + PROCESS__TRANSITION); > + if (error) > + return (error); > + > + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, > + FILE__ENTRYPOINT); > + if (error) > + return (error); > + *setsecid = 1; > + *prev_secidp = prev_secid; > + *secidp = secid; > + return (0); > +} > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > --- a/usr/src/uts/common/os/exec.c > +++ b/usr/src/uts/common/os/exec.c > @@ -68,6 +68,7 @@ > #include > #include > #include > +#include > > #include > > @@ -522,6 +523,8 @@ > int suidflags = 0; > ssize_t resid; > uid_t uid, gid; > + security_id_t prev_secid, secid; > + int setsecid = 0; > struct vattr vattr; > char magbuf[MAGIC_BYTES]; > int setid; > @@ -562,10 +565,25 @@ > if ((eswp = findexec_by_hdr(magbuf)) == NULL) > goto bad; > > - if (level == 0 && > - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { > + if (level == 0) { > + privflags = execsetid(vp, &vattr, &uid, &gid); > > + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > + if (error) > + goto bad; > + > + if (setsecid) > + privflags |= PRIV_SETUGID; > + } > + > + if (level == 0 && privflags != 0) { > newcred = cred = crdup(cred); > + > + if (setsecid) { > + cred->cr_prev_secid = prev_secid; > + cred->cr_secid = secid; > + cred->cr_exec_secid = SECSID_NULL; > + } > > /* If we can, drop the PA bit */ > if ((privflags & PRIV_RESET) != 0) > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -89,6 +89,8 @@ > int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > security_id_t *); > void fmac_vnode_post_create(vnode_t *, security_id_t); > +int fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp); > #endif /* _KERNEL */ > > #ifdef __cplusplus > > > > > > From sds at tycho.nsa.gov Wed Sep 3 12:24:03 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 03 Sep 2008 15:24:03 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48BEE16D.4010403@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEE16D.4010403@sun.com> Message-ID: <1220469843.6034.178.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 12:11 -0700, Glenn Faden wrote: > Stephen, > > I have a general question about automatic process context transitions, > not about this patch, in particular. When specifying policy rules for > such transitions, is the normal behavior that the process's new domain > type depends on the new executable's type, but that the process retains > its MLS label? Is it possible to express either behavior (retain MLS > label or transition to MLS label of the executable)? They are primarily used for role and/or domain transitions only, with the MLS label being left unmodified. SELinux later introduced "range transitions" whereby the MLS level/range of a process could also change upon program execution, but that is also based on the executable's type rather than its MLS level - to enable the MLS level/range to change upon execution of a multi-level trusted application. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Wed Sep 3 12:34:27 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Wed, 03 Sep 2008 13:34:27 -0600 Subject: [fmac-discuss] [RFC][PATCH] Prototype file security context support In-Reply-To: <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> References: <488CD182.5060902@Sun.COM> <1217268420.20373.88.camel@moss-spartans.epoch.ncsc.mil> <488E140F.5000907@Sun.COM> <1217272865.20373.121.camel@moss-spartans.epoch.ncsc.mil> <488E1DF1.8060508@Sun.COM> <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48BEE6C3.8080803@Sun.COM> Stephen Smalley wrote: > Hi, > > Based on our earlier exchange about FMAC support in the filesystem, I've > prototyped file security context support via a new "secctx" system > attribute. This patch isn't intended for production use but is just a > prototype to investigate what is required, to help identify issues with > this approach, and to enable us to make progress on developing other > parts of FMAC that depend on file security contexts. > > In the kernel, this patch adds support for a "secctx" system attribute, > fetches this attribute on the lookup path and maps it to an in-core > vnode secid (a non-persistent handle to a context) for internal use by > FMAC, and attempts to compute and set this attribute on the create path > (this last part doesn't appear to work though - see below). In > userland, this patch implements getfilecon() and setfilecon() libc > interfaces and corresponding utilities for getting and setting the file > security context. With the patch applied, I can successfully set file > contexts via setfilecon (e.g. setfilecon > system_u:object_r:shadow_t /etc/shadow) and get them via getfilecon > (e.g. getfilecon /etc/shadow) on a zfs filesystem. > > The limitations of this patch include: > 1) Storage of the secctx is presently limited to 56 bytes since it is > stored directly in the bonus buffer and is exclusive of the av > scanstamp. I expect that this limitation can be addressed by storing > the secctx externally as with the external acl support and/or by using > the more extensible mechanism you are developing for system attributes. > We also need a more flexible way of passing it internally as a > variable-length string in the xoptattr rather than as a fixed size > buffer. > This seems reasonable until I finish the rework of the system attribute support in ZFS. > 2) It appears that we can only set attributes on regular files and > directories, whereas we need security contexts on all file types. As I > recall, Linux also had limitations in what file types supported > attributes originally but these limitations were removed by the time we > migrated SELinux to using Linux xattrs. Hopefully this limitation can > also be removed from Solaris. > We could support these easily on device files, but are you also wanting the context on symlinks? The link itself, not what it points to? > 3) Although the code seems to be successfully computing a secctx for new > files and setting up an xvattr to convey it to the filesystem create and > mkdir operations (see fmac_vnode_create as called by fop_create and > fop_mkdir) and we later see that xvattr in the subsequent > secpolicy_xvattr call, the attribute is not being set on the new files > by zfs. I'm not clear as to whether support for setting system > attribute at creation exists in zfs presently or if I have missed some > crucial step there. > This is most likely because the bonus buffer hasn't been resized to make space for the security context. In zfs_setattr() prior to setting the scanstamp attribute the bonus is resized to make room for the attribute. this bug should also exist if anybody ever tried to set the scanstamp during a create. Nobody currently does that. > I'd appreciate any comments you have on the above limitations or on the > code below. > I will take a look at all of your file system and libc related changes and get you some comments within the next day or two. > Webrev available at: http://cr.opensolaris.org/~sds/secctx/ -Mark From sds at tycho.nsa.gov Wed Sep 3 12:51:27 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 03 Sep 2008 15:51:27 -0400 Subject: [fmac-discuss] [RFC][PATCH] Prototype file security context support In-Reply-To: <48BEE6C3.8080803@Sun.COM> References: <488CD182.5060902@Sun.COM> <1217268420.20373.88.camel@moss-spartans.epoch.ncsc.mil> <488E140F.5000907@Sun.COM> <1217272865.20373.121.camel@moss-spartans.epoch.ncsc.mil> <488E1DF1.8060508@Sun.COM> <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> <48BEE6C3.8080803@Sun.COM> Message-ID: <1220471487.6034.187.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 13:34 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > 2) It appears that we can only set attributes on regular files and > > directories, whereas we need security contexts on all file types. As I > > recall, Linux also had limitations in what file types supported > > attributes originally but these limitations were removed by the time we > > migrated SELinux to using Linux xattrs. Hopefully this limitation can > > also be removed from Solaris. > > > > We could support these easily on device files, but are you also wanting > the context on symlinks? The link itself, not what it points to? Yes, the symlink itself, reflecting the security attributes of its creator, so that we can decide whether another process is allowed to read or follow it. > > 3) Although the code seems to be successfully computing a secctx for new > > files and setting up an xvattr to convey it to the filesystem create and > > mkdir operations (see fmac_vnode_create as called by fop_create and > > fop_mkdir) and we later see that xvattr in the subsequent > > secpolicy_xvattr call, the attribute is not being set on the new files > > by zfs. I'm not clear as to whether support for setting system > > attribute at creation exists in zfs presently or if I have missed some > > crucial step there. > > > > This is most likely because the bonus buffer hasn't been resized to make > space for the security context. In zfs_setattr() prior to setting the > scanstamp attribute the bonus is resized to make room for the attribute. Ah, I see - I'll have to try resizing it in zfs_create()/mkdir(). > this bug should also exist if anybody ever tried to set the scanstamp > during a create. Nobody currently does that. > > > I'd appreciate any comments you have on the above limitations or on the > > code below. > > > > I will take a look at all of your file system and libc related changes > and get you some comments within the next day or two. Great, thanks. -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Wed Sep 3 13:20:15 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Wed, 03 Sep 2008 13:20:15 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48BEF17F.3030509@sun.com> Stephen, > + > +int > +fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp) > +{ > + security_id_t prev_secid, secid; > + int error; > + > + if (!fmac_enabled) > + return (0); > + > + prev_secid = crgetsecid(cr); > + secid = crgetexecsecid(cr); > + if (!secid) { > + error = security_transition_sid(prev_secid, vp->v_secid, > + SECCLASS_PROCESS, &secid); > + if (error) > + return (error); > + } > + > + if (prev_secid == secid) { > + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, > + FILE__EXECUTE_NO_TRANS); > + if (error) > + return (error); > + *setsecid = 0; > + return (0); > + } > + > + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, > + PROCESS__TRANSITION); > + if (error) > + return (error); > + > + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, > + FILE__ENTRYPOINT); > + if (error) > + return (error); > + *setsecid = 1; > + *prev_secidp = prev_secid; > + *secidp = secid; > + return (0); > +} > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > --- a/usr/src/uts/common/os/exec.c > +++ b/usr/src/uts/common/os/exec.c > @@ -68,6 +68,7 @@ > #include > #include > #include > +#include > > #include > > @@ -522,6 +523,8 @@ > int suidflags = 0; > ssize_t resid; > uid_t uid, gid; > + security_id_t prev_secid, secid; > + int setsecid = 0; > struct vattr vattr; > char magbuf[MAGIC_BYTES]; > int setid; > @@ -562,10 +565,25 @@ > if ((eswp = findexec_by_hdr(magbuf)) == NULL) > goto bad; > > - if (level == 0 && > - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { > + if (level == 0) { > + privflags = execsetid(vp, &vattr, &uid, &gid); > > + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > + if (error) > + goto bad; > + > + if (setsecid) > + privflags |= PRIV_SETUGID; > Why is it necessary to assert the privilege PRIV_SETUGID when the process is doing a domain transition? It seems that you are taking advantage of a side effect that a new process credential will be created during exec. However, it seems to me that it is unsafe to do it this way. If the process is lacking this privilege in its limit set, and should not be allowed to execute setuid or setgid binaries, asserting the privilege here will unintentionally bypass that restriction. --Glenn > + } > + > + if (level == 0 && privflags != 0) { > newcred = cred = crdup(cred); > + > + if (setsecid) { > + cred->cr_prev_secid = prev_secid; > + cred->cr_secid = secid; > + cred->cr_exec_secid = SECSID_NULL; > + } > > /* If we can, drop the PA bit */ > if ((privflags & PRIV_RESET) != 0) > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -89,6 +89,8 @@ > int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > security_id_t *); > void fmac_vnode_post_create(vnode_t *, security_id_t); > +int fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp); > #endif /* _KERNEL */ > > #ifdef __cplusplus > > > > > > From Glenn.Faden at Sun.COM Wed Sep 3 13:30:51 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Wed, 03 Sep 2008 13:30:51 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48BEF3FB.30607@sun.com> Stephen, Please change the declaration of setsecid from int to boolean_t and use the values B_TRUE and B_FALSE instead of 1 and 0. --Glenn Stephen Smalley wrote: > This patch adds basic security context transition support to FMAC. It > depends on the prior patch for file security context support in order to > obtain the security context for executables. With this patch applied > and a suitably labeled filesystem and policy, processes will > automatically transition into a suitable security context when they > execute a program based on the program file's security context, and a > process may explicitly transition to a given security context if > authorized. This patch implements the execute_no_trans, transition, and > entrypoint permission checks. The execute check will be handled by a > separate change to fop_access. Other checks applied upon security > context transitions in SELinux such as inheritance of open file > descriptors and other state will be introduced to FMAC by subsequent > patches. > > The checks applied here are: > - If not transitioning, may the process execute the file without > transitioning to a new security context? > - If transitioning, may the process transition to the new security > context and may the new security context be entered via the program? > > Webrev available at: http://cr.opensolaris.org/~sds/exec/ > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -308,3 +308,46 @@ > vp->v_secid = secid; > mutex_exit(&(vp->v_lock)); > } > + > +int > +fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp) > +{ > + security_id_t prev_secid, secid; > + int error; > + > + if (!fmac_enabled) > + return (0); > + > + prev_secid = crgetsecid(cr); > + secid = crgetexecsecid(cr); > + if (!secid) { > + error = security_transition_sid(prev_secid, vp->v_secid, > + SECCLASS_PROCESS, &secid); > + if (error) > + return (error); > + } > + > + if (prev_secid == secid) { > + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, > + FILE__EXECUTE_NO_TRANS); > + if (error) > + return (error); > + *setsecid = 0; > + return (0); > + } > + > + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, > + PROCESS__TRANSITION); > + if (error) > + return (error); > + > + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, > + FILE__ENTRYPOINT); > + if (error) > + return (error); > + *setsecid = 1; > + *prev_secidp = prev_secid; > + *secidp = secid; > + return (0); > +} > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > --- a/usr/src/uts/common/os/exec.c > +++ b/usr/src/uts/common/os/exec.c > @@ -68,6 +68,7 @@ > #include > #include > #include > +#include > > #include > > @@ -522,6 +523,8 @@ > int suidflags = 0; > ssize_t resid; > uid_t uid, gid; > + security_id_t prev_secid, secid; > + int setsecid = 0; > struct vattr vattr; > char magbuf[MAGIC_BYTES]; > int setid; > @@ -562,10 +565,25 @@ > if ((eswp = findexec_by_hdr(magbuf)) == NULL) > goto bad; > > - if (level == 0 && > - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { > + if (level == 0) { > + privflags = execsetid(vp, &vattr, &uid, &gid); > > + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > + if (error) > + goto bad; > + > + if (setsecid) > + privflags |= PRIV_SETUGID; > + } > + > + if (level == 0 && privflags != 0) { > newcred = cred = crdup(cred); > + > + if (setsecid) { > + cred->cr_prev_secid = prev_secid; > + cred->cr_secid = secid; > + cred->cr_exec_secid = SECSID_NULL; > + } > > /* If we can, drop the PA bit */ > if ((privflags & PRIV_RESET) != 0) > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -89,6 +89,8 @@ > int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > security_id_t *); > void fmac_vnode_post_create(vnode_t *, security_id_t); > +int fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp); > #endif /* _KERNEL */ > > #ifdef __cplusplus > > > > > > From sds at tycho.nsa.gov Wed Sep 3 13:54:37 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 03 Sep 2008 16:54:37 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48BEF17F.3030509@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> Message-ID: <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 13:20 -0700, Glenn Faden wrote: > Stephen, > > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > > --- a/usr/src/uts/common/os/exec.c > > +++ b/usr/src/uts/common/os/exec.c > > @@ -562,10 +565,25 @@ > > if ((eswp = findexec_by_hdr(magbuf)) == NULL) > > goto bad; > > > > - if (level == 0 && > > - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { > > + if (level == 0) { > > + privflags = execsetid(vp, &vattr, &uid, &gid); > > > > + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > > + if (error) > > + goto bad; > > + > > + if (setsecid) > > + privflags |= PRIV_SETUGID; > > > > Why is it necessary to assert the privilege PRIV_SETUGID when the > process is doing a domain transition? It seems that you are taking > advantage of a side effect that a new process credential will be created > during exec. However, it seems to me that it is unsafe to do it this > way. If the process is lacking this privilege in its limit set, and > should not be allowed to execute setuid or setgid binaries, asserting > the privilege here will unintentionally bypass that restriction. I found the interplay between the PRIV_* and the EXECSETID_* flags (and the setid and setidfl variables) to be rather obscure. What I want: - new credential creation, - update of the secid, - setting of the linker security flag (conditional on another check, not yet done here), - invalidation of /proc vnode if being traced Setting PRIV_SETUGID doesn't appear to actually change the uid/gid AFAICS - that seems to be PRIV_SETID instead. And even there it only appears to set the uid/gid to values as determined by execsetid() in the first place, with the degenerate case being the uid and gid equal their old values. I could introduce a new flag I suppose. -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Wed Sep 3 14:47:26 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Wed, 03 Sep 2008 14:47:26 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48BF05EE.4080908@sun.com> Stephen Smalley wrote: > On Wed, 2008-09-03 at 13:20 -0700, Glenn Faden wrote: > >> Stephen, >> >>> diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c >>> --- a/usr/src/uts/common/os/exec.c >>> +++ b/usr/src/uts/common/os/exec.c >>> @@ -562,10 +565,25 @@ >>> if ((eswp = findexec_by_hdr(magbuf)) == NULL) >>> goto bad; >>> >>> - if (level == 0 && >>> - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { >>> + if (level == 0) { >>> + privflags = execsetid(vp, &vattr, &uid, &gid); >>> >>> + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); >>> + if (error) >>> + goto bad; >>> + >>> + if (setsecid) >>> + privflags |= PRIV_SETUGID; >>> >>> >> Why is it necessary to assert the privilege PRIV_SETUGID when the >> process is doing a domain transition? It seems that you are taking >> advantage of a side effect that a new process credential will be created >> during exec. However, it seems to me that it is unsafe to do it this >> way. If the process is lacking this privilege in its limit set, and >> should not be allowed to execute setuid or setgid binaries, asserting >> the privilege here will unintentionally bypass that restriction. >> > > I found the interplay between the PRIV_* and the EXECSETID_* flags (and > the setid and setidfl variables) to be rather obscure. What I want: > - new credential creation, > - update of the secid, > - setting of the linker security flag (conditional on another check, not > yet done here), > - invalidation of /proc vnode if being traced > > Setting PRIV_SETUGID doesn't appear to actually change the uid/gid > AFAICS - that seems to be PRIV_SETID instead. And even there it only > appears to set the uid/gid to values as determined by execsetid() in the > first place, with the degenerate case being the uid and gid equal their > old values. > > I could introduce a new flag I suppose. > I've looked at this again, since I had misread PRIV_SETUGID as PRIV_SETID. Now I'm not sure if the vulnerability I mentioned actually exists. The flag usage is obscure, in part, because we originally intended to add forced privileges on executables, as was done in Trusted Solaris. This was postponed because we weren't ready to introduce the complexity of new security attributes for files. Since we are adding a new attribute for the FMAC security context, it seems to be the right time to implement forced privileges, as well. This is especially timely since the Linux community is adding a similar feature which they call POSIX file capabilities (http://www.ibm.com/developerworks/library/l-posixcap.html ). I've copied Casper Dik who introduced these flags in Solaris 10, to verify that it is safe to set PRIV_SETUGID for secid transitions. --Glenn From Cathleen.Reiher at Sun.COM Wed Sep 3 17:17:06 2008 From: Cathleen.Reiher at Sun.COM (Cathleen Reiher) Date: Wed, 03 Sep 2008 17:17:06 -0700 Subject: [fmac-discuss] REVIEW: FMAC man pages Message-ID: Hi all, I've created a new man page to describe the new getfilecon and setfilecon utilities that Stephen Smalley introduced with his 9/3/08 patches. I've also updated the pcon(1M), setfiles(1M), and fmac(5) man pages to refer to these new commands. The updated man pages are posted on the project page: http://www.opensolaris.org/os/project/fmac/docs/ Please send your feedback to the discussion list. Thanks for your review. Cathleen. From sds at tycho.nsa.gov Thu Sep 4 04:57:04 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 04 Sep 2008 07:57:04 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48BEF3FB.30607@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF3FB.30607@sun.com> Message-ID: <1220529424.17197.6.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 13:30 -0700, Glenn Faden wrote: > Stephen, > > Please change the declaration of setsecid from int to boolean_t and use > the values B_TRUE and B_FALSE instead of 1 and 0. Sure, I'll include that change in the next revision of the patch. > > --Glenn > > Stephen Smalley wrote: > > This patch adds basic security context transition support to FMAC. It > > depends on the prior patch for file security context support in order to > > obtain the security context for executables. With this patch applied > > and a suitably labeled filesystem and policy, processes will > > automatically transition into a suitable security context when they > > execute a program based on the program file's security context, and a > > process may explicitly transition to a given security context if > > authorized. This patch implements the execute_no_trans, transition, and > > entrypoint permission checks. The execute check will be handled by a > > separate change to fop_access. Other checks applied upon security > > context transitions in SELinux such as inheritance of open file > > descriptors and other state will be introduced to FMAC by subsequent > > patches. > > > > The checks applied here are: > > - If not transitioning, may the process execute the file without > > transitioning to a new security context? > > - If transitioning, may the process transition to the new security > > context and may the new security context be entered via the program? > > > > Webrev available at: http://cr.opensolaris.org/~sds/exec/ > > > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > > --- a/usr/src/uts/common/fmac/fmac.c > > +++ b/usr/src/uts/common/fmac/fmac.c > > @@ -308,3 +308,46 @@ > > vp->v_secid = secid; > > mutex_exit(&(vp->v_lock)); > > } > > + > > +int > > +fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > > + security_id_t *prev_secidp, security_id_t *secidp) > > +{ > > + security_id_t prev_secid, secid; > > + int error; > > + > > + if (!fmac_enabled) > > + return (0); > > + > > + prev_secid = crgetsecid(cr); > > + secid = crgetexecsecid(cr); > > + if (!secid) { > > + error = security_transition_sid(prev_secid, vp->v_secid, > > + SECCLASS_PROCESS, &secid); > > + if (error) > > + return (error); > > + } > > + > > + if (prev_secid == secid) { > > + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, > > + FILE__EXECUTE_NO_TRANS); > > + if (error) > > + return (error); > > + *setsecid = 0; > > + return (0); > > + } > > + > > + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, > > + PROCESS__TRANSITION); > > + if (error) > > + return (error); > > + > > + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, > > + FILE__ENTRYPOINT); > > + if (error) > > + return (error); > > + *setsecid = 1; > > + *prev_secidp = prev_secid; > > + *secidp = secid; > > + return (0); > > +} > > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > > --- a/usr/src/uts/common/os/exec.c > > +++ b/usr/src/uts/common/os/exec.c > > @@ -68,6 +68,7 @@ > > #include > > #include > > #include > > +#include > > > > #include > > > > @@ -522,6 +523,8 @@ > > int suidflags = 0; > > ssize_t resid; > > uid_t uid, gid; > > + security_id_t prev_secid, secid; > > + int setsecid = 0; > > struct vattr vattr; > > char magbuf[MAGIC_BYTES]; > > int setid; > > @@ -562,10 +565,25 @@ > > if ((eswp = findexec_by_hdr(magbuf)) == NULL) > > goto bad; > > > > - if (level == 0 && > > - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { > > + if (level == 0) { > > + privflags = execsetid(vp, &vattr, &uid, &gid); > > > > + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > > + if (error) > > + goto bad; > > + > > + if (setsecid) > > + privflags |= PRIV_SETUGID; > > + } > > + > > + if (level == 0 && privflags != 0) { > > newcred = cred = crdup(cred); > > + > > + if (setsecid) { > > + cred->cr_prev_secid = prev_secid; > > + cred->cr_secid = secid; > > + cred->cr_exec_secid = SECSID_NULL; > > + } > > > > /* If we can, drop the PA bit */ > > if ((privflags & PRIV_RESET) != 0) > > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > > --- a/usr/src/uts/common/sys/fmac/fmac.h > > +++ b/usr/src/uts/common/sys/fmac/fmac.h > > @@ -89,6 +89,8 @@ > > int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > > security_id_t *); > > void fmac_vnode_post_create(vnode_t *, security_id_t); > > +int fmac_exec(cred_t *cr, vnode_t *vp, int *setsecid, > > + security_id_t *prev_secidp, security_id_t *secidp); > > #endif /* _KERNEL */ > > > > #ifdef __cplusplus > > > > > > > > > > > > -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Sep 4 05:10:16 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 04 Sep 2008 08:10:16 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48BF05EE.4080908@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> Message-ID: <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 14:47 -0700, Glenn Faden wrote: > Stephen Smalley wrote: > > On Wed, 2008-09-03 at 13:20 -0700, Glenn Faden wrote: > > > >> Stephen, > >> > >>> diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > >>> --- a/usr/src/uts/common/os/exec.c > >>> +++ b/usr/src/uts/common/os/exec.c > >>> @@ -562,10 +565,25 @@ > >>> if ((eswp = findexec_by_hdr(magbuf)) == NULL) > >>> goto bad; > >>> > >>> - if (level == 0 && > >>> - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { > >>> + if (level == 0) { > >>> + privflags = execsetid(vp, &vattr, &uid, &gid); > >>> > >>> + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > >>> + if (error) > >>> + goto bad; > >>> + > >>> + if (setsecid) > >>> + privflags |= PRIV_SETUGID; > >>> > >>> > >> Why is it necessary to assert the privilege PRIV_SETUGID when the > >> process is doing a domain transition? It seems that you are taking > >> advantage of a side effect that a new process credential will be created > >> during exec. However, it seems to me that it is unsafe to do it this > >> way. If the process is lacking this privilege in its limit set, and > >> should not be allowed to execute setuid or setgid binaries, asserting > >> the privilege here will unintentionally bypass that restriction. > >> > > > > I found the interplay between the PRIV_* and the EXECSETID_* flags (and > > the setid and setidfl variables) to be rather obscure. What I want: > > - new credential creation, > > - update of the secid, > > - setting of the linker security flag (conditional on another check, not > > yet done here), > > - invalidation of /proc vnode if being traced > > > > Setting PRIV_SETUGID doesn't appear to actually change the uid/gid > > AFAICS - that seems to be PRIV_SETID instead. And even there it only > > appears to set the uid/gid to values as determined by execsetid() in the > > first place, with the degenerate case being the uid and gid equal their > > old values. > > > > I could introduce a new flag I suppose. > > > I've looked at this again, since I had misread PRIV_SETUGID as > PRIV_SETID. Now I'm not sure if the vulnerability I mentioned actually > exists. The flag usage is obscure, in part, because we originally > intended to add forced privileges on executables, as was done in Trusted > Solaris. This was postponed because we weren't ready to introduce the > complexity of new security attributes for files. Since we are adding a > new attribute for the FMAC security context, it seems to be the right > time to implement forced privileges, as well. This is especially timely > since the Linux community is adding a similar feature which they call > POSIX file capabilities > (http://www.ibm.com/developerworks/library/l-posixcap.html ). Strictly speaking, you don't need forced privileges on executables if you use type enforcement (which can likewise bind privileges to processes based on their entrypoint executables) and if you allow FMAC to be authoritative rather than restrictive-only (i.e. allow it to grant privileges as well as deny them). Type enforcement vs. POSIX.1e privileges were compared in: http://www.securecomputing.com/pdfs/secureos.pdf And type enforcement vs. setuid was compared in D.J. Thomsen and J.T. Haigh, "A Comparison of Type Enforcement and Unix Setuid Implementation of Well-formed Transactions", Proceedings of the 6th Annual Computer Security Applications Conference, 1990. http://www.cs.utah.edu/~sjt/seminar/papers/te-cw-setuid.ps If you support both privileges-on-executables and TE, then you'll essentially have redundant policy in two places - one on a per-file basis scattered throughout your filesystem and one in the centralized FMAC policy (with only the entrypoint type tags assigned on a per-file basis - but the privilege assignment to those types centralized, along with the domain transition rules). > I've copied Casper Dik who introduced these flags in Solaris 10, to > verify that it is safe to set PRIV_SETUGID for secid transitions. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Sep 4 05:33:12 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 04 Sep 2008 08:33:12 -0400 Subject: [fmac-discuss] REVIEW: FMAC man pages In-Reply-To: References: Message-ID: <1220531592.17197.43.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 17:17 -0700, Cathleen Reiher wrote: > Hi all, > > I've created a new man page to > describe the new getfilecon and > setfilecon utilities that Stephen > Smalley introduced with his > 9/3/08 patches. > > I've also updated the pcon(1M), > setfiles(1M), and fmac(5) man > pages to refer to these new > commands. > > The updated man pages are posted > on the project page: > > http://www.opensolaris.org/os/project/fmac/docs/ > > Please send your feedback to the > discussion list. Thanks for your > review. First sentence of getfilecon DESCRIPTION doesn't quite seem right ("...for one or more files, filename."). setfilecon can be used to customize file labels individually to a specific context, while setfiles is oriented toward labeling an entire filesystem based on the file_contexts specification, primarily for the initial labeling of a filesystem or to reset it to a known state. getfilecon/setfilecon are largely obsoleted in modern SELinux by the direct support in GNU coreutils for displaying and setting file security contexts. setfiles still exists but is used less frequently due to the directly integrated support for initial setting of file security contexts by the package manager, and most users today use setfiles via an alternate user interface called restorecon that avoids the need to manually specify the location of the file_contexts configuration and has slightly different default behaviors. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Sep 4 07:38:35 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 04 Sep 2008 10:38:35 -0400 Subject: [fmac-discuss] [RFC][PATCH] Prototype file security context support In-Reply-To: <48BEEBEF.3080903@Sun.COM> References: <488CD182.5060902@Sun.COM> <1217268420.20373.88.camel@moss-spartans.epoch.ncsc.mil> <488E140F.5000907@Sun.COM> <1217272865.20373.121.camel@moss-spartans.epoch.ncsc.mil> <488E1DF1.8060508@Sun.COM> <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> <48BEE6C3.8080803@Sun.COM> <1220471487.6034.187.camel@moss-spartans.epoch.ncsc.mil> <48BEEBEF.3080903@Sun.COM> Message-ID: <1220539115.17197.77.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 13:56 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > On Wed, 2008-09-03 at 13:34 -0600, Mark Shellenbaum wrote: > >> Stephen Smalley wrote: > >>> 2) It appears that we can only set attributes on regular files and > >>> directories, whereas we need security contexts on all file types. As I > >>> recall, Linux also had limitations in what file types supported > >>> attributes originally but these limitations were removed by the time we > >>> migrated SELinux to using Linux xattrs. Hopefully this limitation can > >>> also be removed from Solaris. > >>> > >> We could support these easily on device files, but are you also wanting > >> the context on symlinks? The link itself, not what it points to? > > > > Yes, the symlink itself, reflecting the security attributes of its > > creator, so that we can decide whether another process is allowed to > > read or follow it. > > > >>> 3) Although the code seems to be successfully computing a secctx for new > >>> files and setting up an xvattr to convey it to the filesystem create and > >>> mkdir operations (see fmac_vnode_create as called by fop_create and > >>> fop_mkdir) and we later see that xvattr in the subsequent > >>> secpolicy_xvattr call, the attribute is not being set on the new files > >>> by zfs. I'm not clear as to whether support for setting system > >>> attribute at creation exists in zfs presently or if I have missed some > >>> crucial step there. > >>> > >> This is most likely because the bonus buffer hasn't been resized to make > >> space for the security context. In zfs_setattr() prior to setting the > >> scanstamp attribute the bonus is resized to make room for the attribute. > > > > Ah, I see - I'll have to try resizing it in zfs_create()/mkdir(). > > > > I would do the resize in zfs_xvattr_set(). You will need to pass the > dmu_tx_t to the function though. Yes, that seems to have fixed the problem with labeling of new files. Patch below relative to the prior one moves the resizing into zfs_xvattr_set() as you suggested. I'll merge this change into the patch for its next revision. Thanks. diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h --- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h @@ -335,7 +335,7 @@ znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp); extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp, vsecattr_t *vsecp, zfs_fuid_info_t *fuidp); -extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap); +extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx); extern void zfs_upgrade(zfsvfs_t *zfsvfs, dmu_tx_t *tx); extern caddr_t zfs_map_page(page_t *, enum seg_rw); diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -1868,7 +1868,7 @@ /* Set optional attributes if any */ if (vap->va_mask & AT_XVATTR) - zfs_xvattr_set(zp, xvap); + zfs_xvattr_set(zp, xvap, tx); mutex_exit(&zp->z_lock); mutex_exit(&zp->z_acl_lock); diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -2785,37 +2785,8 @@ * update from toggling bit */ - if (xoap && (mask & AT_XVATTR)) { - if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) && - (!(zp->z_phys->zp_flags & ZFS_BONUS_SECCTX))) { - size_t len; - dmu_object_info_t doi; - - ASSERT(vp->v_type == VREG); - - /* Grow the bonus buffer if necessary. */ - dmu_object_info_from_db(zp->z_dbuf, &doi); - len = sizeof (xoap->xoa_av_scanstamp) + - sizeof (znode_phys_t); - if (len > doi.doi_bonus_size) - VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); - } - if (XVA_ISSET_REQ(xvap, XAT_SECCTX) && - (!(zp->z_phys->zp_flags & ZFS_BONUS_SCANSTAMP))) { - size_t len; - dmu_object_info_t doi; - - ASSERT(vp->v_type != VLNK); - - /* Grow the bonus buffer if necessary. */ - dmu_object_info_from_db(zp->z_dbuf, &doi); - len = sizeof (xoap->xoa_secctx) + - sizeof (znode_phys_t); - if (len > doi.doi_bonus_size) - VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); - } - zfs_xvattr_set(zp, xvap); - } + if (xoap && (mask & AT_XVATTR)) + zfs_xvattr_set(zp, xvap, tx); if (mask != 0) zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp); diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c --- a/usr/src/uts/common/fs/zfs/zfs_znode.c +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c @@ -851,9 +851,14 @@ } void -zfs_xvattr_set(znode_t *zp, xvattr_t *xvap) +zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx) { xoptattr_t *xoap; + size_t len; + dmu_object_info_t doi; + vnode_t *vp; + + vp = ZTOV(zp); xoap = xva_getxoptattr(xvap); ASSERT(xoap); @@ -908,12 +913,29 @@ XVA_SET_RTN(xvap, XAT_AV_MODIFIED); } if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { + ASSERT(vp->v_type == VREG); + + /* Grow the bonus buffer if necessary. */ + dmu_object_info_from_db(zp->z_dbuf, &doi); + len = sizeof (xoap->xoa_av_scanstamp) + + sizeof (znode_phys_t); + if (len > doi.doi_bonus_size) + VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); + (void) memcpy(zp->z_phys + 1, xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp)); zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP; XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); } if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) { + ASSERT(vp->v_type != VLNK); + + /* Grow the bonus buffer if necessary. */ + dmu_object_info_from_db(zp->z_dbuf, &doi); + len = sizeof (xoap->xoa_secctx) + + sizeof (znode_phys_t); + if (len > doi.doi_bonus_size) + VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); (void) memcpy(zp->z_phys + 1, xoap->xoa_secctx, sizeof (xoap->xoa_secctx)); zp->z_phys->zp_flags |= ZFS_BONUS_SECCTX; -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Sep 4 08:27:36 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 04 Sep 2008 09:27:36 -0600 Subject: [fmac-discuss] [RFC][PATCH] Prototype file security context support In-Reply-To: <48BEE6C3.8080803@Sun.COM> References: <488CD182.5060902@Sun.COM> <1217268420.20373.88.camel@moss-spartans.epoch.ncsc.mil> <488E140F.5000907@Sun.COM> <1217272865.20373.121.camel@moss-spartans.epoch.ncsc.mil> <488E1DF1.8060508@Sun.COM> <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> <48BEE6C3.8080803@Sun.COM> Message-ID: <48BFFE68.7000502@Sun.COM> Mark Shellenbaum wrote: > Stephen Smalley wrote: >> Hi, >> >> Based on our earlier exchange about FMAC support in the filesystem, I've >> prototyped file security context support via a new "secctx" system >> attribute. This patch isn't intended for production use but is just a >> prototype to investigate what is required, to help identify issues with >> this approach, and to enable us to make progress on developing other >> parts of FMAC that depend on file security contexts. >> >> In the kernel, this patch adds support for a "secctx" system attribute, >> fetches this attribute on the lookup path and maps it to an in-core >> vnode secid (a non-persistent handle to a context) for internal use by >> FMAC, and attempts to compute and set this attribute on the create path >> (this last part doesn't appear to work though - see below). In >> userland, this patch implements getfilecon() and setfilecon() libc >> interfaces and corresponding utilities for getting and setting the file >> security context. With the patch applied, I can successfully set file >> contexts via setfilecon (e.g. setfilecon >> system_u:object_r:shadow_t /etc/shadow) and get them via getfilecon >> (e.g. getfilecon /etc/shadow) on a zfs filesystem. >> >> The limitations of this patch include: >> 1) Storage of the secctx is presently limited to 56 bytes since it is >> stored directly in the bonus buffer and is exclusive of the av >> scanstamp. I expect that this limitation can be addressed by storing >> the secctx externally as with the external acl support and/or by using >> the more extensible mechanism you are developing for system attributes. >> We also need a more flexible way of passing it internally as a >> variable-length string in the xoptattr rather than as a fixed size >> buffer. >> > > This seems reasonable until I finish the rework of the system attribute > support in ZFS. > >> 2) It appears that we can only set attributes on regular files and >> directories, whereas we need security contexts on all file types. As I >> recall, Linux also had limitations in what file types supported >> attributes originally but these limitations were removed by the time we >> migrated SELinux to using Linux xattrs. Hopefully this limitation can >> also be removed from Solaris. >> > > We could support these easily on device files, but are you also wanting > the context on symlinks? The link itself, not what it points to? > >> 3) Although the code seems to be successfully computing a secctx for new >> files and setting up an xvattr to convey it to the filesystem create and >> mkdir operations (see fmac_vnode_create as called by fop_create and >> fop_mkdir) and we later see that xvattr in the subsequent >> secpolicy_xvattr call, the attribute is not being set on the new files >> by zfs. I'm not clear as to whether support for setting system >> attribute at creation exists in zfs presently or if I have missed some >> crucial step there. >> > > This is most likely because the bonus buffer hasn't been resized to make > space for the security context. In zfs_setattr() prior to setting the > scanstamp attribute the bonus is resized to make room for the attribute. > > this bug should also exist if anybody ever tried to set the scanstamp > during a create. Nobody currently does that. > >> I'd appreciate any comments you have on the above limitations or on the >> code below. >> > > I will take a look at all of your file system and libc related changes > and get you some comments within the next day or two. > >> Webrev available at: http://cr.opensolaris.org/~sds/secctx/ > libc/port/gen/attrat.c How about a blank line between lines 325 and 326. libc_nvlist_alloc() isn't returning consistent error values the attrat_init() function could return -1, and then nvalloc() could return an errno as the returned value. libc/port/gen/filecon.c line 80 I believe you will be setting errno to -1 in that error case. libc_nvlist_alloc() won't be returning an errno as the returned value. this is a side effect of the attrat.c issue uts/common/fmac/fmac.c fmac_vnode_create(). I would like this function changed to not replace the original vattr_t with an xvattr_t, but rather just initialize the xvattr_t to include the original mask/data from the users vattr_t. Then in fop_create()/fop_mkdir() pass the xvattr_t instead of the users vattr_t. Some file systems can get a bit grumpy if you start changing the vattr_t from underneath it. Also, you should do the vfs_has_feature check earlier in the function around line 256 or after 258. usr/src/uts/common/os/policy.[ch] in secpolicy_xvattr() since you are now passing in the complete "vp" you should get rid of the vtype_t parameter since we can now get that directly from the passed in vnode. usr/src/cmd/fmac/setfiles.c Shouldn't the various error messages have gettext() calls wrapped around them? The ZFS changes look fine. -Mark From sds at tycho.nsa.gov Thu Sep 4 09:50:18 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 04 Sep 2008 12:50:18 -0400 Subject: [fmac-discuss] [RFC][PATCH] Prototype file security context support In-Reply-To: <48BFFE68.7000502@Sun.COM> References: <488CD182.5060902@Sun.COM> <1217268420.20373.88.camel@moss-spartans.epoch.ncsc.mil> <488E140F.5000907@Sun.COM> <1217272865.20373.121.camel@moss-spartans.epoch.ncsc.mil> <488E1DF1.8060508@Sun.COM> <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> <48BEE6C3.8080803@Sun.COM> <48BFFE68.7000502@Sun.COM> Message-ID: <1220547018.17197.114.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-09-04 at 09:27 -0600, Mark Shellenbaum wrote: > libc/port/gen/attrat.c > How about a blank line between lines 325 and 326. > libc_nvlist_alloc() isn't returning consistent error values > the attrat_init() function could return -1, and then > nvalloc() could return an errno as the returned value. Good catch, thanks. Can I rely on any errors in attrat_init() to set errno such that I can just return (errno) if it fails, or should I fall back to some fixed errno value if the attrat_init() call fails? Looks like nvlist_alloc normally can fail with EINVAL or ENOMEM. attrat_init() can fail on dlopen() or dlsym() calls. I suppose I could do: if (attrat_init()) return (errno ? errno : EINVAL); if that isn't too ugly. > libc/port/gen/filecon.c > line 80 I believe you will be setting errno to -1 in that > error case. libc_nvlist_alloc() won't be returning an errno > as the returned value. this is a side effect of the attrat.c > issue Ok, so that would be fixed by the above. In general this difference in return code conventions for the nvlist functions vs. other library functions seems prone to mistakes. > uts/common/fmac/fmac.c > fmac_vnode_create(). I would like this function changed to > not replace the original vattr_t with an xvattr_t, but rather > just initialize the xvattr_t to include the original mask/data > from the users vattr_t. Then in fop_create()/fop_mkdir() > pass the xvattr_t instead of the users vattr_t. Some file > systems can get a bit grumpy if you start changing the vattr_t > from underneath it. Also, you should do the vfs_has_feature > check earlier in the function around line 256 or after 258. Ok, I can change this; just to clarify though - all I am doing is switching the vap pointer to refer to the newly populated xvattr, not mutating the existing vattr at all. It should only have local impact on fop_create/mkdir. > usr/src/uts/common/os/policy.[ch] > in secpolicy_xvattr() since you are now passing in the complete > "vp" you should get rid of the vtype_t parameter since we > can now get that directly from the passed in vnode. I had to retain it because secpolicy_xvattr() is called before the vp exists in the file create code path, in which case we still pass the type (from the vattr) but pass NULL for the vp. This is then used by fmac_vnode_set_secctx() to distinguish a setattr from a create, as those require different permission checks. > usr/src/cmd/fmac/setfiles.c > Shouldn't the various error messages have gettext() calls > wrapped around them? Likely, yes, but it was imported without converting them, so all of its error messages are that way presently. We can clean that up in a follow up patch. > The ZFS changes look fine. Ok, thanks. I'll create a revised patch. -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Sep 4 10:01:31 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 04 Sep 2008 11:01:31 -0600 Subject: [fmac-discuss] [RFC][PATCH] Prototype file security context support In-Reply-To: <1220547018.17197.114.camel@moss-spartans.epoch.ncsc.mil> References: <488CD182.5060902@Sun.COM> <1217268420.20373.88.camel@moss-spartans.epoch.ncsc.mil> <488E140F.5000907@Sun.COM> <1217272865.20373.121.camel@moss-spartans.epoch.ncsc.mil> <488E1DF1.8060508@Sun.COM> <1220462694.6034.129.camel@moss-spartans.epoch.ncsc.mil> <48BEE6C3.8080803@Sun.COM> <48BFFE68.7000502@Sun.COM> <1220547018.17197.114.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C0146B.7090808@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-09-04 at 09:27 -0600, Mark Shellenbaum wrote: >> libc/port/gen/attrat.c >> How about a blank line between lines 325 and 326. >> libc_nvlist_alloc() isn't returning consistent error values >> the attrat_init() function could return -1, and then >> nvalloc() could return an errno as the returned value. > > Good catch, thanks. Can I rely on any errors in attrat_init() to set > errno such that I can just return (errno) if it fails, or should I fall > back to some fixed errno value if the attrat_init() call fails? Looks > like nvlist_alloc normally can fail with EINVAL or ENOMEM. > attrat_init() can fail on dlopen() or dlsym() calls. I suppose I could > do: > if (attrat_init()) > return (errno ? errno : EINVAL); > if that isn't too ugly. > I don't think I would trust the errno being set from attr_init(). You would probably have to use dlerror() to figure out the exact error. In reality that function should never fail, unless you have a broken libnvpair. Your proposed solution looks fine. >> libc/port/gen/filecon.c >> line 80 I believe you will be setting errno to -1 in that >> error case. libc_nvlist_alloc() won't be returning an errno >> as the returned value. this is a side effect of the attrat.c >> issue > > Ok, so that would be fixed by the above. In general this difference in > return code conventions for the nvlist functions vs. other library > functions seems prone to mistakes. > Yep, the errors from the nvlist functions are a bit different. >> uts/common/fmac/fmac.c >> fmac_vnode_create(). I would like this function changed to >> not replace the original vattr_t with an xvattr_t, but rather >> just initialize the xvattr_t to include the original mask/data >> from the users vattr_t. Then in fop_create()/fop_mkdir() >> pass the xvattr_t instead of the users vattr_t. Some file >> systems can get a bit grumpy if you start changing the vattr_t >> from underneath it. Also, you should do the vfs_has_feature >> check earlier in the function around line 256 or after 258. > > Ok, I can change this; just to clarify though - all I am doing is > switching the vap pointer to refer to the newly populated xvattr, not > mutating the existing vattr at all. It should only have local impact on > fop_create/mkdir. > Ok, that part should be alright then. I would still move the vfs_feature check to earlier in the function though. >> usr/src/uts/common/os/policy.[ch] >> in secpolicy_xvattr() since you are now passing in the complete >> "vp" you should get rid of the vtype_t parameter since we >> can now get that directly from the passed in vnode. > > I had to retain it because secpolicy_xvattr() is called before the vp > exists in the file create code path, in which case we still pass the > type (from the vattr) but pass NULL for the vp. This is then used by > fmac_vnode_set_secctx() to distinguish a setattr from a create, as those > require different permission checks. > Oh, that makes sense then. >> usr/src/cmd/fmac/setfiles.c >> Shouldn't the various error messages have gettext() calls >> wrapped around them? > > Likely, yes, but it was imported without converting them, so all of its > error messages are that way presently. We can clean that up in a follow > up patch. > >> The ZFS changes look fine. > > Ok, thanks. I'll create a revised patch. > From Glenn.Faden at Sun.COM Thu Sep 4 10:26:59 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Thu, 04 Sep 2008 10:26:59 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C01A63.4080606@sun.com> Stephen Smalley wrote: > > Strictly speaking, you don't need forced privileges on executables if > you use type enforcement (which can likewise bind privileges to > processes based on their entrypoint executables) and if you allow FMAC > to be authoritative rather than restrictive-only (i.e. allow it to grant > privileges as well as deny them). Type enforcement vs. POSIX.1e > privileges were compared in: > http://www.securecomputing.com/pdfs/secureos.pdf > I would like to explore your suggestion for making FMAC authoritative. In particular, I'd like to see a better integration between the existing sec_policy hooks that are already in the Solaris kernel and the avc_has_perm() calls for FMAC. I think this is a significant architectural issue that affects the placement of the FMAC hooks into the kernel. The sec_policy calls are authoritative, and are only called when the legacy policy is to deny. In SELinux, the LSM hooks are only called when the legacy policy is to allow. So the placement of the hooks is dependent on whether the policy is authoritative. Do you have a specific proposal in this regard? --Glenn From Cathleen.Reiher at Sun.COM Thu Sep 4 12:30:56 2008 From: Cathleen.Reiher at Sun.COM (Cathleen Reiher) Date: Thu, 04 Sep 2008 12:30:56 -0700 Subject: [fmac-discuss] REVIEW: FMAC man pages In-Reply-To: <1220531592.17197.43.camel@moss-spartans.epoch.ncsc.mil> References: <1220531592.17197.43.camel@moss-spartans.epoch.ncsc.mil> Message-ID: Thanks for the review, Stephen. I've made updates to the getfilecon(1M) and setfiles(1M) man pages based on your comments, and posted the pages to the FMAC docs page: http://www.opensolaris.org/os/project/fmac/docs/ Does the FMAC project plan to update the Solaris core utilities as was done for the GNU core utilities in SELinux? Or, does FMAC plan to use the getfilecon and setfilecon commands instead? Also, will FMAC introduce the restorecon utility? Cathleen. Stephen Smalley wrote: > On Wed, 2008-09-03 at 17:17 -0700, Cathleen Reiher wrote: > > Hi all, > > > > I've created a new man page to > > describe the new getfilecon and > > setfilecon utilities that Stephen > > Smalley introduced with his > > 9/3/08 patches. > > > > I've also updated the pcon(1M), > > setfiles(1M), and fmac(5) man > > pages to refer to these new > > commands. > > > > The updated man pages are posted > > on the project page: > > > > http://www.opensolaris.org/os/project/fmac/docs/ > > > > Please send your feedback to the > > discussion list. Thanks for your > > review. > > First sentence of getfilecon DESCRIPTION doesn't quite seem right > ("...for one or more files, filename."). > > setfilecon can be used to customize file labels individually to a > specific context, while setfiles is oriented toward labeling an entire > filesystem based on the file_contexts specification, primarily for the > initial labeling of a filesystem or to reset it to a known state. > > getfilecon/setfilecon are largely obsoleted in modern SELinux by the > direct support in GNU coreutils for displaying and setting file security > contexts. setfiles still exists but is used less frequently due to the > directly integrated support for initial setting of file security > contexts by the package manager, and most users today use setfiles via > an alternate user interface called restorecon that avoids the need to > manually specify the location of the file_contexts configuration and has > slightly different default behaviors. > > -- > Stephen Smalley > National Security Agency > From sds at tycho.nsa.gov Thu Sep 4 12:41:06 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 04 Sep 2008 15:41:06 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C01A63.4080606@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> Message-ID: <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-09-04 at 10:26 -0700, Glenn Faden wrote: > Stephen Smalley wrote: > > > > Strictly speaking, you don't need forced privileges on executables if > > you use type enforcement (which can likewise bind privileges to > > processes based on their entrypoint executables) and if you allow FMAC > > to be authoritative rather than restrictive-only (i.e. allow it to grant > > privileges as well as deny them). Type enforcement vs. POSIX.1e > > privileges were compared in: > > http://www.securecomputing.com/pdfs/secureos.pdf > > > I would like to explore your suggestion for making FMAC authoritative. > In particular, I'd like to see a better integration between the existing > sec_policy hooks that are already in the Solaris kernel and the > avc_has_perm() calls for FMAC. I think this is a significant > architectural issue that affects the placement of the FMAC hooks into > the kernel. The sec_policy calls are authoritative, and are only called > when the legacy policy is to deny. In SELinux, the LSM hooks are only > called when the legacy policy is to allow. So the placement of the hooks > is dependent on whether the policy is authoritative. Do you have a > specific proposal in this regard? I'd expect FMAC to be similar to SELinux in that we would insert an ordinary permission checking hook that would always get applied before an operation is granted, ideally but not necessarily after the existing DAC checking (this is helpful when trying to generate policy as it avoids noise from harmless application probing that would be denied by DAC anyway, but it isn't strictly required), and a separate hook in the existing privilege interfaces (capable in Linux, secpolicy_* in Solaris) that would only get applied if a privilege was required. For example, we might insert a hook into fop_access() after a successful ->vop_access() call to apply a FMAC file read/write/execute permission check based on the security contexts of the process and file governing whether access is allowed by the MAC policy at all. We would also insert a separate hook into secpolicy_vnode_access() to apply a FMAC file priv_read/priv_write/priv_exec permission check governing whether or not the privilege to override the normal DAC checks should be granted for the given process and file security context; these would correspond with the SELinux capability checks except that they can take into account the object as well. The authoritative vs. restrictive issue just depends on how we combine the logic of the base privilege model in the existing secpolicy functions and the FMAC hook called by those functions; it doesn't really change the hook placement. In SELinux today, the base capability logic is applied first and if it denies access, then a permission denial is immediately returned. I have floated patches before to allow SELinux to be authoritative with respect to Linux capabilities (circa June 2007 on selinux list) by introducing another set of permissions governing whether a denial by the base capability logic should be overridden. There are however some concerns about the implications of such a change, both due to the long established behavior of SELinux as restrictive-only as well as concerns about how to handle selinux-disabled, permissive mode, the "unconfined" domain of targeted policy, etc. The other approach is to stay restrictive and continue using setuid programs to grant privileges but confine what privileges they can exercise using type enforcement policy, as we do presently in SELinux. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Sep 4 12:54:00 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 04 Sep 2008 15:54:00 -0400 Subject: [fmac-discuss] REVIEW: FMAC man pages In-Reply-To: References: <1220531592.17197.43.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <1220558040.17197.255.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-09-04 at 12:30 -0700, Cathleen Reiher wrote: > Thanks for the review, Stephen. > > I've made updates to the getfilecon(1M) > and setfiles(1M) man pages based on > your comments, and posted the pages > to the FMAC docs page: > > http://www.opensolaris.org/os/project/fmac/docs/ > > Does the FMAC project plan to update > the Solaris core utilities as was done for > the GNU core utilities in SELinux? Or, > does FMAC plan to use the getfilecon > and setfilecon commands instead? > Also, will FMAC introduce the restorecon > utility? I don't think we know yet - it depends on the direction that OpenSolaris takes for its userland, e.g. if they migrate to a GNU userland, we'd leverage the existing support there and generalize it to work on either Linux or Solaris; if not, then we'd be more likely to extend the Solaris core utilities. The Solaris utilities already have support for Solaris file attributes, but not specifically for security contexts, so for example, cp -/ foo foo1 will try to preserve the security context along with any other system attributes (but there is a kernel permission checking issue there discovered by John), but I don't think you can display the context without modifying the utilities to know that they are printable strings. On restorecon, I think it just depends on user demand; it was originally introduced to SELinux by others as a wrapper for setfiles and later forked into its own program, and I later coalesced the two back into a single program with different default user interfaces and behaviors selected by link name. -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Thu Sep 4 13:44:41 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Thu, 04 Sep 2008 13:44:41 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C048B9.6070701@sun.com> Stephen Smalley wrote: > On Thu, 2008-09-04 at 10:26 -0700, Glenn Faden wrote: > >> >> I would like to explore your suggestion for making FMAC authoritative. >> In particular, I'd like to see a better integration between the existing >> sec_policy hooks that are already in the Solaris kernel and the >> avc_has_perm() calls for FMAC. I think this is a significant >> architectural issue that affects the placement of the FMAC hooks into >> the kernel. The sec_policy calls are authoritative, and are only called >> when the legacy policy is to deny. In SELinux, the LSM hooks are only >> called when the legacy policy is to allow. So the placement of the hooks >> is dependent on whether the policy is authoritative. Do you have a >> specific proposal in this regard? >> > > I'd expect FMAC to be similar to SELinux in that we would insert an > ordinary permission checking hook that would always get applied before > an operation is granted, ideally but not necessarily after the existing > DAC checking (this is helpful when trying to generate policy as it > avoids noise from harmless application probing that would be denied by > DAC anyway, but it isn't strictly required), and a separate hook in the > existing privilege interfaces (capable in Linux, secpolicy_* in Solaris) > that would only get applied if a privilege was required. For example, > we might insert a hook into fop_access() after a successful > ->vop_access() call to apply a FMAC file read/write/execute permission > check based on the security contexts of the process and file governing > whether access is allowed by the MAC policy at all. We would also > insert a separate hook into secpolicy_vnode_access() to apply a FMAC > file priv_read/priv_write/priv_exec permission check governing whether > or not the privilege to override the normal DAC checks should be granted > for the given process and file security context; these would correspond > with the SELinux capability checks except that they can take into > account the object as well. > Yes, having separate hooks for the restrictive and authoritative checks is what I meant in my comment about hook placement. > The authoritative vs. restrictive issue just depends on how we combine > the logic of the base privilege model in the existing secpolicy > functions and the FMAC hook called by those functions; it doesn't really > change the hook placement. In SELinux today, the base capability logic > is applied first and if it denies access, then a permission denial is > immediately returned. I have floated patches before to allow SELinux to > be authoritative with respect to Linux capabilities (circa June 2007 on > selinux list) by introducing another set of permissions governing > whether a denial by the base capability logic should be overridden. > There are however some concerns about the implications of such a change, > both due to the long established behavior of SELinux as restrictive-only > as well as concerns about how to handle selinux-disabled, permissive > mode, the "unconfined" domain of targeted policy, etc. > I'm in favor of providing flexibility for both authoritative and restrictive policies. Since FMAC is new in OpenSolaris, we shouldn't have to deal with backward compatibility with existing FMAC policies. We would be constrained that process privileges still work even when FMAC is disabled, but it is reasonable to require enabling FMAC to associate privileges with specific objects. Or we might have two switches for FMAC enabling: Restrictive(Off/Permissive/Enforcing) and Authoritative(Off,Tracing/Enforcing). > The other approach is to stay restrictive and continue using setuid > programs to grant privileges but confine what privileges they can > exercise using type enforcement policy, as we do presently in SELinux. > > Sure, but we have the opportunity do something better. --Glenn From sds at tycho.nsa.gov Fri Sep 5 06:48:19 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 05 Sep 2008 09:48:19 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C048B9.6070701@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> Message-ID: <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-09-04 at 13:44 -0700, Glenn Faden wrote: > Stephen Smalley wrote: > > On Thu, 2008-09-04 at 10:26 -0700, Glenn Faden wrote: > > > >> > >> I would like to explore your suggestion for making FMAC authoritative. > >> In particular, I'd like to see a better integration between the existing > >> sec_policy hooks that are already in the Solaris kernel and the > >> avc_has_perm() calls for FMAC. I think this is a significant > >> architectural issue that affects the placement of the FMAC hooks into > >> the kernel. The sec_policy calls are authoritative, and are only called > >> when the legacy policy is to deny. In SELinux, the LSM hooks are only > >> called when the legacy policy is to allow. So the placement of the hooks > >> is dependent on whether the policy is authoritative. Do you have a > >> specific proposal in this regard? > >> > > > > I'd expect FMAC to be similar to SELinux in that we would insert an > > ordinary permission checking hook that would always get applied before > > an operation is granted, ideally but not necessarily after the existing > > DAC checking (this is helpful when trying to generate policy as it > > avoids noise from harmless application probing that would be denied by > > DAC anyway, but it isn't strictly required), and a separate hook in the > > existing privilege interfaces (capable in Linux, secpolicy_* in Solaris) > > that would only get applied if a privilege was required. For example, > > we might insert a hook into fop_access() after a successful > > ->vop_access() call to apply a FMAC file read/write/execute permission > > check based on the security contexts of the process and file governing > > whether access is allowed by the MAC policy at all. We would also > > insert a separate hook into secpolicy_vnode_access() to apply a FMAC > > file priv_read/priv_write/priv_exec permission check governing whether > > or not the privilege to override the normal DAC checks should be granted > > for the given process and file security context; these would correspond > > with the SELinux capability checks except that they can take into > > account the object as well. > > > > Yes, having separate hooks for the restrictive and authoritative checks > is what I meant in my comment about hook placement. > > The authoritative vs. restrictive issue just depends on how we combine > > the logic of the base privilege model in the existing secpolicy > > functions and the FMAC hook called by those functions; it doesn't really > > change the hook placement. In SELinux today, the base capability logic > > is applied first and if it denies access, then a permission denial is > > immediately returned. I have floated patches before to allow SELinux to > > be authoritative with respect to Linux capabilities (circa June 2007 on > > selinux list) by introducing another set of permissions governing > > whether a denial by the base capability logic should be overridden. > > There are however some concerns about the implications of such a change, > > both due to the long established behavior of SELinux as restrictive-only > > as well as concerns about how to handle selinux-disabled, permissive > > mode, the "unconfined" domain of targeted policy, etc. > > > I'm in favor of providing flexibility for both authoritative and > restrictive policies. Since FMAC is new in OpenSolaris, we shouldn't > have to deal with backward compatibility with existing FMAC policies. We > would be constrained that process privileges still work even when FMAC > is disabled, but it is reasonable to require enabling FMAC to associate > privileges with specific objects. Or we might have two switches for FMAC > enabling: Restrictive(Off/Permissive/Enforcing) and > Authoritative(Off,Tracing/Enforcing). Ok, it might look something like the following patch (untested): --- old/usr/src/common/fmac/policy/flask/access_vectors Fri Sep 5 09:41:39 2008 +++ new/usr/src/common/fmac/policy/flask/access_vectors Fri Sep 5 09:41:37 2008 @@ -40,6 +40,9 @@ write read append + priv_execute + priv_write + priv_read open create link @@ -130,6 +133,7 @@ remove_name reparent search + priv_search rmdir mounton mountassociate --- old/usr/src/uts/common/fmac/fmac.c Fri Sep 5 09:41:42 2008 +++ new/usr/src/uts/common/fmac/fmac.c Fri Sep 5 09:41:41 2008 @@ -43,6 +43,7 @@ /* Tunables */ int fmac_enabled = 1; /* policy enabled */ int fmac_enforcing = 0; /* permissive or enforcing */ +int fmac_authoritative = 0; /* restrictive or authoritative */ char *fmac_default_policy_file = FMAC_POLICY_FILE; @@ -78,6 +79,14 @@ fmac_enabled = 1; fmac_enforcing = 0; cp += sizeof ("permissive") - 1; + } else if (strncmp(cp, "authoritative", + sizeof ("authoritative")-1) == 0) { + fmac_authoritative = 1; + cp += sizeof ("authoritative") - 1; + } else if (strncmp(cp, "restrictive", + sizeof ("restrictive")-1) == 0) { + fmac_authoritative = 0; + cp += sizeof ("restrictive") - 1; } /* Check for additional arguments */ @@ -361,4 +370,84 @@ *prev_secidp = prev_secid; *secidp = secid; return (0); +} + +int +fmac_vnode_access(cred_t *cr, vnode_t *vp, int mode, int flags) +{ + security_id_t cr_secid; + security_class_t sclass; + access_vector_t av; + int error; + + if (!fmac_enabled) + return (0); + + cr_secid = crgetsecid(cr); + + sclass = fmac_vtype_to_sclass(vp->v_type); + if (!sclass) + return (0); + + av = 0; + if (mode & VREAD) + av |= FILE__READ; + if (flags & V_APPEND) + av |= FILE__APPEND; + else if (mode & VWRITE) + av |= FILE__WRITE; + if (mode & VEXEC) { + if (sclass == SECCLASS_DIR) + av |= DIR__SEARCH; + else + av |= FILE__EXECUTE; + } + + if (!av) + return (0); + + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); +} + +int +fmac_vnode_priv_access(cred_t *cr, vnode_t *vp, int mode, int err) +{ + security_id_t cr_secid; + security_class_t sclass; + access_vector_t av; + + /* If not enabled, just return the legacy policy decision. */ + if (!fmac_enabled) + return (err); + + /* + * If the legacy policy check failed, and FMAC is either + * permissive or restrictive-only, then return the legacy + * policy decision. + */ + if (err && (!fmac_enforcing || !fmac_authoritative)) + return (err); + + cr_secid = crgetsecid(cr); + + sclass = fmac_vtype_to_sclass(vp->v_type); + if (!sclass) + return (err); + + av = 0; + if (mode & VREAD) + av |= FILE__PRIV_READ; + if (mode & VWRITE) + av |= FILE__PRIV_WRITE; + if (mode & VEXEC) { + if (sclass == SECCLASS_DIR) + av |= DIR__PRIV_SEARCH; + else + av |= FILE__PRIV_EXECUTE; + } + + if (!av) + return (err); + + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); } --- old/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:44 2008 +++ new/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:43 2008 @@ -3298,7 +3298,9 @@ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); VOPSTATS_UPDATE(vp, access); - return (err); + if (err) + return (err); + return (fmac_vnode_access(cr, vp, mode, flags)); } int --- old/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:48 2008 +++ new/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:47 2008 @@ -835,13 +835,15 @@ int secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) { + int err = 0; + if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { - return (EACCES); + err = EACCES; } - if (mode & VWRITE) { + if (!err && (mode & VWRITE)) { boolean_t allzone; if (owner == 0 && cr->cr_uid != 0) @@ -851,11 +853,11 @@ if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { - return (EACCES); + err = EACCES; } } - if (mode & VEXEC) { + if (!err && (mode & VEXEC)) { /* * Directories use file_dac_search to override the execute bit. */ @@ -862,10 +864,11 @@ int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : PRIV_FILE_DAC_EXECUTE; - return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, - KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); + err = priv_policy_va(cr, p, B_FALSE, EACCES, NULL, + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE); } - return (0); + + return (fmac_vnode_priv_access(cr, vp, mode, err)); } /* --- old/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:52 2008 +++ new/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:50 2008 @@ -91,6 +91,8 @@ void fmac_vnode_post_create(vnode_t *, security_id_t); int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, security_id_t *prev_secidp, security_id_t *secidp); +int fmac_vnode_access(cred_t *, vnode_t *, int, int); +int fmac_vnode_priv_access(cred_t *, vnode_t *, int, int); #endif /* _KERNEL */ #ifdef __cplusplus -- Stephen Smalley National Security Agency From Darren.Moffat at Sun.COM Fri Sep 5 06:59:28 2008 From: Darren.Moffat at Sun.COM (Darren J Moffat) Date: Fri, 05 Sep 2008 14:59:28 +0100 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C048B9.6070701@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> Message-ID: <48C13B40.4060309@Sun.COM> Glenn Faden wrote: > privileges with specific objects. Or we might have two switches for FMAC > enabling: Restrictive(Off/Permissive/Enforcing) and > Authoritative(Off,Tracing/Enforcing). I think I've followed all the discussion up to this point but I might be missing some subtleties. I don't like the idea of integrating FMAC and having one or more switches that amount to turning it off completely or changing how it works in ways that the words above suggest. If we are going to have FMAC then I think it should always be there. Just like we can't turn off privileges in Solaris 10 today, we dealt with the backwards compatibility issues with setuid so that there is no on/off switch for privileges and there isn't even an on/off switch for privilege debugging like there was in previous Trusted Solaris releases (instead a process flag and dtrace SDT probes). It might amount to the same thing but couldn't we instead have FMAC as "Authoritative: Enforcing" but a default policy that preserves backwards compatibility. Similarly for Restrictive. Part of my concern is about is getting into a situation where a given system deployment (based on best practices for the applications/services being deployed) on a single kernel requires conflicting settings for the Restrictive/Authoritative switches - if that is possible then I think FMAC would be see as to complex by those doing the system deployment. -- Darren J Moffat From Mark.Shellenbaum at Sun.COM Fri Sep 5 07:12:59 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Fri, 05 Sep 2008 08:12:59 -0600 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C13E6B.3000506@Sun.COM> Stephen Smalley wrote: > On Thu, 2008-09-04 at 13:44 -0700, Glenn Faden wrote: >> Stephen Smalley wrote: >>> On Thu, 2008-09-04 at 10:26 -0700, Glenn Faden wrote: >>> >>>> I would like to explore your suggestion for making FMAC authoritative. >>>> In particular, I'd like to see a better integration between the existing >>>> sec_policy hooks that are already in the Solaris kernel and the >>>> avc_has_perm() calls for FMAC. I think this is a significant >>>> architectural issue that affects the placement of the FMAC hooks into >>>> the kernel. The sec_policy calls are authoritative, and are only called >>>> when the legacy policy is to deny. In SELinux, the LSM hooks are only >>>> called when the legacy policy is to allow. So the placement of the hooks >>>> is dependent on whether the policy is authoritative. Do you have a >>>> specific proposal in this regard? >>>> > > Ok, it might look something like the following patch (untested): > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (0); > + > + av = 0; > + if (mode & VREAD) > + av |= FILE__READ; > + if (flags & V_APPEND) > + av |= FILE__APPEND; > + else if (mode & VWRITE) > + av |= FILE__WRITE; > + if (mode & VEXEC) { > + if (sclass == SECCLASS_DIR) > + av |= DIR__SEARCH; > + else > + av |= FILE__EXECUTE; > + } > + > + if (!av) > + return (0); > + > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); > +} > + It would be great if we could extend the mode field in the various policy functions to represent more than just traditional unix "rwx" permissions, but instead be flexible enough to take either a traditional "rwx" model or an NFSv4 ACL permission mask. Otherwise, ZFS has to attempt to convert the NFSv4 permissions into an equivalent "rwx" permission mask in certain situations. > +int > +fmac_vnode_priv_access(cred_t *cr, vnode_t *vp, int mode, int err) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + access_vector_t av; > + > + /* If not enabled, just return the legacy policy decision. */ > + if (!fmac_enabled) > + return (err); > + > + /* > + * If the legacy policy check failed, and FMAC is either > + * permissive or restrictive-only, then return the legacy > + * policy decision. > + */ > + if (err && (!fmac_enforcing || !fmac_authoritative)) > + return (err); > + > + cr_secid = crgetsecid(cr); > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (err); > + > + av = 0; > + if (mode & VREAD) > + av |= FILE__PRIV_READ; > + if (mode & VWRITE) > + av |= FILE__PRIV_WRITE; > + if (mode & VEXEC) { > + if (sclass == SECCLASS_DIR) > + av |= DIR__PRIV_SEARCH; > + else > + av |= FILE__PRIV_EXECUTE; > + } > + > + if (!av) > + return (err); > + > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); > } > --- old/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:44 2008 > +++ new/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:43 2008 > @@ -3298,7 +3298,9 @@ > > err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); > VOPSTATS_UPDATE(vp, access); > - return (err); > + if (err) > + return (err); > + return (fmac_vnode_access(cr, vp, mode, flags)); > } > > int > --- old/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:48 2008 > +++ new/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:47 2008 > @@ -835,13 +835,15 @@ > int > secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) > { > + int err = 0; > + > if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, > EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, > KLPDARG_NOMORE) != 0) { > - return (EACCES); > + err = EACCES; > } > > - if (mode & VWRITE) { > + if (!err && (mode & VWRITE)) { > boolean_t allzone; > > if (owner == 0 && cr->cr_uid != 0) > @@ -851,11 +853,11 @@ > if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, > NULL, KLPDARG_VNODE, vp, (char *)NULL, > KLPDARG_NOMORE) != 0) { > - return (EACCES); > + err = EACCES; > } > } > > - if (mode & VEXEC) { > + if (!err && (mode & VEXEC)) { > /* > * Directories use file_dac_search to override the execute bit. > */ > @@ -862,10 +864,11 @@ > int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : > PRIV_FILE_DAC_EXECUTE; > > - return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, > - KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); > + err = priv_policy_va(cr, p, B_FALSE, EACCES, NULL, > + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE); > } > - return (0); > + > + return (fmac_vnode_priv_access(cr, vp, mode, err)); > } > > /* > --- old/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:52 2008 > +++ new/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:50 2008 > @@ -91,6 +91,8 @@ > void fmac_vnode_post_create(vnode_t *, security_id_t); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > security_id_t *prev_secidp, security_id_t *secidp); > +int fmac_vnode_access(cred_t *, vnode_t *, int, int); > +int fmac_vnode_priv_access(cred_t *, vnode_t *, int, int); > #endif /* _KERNEL */ > > #ifdef __cplusplus > From Glenn.Faden at Sun.COM Fri Sep 5 10:22:36 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Fri, 05 Sep 2008 10:22:36 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C13B40.4060309@Sun.COM> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <48C13B40.4060309@Sun.COM> Message-ID: <48C16ADC.7020509@sun.com> Darren J Moffat wrote: > Glenn Faden wrote: > >> privileges with specific objects. Or we might have two switches for FMAC >> enabling: Restrictive(Off/Permissive/Enforcing) and >> Authoritative(Off,Tracing/Enforcing). >> > > I think I've followed all the discussion up to this point but I might be > missing some subtleties. > > I don't like the idea of integrating FMAC and having one or more > switches that amount to turning it off completely or changing how it > works in ways that the words above suggest. > > If we are going to have FMAC then I think it should always be there. > Just like we can't turn off privileges in Solaris 10 today, we dealt > with the backwards compatibility issues with setuid so that there is no > on/off switch for privileges and there isn't even an on/off switch for > privilege debugging like there was in previous Trusted Solaris releases > (instead a process flag and dtrace SDT probes). > > It might amount to the same thing but couldn't we instead have FMAC as > "Authoritative: Enforcing" but a default policy that preserves backwards > compatibility. Similarly for Restrictive. > > Part of my concern is about is getting into a situation where a given > system deployment (based on best practices for the applications/services > being deployed) on a single kernel requires conflicting settings for the > Restrictive/Authoritative switches - if that is possible then I think > FMAC would be see as to complex by those doing the system deployment. > I'm sympathetic to the argument that a feature should be on by default so that it gets well tested, but the restrictive aspects of FMAC will present a challenge if there is no way to disable it. In RHEL5 they ship with a relatively simple targeted policy which is on by default, so it gets well tested. We may be able to follow that model, but we need a way to recover and debug policies since they are much more complex than the current process rights management in Solaris, where we were able to preserve compatibility by interpreting setuid to root as all privileges. However, we disabled Trusted Extensions by default since we couldn't make the restrictions it imposed completely transparent. On the other hand, the authoritative mode of FMAC could probably be enabled all the time, since it shouldn't cause backward compatibility issues. --Glenn From sds at tycho.nsa.gov Fri Sep 5 11:04:13 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 05 Sep 2008 14:04:13 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C13E6B.3000506@Sun.COM> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> <48C13E6B.3000506@Sun.COM> Message-ID: <1220637853.17197.384.camel@moss-spartans.epoch.ncsc.mil> On Fri, 2008-09-05 at 08:12 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > On Thu, 2008-09-04 at 13:44 -0700, Glenn Faden wrote: > >> Stephen Smalley wrote: > >>> On Thu, 2008-09-04 at 10:26 -0700, Glenn Faden wrote: > >>> > >>>> I would like to explore your suggestion for making FMAC authoritative. > >>>> In particular, I'd like to see a better integration between the existing > >>>> sec_policy hooks that are already in the Solaris kernel and the > >>>> avc_has_perm() calls for FMAC. I think this is a significant > >>>> architectural issue that affects the placement of the FMAC hooks into > >>>> the kernel. The sec_policy calls are authoritative, and are only called > >>>> when the legacy policy is to deny. In SELinux, the LSM hooks are only > >>>> called when the legacy policy is to allow. So the placement of the hooks > >>>> is dependent on whether the policy is authoritative. Do you have a > >>>> specific proposal in this regard? > >>>> > > > > > Ok, it might look something like the following patch (untested): > > > + > > + sclass = fmac_vtype_to_sclass(vp->v_type); > > + if (!sclass) > > + return (0); > > + > > + av = 0; > > + if (mode & VREAD) > > + av |= FILE__READ; > > + if (flags & V_APPEND) > > + av |= FILE__APPEND; > > + else if (mode & VWRITE) > > + av |= FILE__WRITE; > > + if (mode & VEXEC) { > > + if (sclass == SECCLASS_DIR) > > + av |= DIR__SEARCH; > > + else > > + av |= FILE__EXECUTE; > > + } > > + > > + if (!av) > > + return (0); > > + > > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); > > +} > > + > > It would be great if we could extend the mode field in the various > policy functions to represent more than just traditional unix "rwx" > permissions, but instead be flexible enough to take either a traditional > "rwx" model or an NFSv4 ACL permission mask. Otherwise, ZFS has to > attempt to convert the NFSv4 permissions into an equivalent "rwx" > permission mask in certain situations. At least in SELinux, we just do this by introducing separate hooks in each operation with the finer-grained permission checks, and only check the generic rwx permissions in the general permission checking function (permission in Linux, fop_access in Solaris). Flask/TE likewise defines a much finer-grained set of permissions than just rwx. -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Fri Sep 5 11:30:48 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Fri, 05 Sep 2008 11:30:48 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C17AD8.4060607@sun.com> Stephen Smalley wrote: This looks like a good first attempt, but I'm not sure it's correct. I'm concerned that it might wind up calling avc_has_perm() twice for a single operation. If my understanding is correct, then this line: err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); VOPSTATS_UPDATE(vp, access); will call the corresponding access function for the filesystem type, e.g., ufs_iaccess() which could result in the following: ufs_iaccess() sec_policy_vnode_access fmac_vnode_priv_access() avc_has_perm() and if this succeeds the avc call is repeated. fmac_vnode_access() avc_has_perm() I think the problem is that the placement of the fmac_vnode_access() is generic for all filesystem types, but sec_policy_vnode_access() is called in filesystem-specific code. One fix would be to move the fmac_vnode_access () call into the filesystem-specific code, too. --Glenn > > Ok, it might look something like the following patch (untested): > > --- old/usr/src/common/fmac/policy/flask/access_vectors Fri Sep 5 09:41:39 2008 > +++ new/usr/src/common/fmac/policy/flask/access_vectors Fri Sep 5 09:41:37 2008 > @@ -40,6 +40,9 @@ > write > read > append > + priv_execute > + priv_write > + priv_read > open > create > link > @@ -130,6 +133,7 @@ > remove_name > reparent > search > + priv_search > rmdir > mounton > mountassociate > --- old/usr/src/uts/common/fmac/fmac.c Fri Sep 5 09:41:42 2008 > +++ new/usr/src/uts/common/fmac/fmac.c Fri Sep 5 09:41:41 2008 > @@ -43,6 +43,7 @@ > /* Tunables */ > int fmac_enabled = 1; /* policy enabled */ > int fmac_enforcing = 0; /* permissive or enforcing */ > +int fmac_authoritative = 0; /* restrictive or authoritative */ > > char *fmac_default_policy_file = FMAC_POLICY_FILE; > > @@ -78,6 +79,14 @@ > fmac_enabled = 1; > fmac_enforcing = 0; > cp += sizeof ("permissive") - 1; > + } else if (strncmp(cp, "authoritative", > + sizeof ("authoritative")-1) == 0) { > + fmac_authoritative = 1; > + cp += sizeof ("authoritative") - 1; > + } else if (strncmp(cp, "restrictive", > + sizeof ("restrictive")-1) == 0) { > + fmac_authoritative = 0; > + cp += sizeof ("restrictive") - 1; > } > > /* Check for additional arguments */ > @@ -361,4 +370,84 @@ > *prev_secidp = prev_secid; > *secidp = secid; > return (0); > +} > + > +int > +fmac_vnode_access(cred_t *cr, vnode_t *vp, int mode, int flags) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + access_vector_t av; > + int error; > + > + if (!fmac_enabled) > + return (0); > + > + cr_secid = crgetsecid(cr); > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (0); > + > + av = 0; > + if (mode & VREAD) > + av |= FILE__READ; > + if (flags & V_APPEND) > + av |= FILE__APPEND; > + else if (mode & VWRITE) > + av |= FILE__WRITE; > + if (mode & VEXEC) { > + if (sclass == SECCLASS_DIR) > + av |= DIR__SEARCH; > + else > + av |= FILE__EXECUTE; > + } > + > + if (!av) > + return (0); > + > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); > +} > + > +int > +fmac_vnode_priv_access(cred_t *cr, vnode_t *vp, int mode, int err) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + access_vector_t av; > + > + /* If not enabled, just return the legacy policy decision. */ > + if (!fmac_enabled) > + return (err); > + > + /* > + * If the legacy policy check failed, and FMAC is either > + * permissive or restrictive-only, then return the legacy > + * policy decision. > + */ > + if (err && (!fmac_enforcing || !fmac_authoritative)) > + return (err); > + > + cr_secid = crgetsecid(cr); > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (err); > + > + av = 0; > + if (mode & VREAD) > + av |= FILE__PRIV_READ; > + if (mode & VWRITE) > + av |= FILE__PRIV_WRITE; > + if (mode & VEXEC) { > + if (sclass == SECCLASS_DIR) > + av |= DIR__PRIV_SEARCH; > + else > + av |= FILE__PRIV_EXECUTE; > + } > + > + if (!av) > + return (err); > + > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); > } > --- old/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:44 2008 > +++ new/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:43 2008 > @@ -3298,7 +3298,9 @@ > > err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); > VOPSTATS_UPDATE(vp, access); > - return (err); > + if (err) > + return (err); > + return (fmac_vnode_access(cr, vp, mode, flags)); > } > > int > --- old/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:48 2008 > +++ new/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:47 2008 > @@ -835,13 +835,15 @@ > int > secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) > { > + int err = 0; > + > if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, > EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, > KLPDARG_NOMORE) != 0) { > - return (EACCES); > + err = EACCES; > } > > - if (mode & VWRITE) { > + if (!err && (mode & VWRITE)) { > boolean_t allzone; > > if (owner == 0 && cr->cr_uid != 0) > @@ -851,11 +853,11 @@ > if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, > NULL, KLPDARG_VNODE, vp, (char *)NULL, > KLPDARG_NOMORE) != 0) { > - return (EACCES); > + err = EACCES; > } > } > > - if (mode & VEXEC) { > + if (!err && (mode & VEXEC)) { > /* > * Directories use file_dac_search to override the execute bit. > */ > @@ -862,10 +864,11 @@ > int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : > PRIV_FILE_DAC_EXECUTE; > > - return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, > - KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); > + err = priv_policy_va(cr, p, B_FALSE, EACCES, NULL, > + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE); > } > - return (0); > + > + return (fmac_vnode_priv_access(cr, vp, mode, err)); > } > > /* > --- old/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:52 2008 > +++ new/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:50 2008 > @@ -91,6 +91,8 @@ > void fmac_vnode_post_create(vnode_t *, security_id_t); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > security_id_t *prev_secidp, security_id_t *secidp); > +int fmac_vnode_access(cred_t *, vnode_t *, int, int); > +int fmac_vnode_priv_access(cred_t *, vnode_t *, int, int); > #endif /* _KERNEL */ > > #ifdef __cplusplus > > From sds at tycho.nsa.gov Fri Sep 5 11:24:02 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 05 Sep 2008 14:24:02 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C13B40.4060309@Sun.COM> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <48C13B40.4060309@Sun.COM> Message-ID: <1220639042.17197.403.camel@moss-spartans.epoch.ncsc.mil> On Fri, 2008-09-05 at 14:59 +0100, Darren J Moffat wrote: > Glenn Faden wrote: > > privileges with specific objects. Or we might have two switches for FMAC > > enabling: Restrictive(Off/Permissive/Enforcing) and > > Authoritative(Off,Tracing/Enforcing). > > I think I've followed all the discussion up to this point but I might be > missing some subtleties. > > I don't like the idea of integrating FMAC and having one or more > switches that amount to turning it off completely or changing how it > works in ways that the words above suggest. > > If we are going to have FMAC then I think it should always be there. > Just like we can't turn off privileges in Solaris 10 today, we dealt > with the backwards compatibility issues with setuid so that there is no > on/off switch for privileges and there isn't even an on/off switch for > privilege debugging like there was in previous Trusted Solaris releases > (instead a process flag and dtrace SDT probes). > > It might amount to the same thing but couldn't we instead have FMAC as > "Authoritative: Enforcing" but a default policy that preserves backwards > compatibility. Similarly for Restrictive. > > Part of my concern is about is getting into a situation where a given > system deployment (based on best practices for the applications/services > being deployed) on a single kernel requires conflicting settings for the > Restrictive/Authoritative switches - if that is possible then I think > FMAC would be see as to complex by those doing the system deployment. We could represent authoritative vs. restrictive as different permissions in the policy rather than as a global setting, e.g. priv_read, priv_read_force. Then priv_read would always have the same semantic meaning (this process may override DAC read restrictions _iff_ the legacy policy logic grants it dac_file_read), and only priv_read_force would indicate that the process should be granted the privilege regardless of what the legacy policy says. Does that address your concern for authoritative vs. restrictive? Enabled vs. disabled is a bit different - the purpose of that setting is to allow recovery in the event that the policy itself is corrupt or missing (although permissive mode should allow for that as well), and to allow those who chose not to use FMAC to avoid any processing overhead from the FMAC code paths (immediate return from all fmac_ functions if ! fmac_enabled). Permissive vs. enforcing may become obsoleted by per-domain permissive mode if/when we introduce that into FMAC, as we can then make domains permissive in policy, although it may still be convenient to have a whole-system or whole-zone permissive setting (unclear). Right now it is fairly crucial to bootstrapping a policy for Solaris. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 5 11:50:09 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 05 Sep 2008 14:50:09 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C17AD8.4060607@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> <48C17AD8.4060607@sun.com> Message-ID: <1220640609.17197.407.camel@moss-spartans.epoch.ncsc.mil> On Fri, 2008-09-05 at 11:30 -0700, Glenn Faden wrote: > Stephen Smalley wrote: > > This looks like a good first attempt, but I'm not sure it's correct. I'm > concerned that it might wind up calling avc_has_perm() twice for a > single operation. That's intentional - it is checking two different permissions (read vs. priv_read, write vs. priv_write, etc). The first is "Can subject S read/write/execute object O?". The second is "Can subject S override DAC restrictions on read/write/execute on object O?". The equivalent in SELinux is: "Can subject S read/write/execute object O?" "Does subject S have dac_override capability?" > > If my understanding is correct, then this line: > > err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); > VOPSTATS_UPDATE(vp, access); > > > will call the corresponding access function for the filesystem type, > e.g., ufs_iaccess() which could result in the following: > > ufs_iaccess() > sec_policy_vnode_access > fmac_vnode_priv_access() > avc_has_perm() > > > and if this succeeds the avc call is repeated. > > fmac_vnode_access() > avc_has_perm() > > > I think the problem is that the placement of the fmac_vnode_access() is > generic for all filesystem types, but sec_policy_vnode_access() is > called in filesystem-specific code. One fix would be to move the > fmac_vnode_access () call into the filesystem-specific code, too. > > --Glenn > > > > Ok, it might look something like the following patch (untested): > > > > --- old/usr/src/common/fmac/policy/flask/access_vectors Fri Sep 5 09:41:39 2008 > > +++ new/usr/src/common/fmac/policy/flask/access_vectors Fri Sep 5 09:41:37 2008 > > @@ -40,6 +40,9 @@ > > write > > read > > append > > + priv_execute > > + priv_write > > + priv_read > > open > > create > > link > > @@ -130,6 +133,7 @@ > > remove_name > > reparent > > search > > + priv_search > > rmdir > > mounton > > mountassociate > > --- old/usr/src/uts/common/fmac/fmac.c Fri Sep 5 09:41:42 2008 > > +++ new/usr/src/uts/common/fmac/fmac.c Fri Sep 5 09:41:41 2008 > > @@ -43,6 +43,7 @@ > > /* Tunables */ > > int fmac_enabled = 1; /* policy enabled */ > > int fmac_enforcing = 0; /* permissive or enforcing */ > > +int fmac_authoritative = 0; /* restrictive or authoritative */ > > > > char *fmac_default_policy_file = FMAC_POLICY_FILE; > > > > @@ -78,6 +79,14 @@ > > fmac_enabled = 1; > > fmac_enforcing = 0; > > cp += sizeof ("permissive") - 1; > > + } else if (strncmp(cp, "authoritative", > > + sizeof ("authoritative")-1) == 0) { > > + fmac_authoritative = 1; > > + cp += sizeof ("authoritative") - 1; > > + } else if (strncmp(cp, "restrictive", > > + sizeof ("restrictive")-1) == 0) { > > + fmac_authoritative = 0; > > + cp += sizeof ("restrictive") - 1; > > } > > > > /* Check for additional arguments */ > > @@ -361,4 +370,84 @@ > > *prev_secidp = prev_secid; > > *secidp = secid; > > return (0); > > +} > > + > > +int > > +fmac_vnode_access(cred_t *cr, vnode_t *vp, int mode, int flags) > > +{ > > + security_id_t cr_secid; > > + security_class_t sclass; > > + access_vector_t av; > > + int error; > > + > > + if (!fmac_enabled) > > + return (0); > > + > > + cr_secid = crgetsecid(cr); > > + > > + sclass = fmac_vtype_to_sclass(vp->v_type); > > + if (!sclass) > > + return (0); > > + > > + av = 0; > > + if (mode & VREAD) > > + av |= FILE__READ; > > + if (flags & V_APPEND) > > + av |= FILE__APPEND; > > + else if (mode & VWRITE) > > + av |= FILE__WRITE; > > + if (mode & VEXEC) { > > + if (sclass == SECCLASS_DIR) > > + av |= DIR__SEARCH; > > + else > > + av |= FILE__EXECUTE; > > + } > > + > > + if (!av) > > + return (0); > > + > > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); > > +} > > + > > +int > > +fmac_vnode_priv_access(cred_t *cr, vnode_t *vp, int mode, int err) > > +{ > > + security_id_t cr_secid; > > + security_class_t sclass; > > + access_vector_t av; > > + > > + /* If not enabled, just return the legacy policy decision. */ > > + if (!fmac_enabled) > > + return (err); > > + > > + /* > > + * If the legacy policy check failed, and FMAC is either > > + * permissive or restrictive-only, then return the legacy > > + * policy decision. > > + */ > > + if (err && (!fmac_enforcing || !fmac_authoritative)) > > + return (err); > > + > > + cr_secid = crgetsecid(cr); > > + > > + sclass = fmac_vtype_to_sclass(vp->v_type); > > + if (!sclass) > > + return (err); > > + > > + av = 0; > > + if (mode & VREAD) > > + av |= FILE__PRIV_READ; > > + if (mode & VWRITE) > > + av |= FILE__PRIV_WRITE; > > + if (mode & VEXEC) { > > + if (sclass == SECCLASS_DIR) > > + av |= DIR__PRIV_SEARCH; > > + else > > + av |= FILE__PRIV_EXECUTE; > > + } > > + > > + if (!av) > > + return (err); > > + > > + return (avc_has_perm(cr_secid, vp->v_secid, sclass, av)); > > } > > --- old/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:44 2008 > > +++ new/usr/src/uts/common/fs/vnode.c Fri Sep 5 09:41:43 2008 > > @@ -3298,7 +3298,9 @@ > > > > err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); > > VOPSTATS_UPDATE(vp, access); > > - return (err); > > + if (err) > > + return (err); > > + return (fmac_vnode_access(cr, vp, mode, flags)); > > } > > > > int > > --- old/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:48 2008 > > +++ new/usr/src/uts/common/os/policy.c Fri Sep 5 09:41:47 2008 > > @@ -835,13 +835,15 @@ > > int > > secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) > > { > > + int err = 0; > > + > > if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, > > EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, > > KLPDARG_NOMORE) != 0) { > > - return (EACCES); > > + err = EACCES; > > } > > > > - if (mode & VWRITE) { > > + if (!err && (mode & VWRITE)) { > > boolean_t allzone; > > > > if (owner == 0 && cr->cr_uid != 0) > > @@ -851,11 +853,11 @@ > > if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, > > NULL, KLPDARG_VNODE, vp, (char *)NULL, > > KLPDARG_NOMORE) != 0) { > > - return (EACCES); > > + err = EACCES; > > } > > } > > > > - if (mode & VEXEC) { > > + if (!err && (mode & VEXEC)) { > > /* > > * Directories use file_dac_search to override the execute bit. > > */ > > @@ -862,10 +864,11 @@ > > int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : > > PRIV_FILE_DAC_EXECUTE; > > > > - return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, > > - KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); > > + err = priv_policy_va(cr, p, B_FALSE, EACCES, NULL, > > + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE); > > } > > - return (0); > > + > > + return (fmac_vnode_priv_access(cr, vp, mode, err)); > > } > > > > /* > > --- old/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:52 2008 > > +++ new/usr/src/uts/common/sys/fmac/fmac.h Fri Sep 5 09:41:50 2008 > > @@ -91,6 +91,8 @@ > > void fmac_vnode_post_create(vnode_t *, security_id_t); > > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > > security_id_t *prev_secidp, security_id_t *secidp); > > +int fmac_vnode_access(cred_t *, vnode_t *, int, int); > > +int fmac_vnode_priv_access(cred_t *, vnode_t *, int, int); > > #endif /* _KERNEL */ > > > > #ifdef __cplusplus > > > > -- Stephen Smalley National Security Agency From Glenn.Faden at Sun.COM Fri Sep 5 13:26:27 2008 From: Glenn.Faden at Sun.COM (Glenn Faden) Date: Fri, 05 Sep 2008 13:26:27 -0700 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <1220640609.17197.407.camel@moss-spartans.epoch.ncsc.mil> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> <48C17AD8.4060607@sun.com> <1220640609.17197.407.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C195F3.1030401@sun.com> Stephen Smalley wrote: > On Fri, 2008-09-05 at 11:30 -0700, Glenn Faden wrote: > >> Stephen Smalley wrote: >> >> This looks like a good first attempt, but I'm not sure it's correct. I'm >> concerned that it might wind up calling avc_has_perm() twice for a >> single operation. >> > > That's intentional - it is checking two different permissions (read vs. > priv_read, write vs. priv_write, etc). The first is "Can subject S > read/write/execute object O?". The second is "Can subject S override > DAC restrictions on read/write/execute on object O?". > > The equivalent in SELinux is: > "Can subject S read/write/execute object O?" > "Does subject S have dac_override capability?" > OK, but it's confusing that the FMAC permission to override DAC restrictions for read is not sufficient to actually read the vnode. The subject might need both the priv_read and priv_read_force FMAC permissions. Is this because you want to treat the authoritative and restrictive aspects of the policy independently? Won't that make writing policy even more difficult? Shouldn't priv_read_force imply priv_read? --Glenn From sds at tycho.nsa.gov Mon Sep 8 06:38:41 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 08 Sep 2008 09:38:41 -0400 Subject: [fmac-discuss] [PATCH v2] Prototype file security context support Message-ID: <1220881121.19241.24.camel@moss-spartans.epoch.ncsc.mil> Implement prototype file security context support to enable progress on developing other parts of FMAC that depend on file security contexts until system attribute support in ZFS is reworked. In the kernel, introduce support for a "secctx" system attribute, fetch this attribute for existing files on the lookup code path and map to an incore vnode secid for internal use by FMAC, and compute and set this attribute and the incore vnode secid on the create and mkdir code paths. Current limitations of this prototype support include a 56-byte maximum length for the security context, inability to use both secctx and av_scanstamp together on a file, and inability to assign a security context to file types other than regular files and directories. In userland, introduce getfilecon() and setfilecon() libc interfaces and corresponding utilities for getting and setting the file security context. Also update the setfiles utility to use the new interfaces and to deal with the current limitation to regular files and directories. Changes from the first version of the patch include: - moving the resizing of the bonus buffer into zfs_xvattr_set(), thereby fixing the setting of the attribute on new files, - fixing libc_nvlist_alloc whitespace and error return, - moved vfs_has_feature check earlier in fmac_vnode_create(), - added comments to clarify certain aspects of the code New libc interfaces: int getfilecon(const char *path, char **secctxp); int setfilecon(const char *path, char *secctx); New utilities: getfilecon path... setfilecon context path... setfiles spec-file path... Example usage: # setfilecon system_u:object_r:shadow_t /etc/shadow # getfilecon /etc/shadow /etc/shadow: system_u:object_r:shadow_t # setfiles /etc/security/fmac/file_contexts / Webrev available at: http://cr.opensolaris.org/~sds/secctx/ diff --git a/usr/src/cmd/fmac/Makefile b/usr/src/cmd/fmac/Makefile --- a/usr/src/cmd/fmac/Makefile +++ b/usr/src/cmd/fmac/Makefile @@ -32,7 +32,9 @@ loadpolicy \ setenforce \ getenforce \ - pcon + pcon \ + getfilecon \ + setfilecon SUBDIR_POLICY = \ policy diff --git a/usr/src/cmd/fmac/getfilecon/Makefile b/usr/src/cmd/fmac/getfilecon/Makefile new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/getfilecon/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +PROG= getfilecon + +include ../../Makefile.cmd + +.KEEP_STATE: + +all: $(PROG) + +install: all $(ROOTPROG) + +clean: + +lint: lint_PROG + +include ../../Makefile.targ diff --git a/usr/src/cmd/fmac/getfilecon/getfilecon.c b/usr/src/cmd/fmac/getfilecon/getfilecon.c new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/getfilecon/getfilecon.c @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Display context for specified files. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + int i, error; + char *secctx; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ +#endif + (void) textdomain(TEXT_DOMAIN); + + if (argc <= 1) { + (void) fprintf(stderr, gettext("usage: getfilecon path ...\n")); + return (1); + } + + for (i = 1; i < argc; i++) { + error = getfilecon(argv[i], &secctx); + if (error) { + (void) fprintf(stderr, + gettext("getfilecon: getting file context of %s failed: %s\n"), + argv[i], strerror(errno)); + exit(1); + } + (void) printf("%s: %s\n", argv[i], secctx); + free(secctx); + } + + return (0); +} diff --git a/usr/src/cmd/fmac/policy/Makefile b/usr/src/cmd/fmac/policy/Makefile --- a/usr/src/cmd/fmac/policy/Makefile +++ b/usr/src/cmd/fmac/policy/Makefile @@ -130,8 +130,6 @@ fs_use$(MLS_SUFFIX) \ net_contexts$(MLS_SUFFIX) -FILECONTEXT_FILE = file_contexts$(MLS_SUFFIX) - MLS_FILE = $(MLS_FLAG:yes=mls) MLS_SUFFIX = $(MLS_FLAG:yes=.mls) @@ -179,19 +177,17 @@ users.mls: users $(SED) 's/;/ ranges u;/' $^ > $@ -install: policy +install: policy file_contexts install -s -m 744 -d $(ROOT)/etc/security/fmac cp policy ss_policy install -s -m 644 -f $(ROOT)/etc/security/fmac ss_policy + install -s -m 644 -f $(ROOT)/etc/security/fmac file_contexts load: install - load_policy /ss_policy + load_policy $(ROOT)/etc/security/fmac/ss_policy -file_contexts.mls: file_contexts - $(SED) 's/_t/_t:u/g' $^ > $@ - -relabel: $(FILECONTEXT_FILE) - $(SETFILES) -v $(FILECONTEXT_FILE) `mount -p | awk '/ufs/{print $$3}; /zfs/{print $$3}'` +relabel: file_contexts + $(SETFILES) -v file_contexts `mount -p | awk '/zfs/{print $$3}'` $(TOUCH) relabel all.te: macros.te attrib.te all_types.te all_domains.te assert.te diff --git a/usr/src/cmd/fmac/setfilecon/Makefile b/usr/src/cmd/fmac/setfilecon/Makefile new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/setfilecon/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +PROG= setfilecon + +include ../../Makefile.cmd + +.KEEP_STATE: + +all: $(PROG) + +install: all $(ROOTPROG) + +clean: + +lint: lint_PROG + +include ../../Makefile.targ diff --git a/usr/src/cmd/fmac/setfilecon/setfilecon.c b/usr/src/cmd/fmac/setfilecon/setfilecon.c new file mode 100644 --- /dev/null +++ b/usr/src/cmd/fmac/setfilecon/setfilecon.c @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Set context for specified files. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + int i, error; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ +#endif + (void) textdomain(TEXT_DOMAIN); + + if (argc < 3) { + (void) fprintf(stderr, gettext("usage: %s context path...\n"), argv[0]); + exit(1); + } + + for (i = 2; i < argc; i++) { + error = setfilecon(argv[i], argv[1]); + if (error) { + (void) fprintf(stderr, + gettext("setfilecon: setting file context of %s to %s failed: %s\n"), + argv[i], argv[1], strerror(errno)); + exit(1); + } + } + return (0); +} diff --git a/usr/src/cmd/fmac/setfiles/Makefile b/usr/src/cmd/fmac/setfiles/Makefile --- a/usr/src/cmd/fmac/setfiles/Makefile +++ b/usr/src/cmd/fmac/setfiles/Makefile @@ -37,7 +37,7 @@ all: $(PROG) -install: all $(ROOTSBINPROG) +install: all $(ROOTPROG) clean: diff --git a/usr/src/cmd/fmac/setfiles/setfiles.c b/usr/src/cmd/fmac/setfiles/setfiles.c --- a/usr/src/cmd/fmac/setfiles/setfiles.c +++ b/usr/src/cmd/fmac/setfiles/setfiles.c @@ -94,37 +94,7 @@ #include #include #include -#ifdef jweeks #include -#endif - -/* jweeks - until we have library support */ -int -lgetfilecon(const char *c, char **context) -{ - *context = strdup("system_u:object_r:file_t"); - return (0); -} - -int -lsetfilecon(const char *c, const char *context) -{ - return (0); -} - -void -freecon(char *context) -{ - if (context != NULL) - free(context); -} - -int -security_check_context(const char *context) -{ - return (0); -} -/* jweeks - until we have library support */ static int add_assoc = 1; @@ -370,14 +340,6 @@ return (i); } -/* Used with qsort to sort specs from lowest to highest hasMetaChars value */ -int -spec_compare(const void* specA, const void* specB) -{ - return (((struct spec *)specB)->hasMetaChars - - ((struct spec *)specA)->hasMetaChars); -} - /* * Check for duplicate specifications. If a duplicate specification is found * and the context is the same, give a warning to the user. If a duplicate @@ -501,6 +463,14 @@ return (0); } + /* + * At present only regular files and directories can be labeled. + * XXX This needs to be fixed in the kernel. + */ + if (flag == FTW_SL || + (!S_ISDIR(sb->st_mode) && !S_ISREG(sb->st_mode))) + return (0); + i = match(my_file, &my_sb); if (i < 0) /* No matching specification. */ @@ -539,16 +509,15 @@ } /* Get the current context of the file. */ - ret = lgetfilecon(my_file, &context); + ret = getfilecon(my_file, &context); if (ret < 0) { if (errno == ENODATA) { context = malloc(10); strcpy(context, "<>"); } else { - perror(my_file); fprintf(stderr, "%s: unable to obtain attribute for " - "file %s\n", - progname, my_file); + "file %s: %s\n", + progname, my_file, strerror(errno)); return (-1); } } @@ -580,7 +549,7 @@ /* * Relabel the file to the specified context. */ - ret = lsetfilecon(my_file, spec[i].context); + ret = setfilecon(my_file, spec[i].context); if (ret) { perror(my_file); fprintf(stderr, "%s: unable to relabel %s to %s\n", @@ -599,7 +568,8 @@ char buf[255 + 1], *buf_p; char regex[256], type[256], context[256]; char *anchored_regex; - int opt, items, len, lineno, pass, nerr, regerr, i; + int opt, items, len, lineno, pass, nerr, regerr, i, j; + spec_t *spec_copy; /* Process any options. */ while ((opt = getopt(argc, argv, "dnpqvxW")) > 0) { @@ -819,8 +789,25 @@ } fclose(fp); - /* Sort the specifications with most general first */ - qsort(spec, nspec, sizeof (struct spec), spec_compare); + /* Move exact pathname specifications to the end. */ + spec_copy = malloc(sizeof (spec_t) * nspec); + if (!spec_copy) { + fprintf(stderr, + "%s: insufficient memory for specifications\n", + argv[0]); + exit(1); + } + j = 0; + for (i = 0; i < nspec; i++) { + if (spec[i].hasMetaChars) + memcpy(&spec_copy[j++], &spec[i], sizeof (spec_t)); + } + for (i = 0; i < nspec; i++) { + if (!spec[i].hasMetaChars) + memcpy(&spec_copy[j++], &spec[i], sizeof (spec_t)); + } + free(spec); + spec = spec_copy; /* Verify no exact duplicates */ if (nodups_specs() != 0) { diff --git a/usr/src/common/fmac/ss/services.c b/usr/src/common/fmac/ss/services.c --- a/usr/src/common/fmac/ss/services.c +++ b/usr/src/common/fmac/ss/services.c @@ -502,9 +502,6 @@ return (0); } } - (void) printf("security_context_to_sid: called before initial " - "load_policy on unknown context %s\n", - scontext); return (EINVAL); } *sid = SECSID_NULL; diff --git a/usr/src/common/xattr/xattr_common.c b/usr/src/common/xattr/xattr_common.c --- a/usr/src/common/xattr/xattr_common.c +++ b/usr/src/common/xattr/xattr_common.c @@ -63,6 +63,7 @@ { A_OWNERSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST }, { A_GROUPSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST }, { A_FSID, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT64 }, + { A_SECCTX, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_STRING }, }; const char * diff --git a/usr/src/head/fmac/fmac.h b/usr/src/head/fmac/fmac.h --- a/usr/src/head/fmac/fmac.h +++ b/usr/src/head/fmac/fmac.h @@ -55,7 +55,8 @@ int setexeccon(security_context_t context); int getprevcon(security_context_t *context); void freecon(security_context_t context); - +int getfilecon(const char *path, char **secctxp); +int setfilecon(const char *path, char *secctx); #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -107,6 +107,7 @@ cuexit.o \ ecvt.o \ errlst.o \ + filecon.o \ amd64_data.o \ ldivide.o \ lock.o \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -426,6 +426,7 @@ fattach.o \ fdetach.o \ fdopendir.o \ + filecon.o \ fmtmsg.o \ ftime.o \ ftok.o \ diff --git a/usr/src/lib/libc/inc/libc.h b/usr/src/lib/libc/inc/libc.h --- a/usr/src/lib/libc/inc/libc.h +++ b/usr/src/lib/libc/inc/libc.h @@ -72,8 +72,11 @@ extern void callout_lock_exit(void); extern void *lmalloc(size_t); extern void lfree(void *, size_t); +extern int libc_nvlist_alloc(nvlist_t **,uint_t, int); extern void libc_nvlist_free(nvlist_t *); extern int libc_nvlist_lookup_uint64(nvlist_t *, const char *, uint64_t *); +extern int libc_nvlist_lookup_string(nvlist_t *, const char *, char **); +extern int libc_nvlist_add_string(nvlist_t *, const char *, const char *); extern void *libc_malloc(size_t); extern void *libc_realloc(void *, size_t); extern void libc_free(void *); diff --git a/usr/src/lib/libc/port/gen/attrat.c b/usr/src/lib/libc/port/gen/attrat.c --- a/usr/src/lib/libc/port/gen/attrat.c +++ b/usr/src/lib/libc/port/gen/attrat.c @@ -44,8 +44,11 @@ static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int); static int (*nvsize)(nvlist_t *, size_t *, int); static int (*nvunpacker)(char *, size_t, nvlist_t **); +static int (*nvalloc)(nvlist_t **, uint_t, int); static int (*nvfree)(nvlist_t *); static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *); +static int (*nvlookupstring)(nvlist_t *, const char *, char **); +static int (*nvaddstring)(nvlist_t *, const char *, const char *); static mutex_t attrlock = DEFAULTMUTEX; static int initialized; @@ -62,8 +65,11 @@ void *packer; void *sizer; void *unpacker; + void *allocer; void *freer; void *looker; + void *lookupstr; + void *addstr; if (initialized == 0) { void *handle = dlopen("libnvpair.so.1", RTLD_LAZY); @@ -72,8 +78,12 @@ (packer = dlsym(handle, "nvlist_pack")) == NULL || (sizer = dlsym(handle, "nvlist_size")) == NULL || (unpacker = dlsym(handle, "nvlist_unpack")) == NULL || + (allocer = dlsym(handle, "nvlist_alloc")) == NULL || (freer = dlsym(handle, "nvlist_free")) == NULL || - (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) { + (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL || + (lookupstr = dlsym(handle, "nvlist_lookup_string")) + == NULL || + (addstr = dlsym(handle, "nvlist_add_string")) == NULL) { if (handle) dlclose(handle); return (-1); @@ -93,10 +103,16 @@ sizer; nvunpacker = (int (*)(char *, size_t, nvlist_t **)) unpacker; + nvalloc = (int (*)(nvlist_t **, uint_t, int)) + allocer; nvfree = (int (*)(nvlist_t *)) freer; nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *)) looker; + nvlookupstring = (int (*)(nvlist_t *, const char *, char **)) + lookupstr; + nvaddstring = (int (*)(nvlist_t *, const char *, const char *)) + addstr; membar_producer(); initialized = 1; @@ -303,6 +319,15 @@ return (error); } +int +libc_nvlist_alloc(nvlist_t **nvp, uint_t nvflag, int flag) +{ + if (attrat_init()) + return (errno ? errno : EINVAL); + + return (nvalloc(nvp, nvflag, flag)); +} + void libc_nvlist_free(nvlist_t *nvp) { @@ -314,3 +339,15 @@ { return (nvlookupint64(nvp, name, value)); } + +int +libc_nvlist_lookup_string(nvlist_t *nvp, const char *name, char **value) +{ + return (nvlookupstring(nvp, name, value)); +} + +int +libc_nvlist_add_string(nvlist_t *nvp, const char *name, const char *value) +{ + return (nvaddstring(nvp, name, value)); +} diff --git a/usr/src/lib/libc/port/gen/filecon.c b/usr/src/lib/libc/port/gen/filecon.c new file mode 100644 --- /dev/null +++ b/usr/src/lib/libc/port/gen/filecon.c @@ -0,0 +1,90 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma weak _getfilecon = getfilecon +#pragma weak _setfilecon = setfilecon + +#include "lint.h" +#include "libc.h" +#include +#include +#include +#include +#include +#include +#include + +#ifndef A_SECCTX +#define A_SECCTX "secctx" +#endif + +int +getfilecon(const char *path, char **secctxp) +{ + nvlist_t *nvp; + int error; + char *secctx; + + error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, path, &nvp); + if (error) + return (-1); + error = libc_nvlist_lookup_string(nvp, A_SECCTX, &secctx); + if (error) { + errno = ENODATA; + libc_nvlist_free(nvp); + return (-1); + } + *secctxp = strdup(secctx); + libc_nvlist_free(nvp); + if (!(*secctxp)) + return (-1); + return (0); +} + +int +setfilecon(const char *path, char *secctx) +{ + nvlist_t *nvp; + int error; + + error = libc_nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0); + if (error) { + errno = error; + return (-1); + } + + error = libc_nvlist_add_string(nvp, A_SECCTX, secctx); + if (error) { + errno = error; + error = -1; + goto out; + } + + error = setattrat(AT_FDCWD, XATTR_VIEW_READWRITE, path, nvp); +out: + libc_nvlist_free(nvp); + return (error); +} diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -82,6 +82,7 @@ getattrat; getcon; getexeccon; + getfilecon; getpagesizes2; getpidcon; getprevcon; @@ -137,6 +138,7 @@ sem_wait; setattrat; setexeccon; + setfilecon; _sharefs; shm_open; shm_unlink; diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile --- a/usr/src/lib/libc/sparc/Makefile +++ b/usr/src/lib/libc/sparc/Makefile @@ -450,6 +450,7 @@ fattach.o \ fdetach.o \ fdopendir.o \ + filecon.o \ fmtmsg.o \ ftime.o \ ftok.o \ diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile --- a/usr/src/lib/libc/sparcv9/Makefile +++ b/usr/src/lib/libc/sparcv9/Makefile @@ -411,6 +411,7 @@ fattach.o \ fdetach.o \ fdopendir.o \ + filecon.o \ fmtmsg.o \ ftime.o \ ftok.o \ diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -286,6 +286,7 @@ f none etc/security/dev/st1 400 root bin d none etc/security/fmac 755 root bin f none etc/security/fmac/ss_policy 644 root sys +f none etc/security/fmac/file_contexts 644 root sys f none etc/security/kmfpolicy.xml 644 root bin d none etc/security/lib 755 root sys f none etc/security/lib/audio_clean 555 root sys diff --git a/usr/src/pkgdefs/SUNWesu/prototype_com b/usr/src/pkgdefs/SUNWesu/prototype_com --- a/usr/src/pkgdefs/SUNWesu/prototype_com +++ b/usr/src/pkgdefs/SUNWesu/prototype_com @@ -66,6 +66,7 @@ f none usr/bin/dos2unix 555 root bin f none usr/bin/expand 555 root bin f none usr/bin/factor 555 root bin +f none usr/bin/getfilecon 555 root bin f none usr/bin/graph 555 root bin f none usr/bin/kstat 555 root bin f none usr/bin/last 555 root bin @@ -103,6 +104,8 @@ l none usr/bin/pwait=../../usr/lib/isaexec l none usr/bin/pwdx=../../usr/lib/isaexec f none usr/bin/sdiff 555 root bin +f none usr/bin/setfilecon 555 root bin +f none usr/bin/setfiles 555 root bin l none usr/bin/sort=../../usr/lib/isaexec f none usr/bin/spell 555 root bin f none usr/bin/spline 555 root bin diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -34,8 +34,11 @@ #include #include #include +#include #include #include +#include +#include /* Tunables */ int fmac_enabled = 1; /* policy enabled */ @@ -125,3 +128,194 @@ return (0); } + +security_class_t +fmac_vtype_to_sclass(vtype_t vtype) +{ + switch (vtype) { + case VREG: + return (SECCLASS_FILE); + case VDIR: + return (SECCLASS_DIR); + case VBLK: + return (SECCLASS_BLK_FILE); + case VCHR: + return (SECCLASS_CHR_FILE); + case VLNK: + return (SECCLASS_LNK_FILE); + case VFIFO: + return (SECCLASS_FIFO_FILE); + case VSOCK: + return (SECCLASS_SOCK_FILE); + case VDOOR: + /* TBD */ + case VPROC: + /* TBD */ + case VPORT: + /* TBD */ + case VNON: + return (SECCLASS_NULL); + } + return (SECCLASS_NULL); +} + +int +fmac_vnode_lookup(vnode_t *vp, cred_t *cr, caller_context_t *ct) +{ + int error; + xvattr_t xvattr; + xoptattr_t *xoap; + security_id_t secid; + + if (!fmac_enabled) + return (0); + if (vp->v_secid != SECINITSID_UNLABELED) + return (0); /* already set */ + + xva_init(&xvattr); + if ((xoap = xva_getxoptattr(&xvattr)) == NULL) + return (EINVAL); + XVA_SET_REQ(&xvattr, XAT_SECCTX); + + error = VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct); + if (error) + return (error); + + if (XVA_ISSET_RTN(&xvattr, XAT_SECCTX)) { + error = security_context_to_sid(xoap->xoa_secctx, + strlen(xoap->xoa_secctx), &secid); + if (error) + return (error); + } else { + /* default SID for files without a secctx. */ + secid = SECINITSID_FILE; + } + + mutex_enter(&(vp->v_lock)); + if (vp->v_secid == SECINITSID_UNLABELED) + vp->v_secid = secid; + mutex_exit(&(vp->v_lock)); + + return (0); +} + +int +fmac_vnode_set_secctx(char *secctx, cred_t *cr, vtype_t vtype, vnode_t *vp) +{ + security_id_t cr_secid, old_secid, new_secid; + security_class_t sclass; + int error; + + if (!fmac_enabled) + return (EINVAL); + + cr_secid = crgetsecid(cr); + + sclass = fmac_vtype_to_sclass(vtype); + if (!sclass) + return (EINVAL); + + error = security_context_to_sid(secctx, strlen(secctx), &new_secid); + if (error) + return (error); + + if (vp) { + /* + * Relabeling an existing file. + */ + mutex_enter(&(vp->v_lock)); + old_secid = vp->v_secid; + error = avc_has_perm(cr_secid, old_secid, sclass, + FILE__RELABELFROM); + if (!error) + error = avc_has_perm(cr_secid, new_secid, sclass, + FILE__RELABELTO); + vp->v_secid = new_secid; + mutex_exit(&(vp->v_lock)); + } else { + /* Creating a new file. */ + error = avc_has_perm(cr_secid, new_secid, sclass, + FILE__CREATE); + } + + return (error); +} + +int +fmac_vnode_create(vnode_t *dvp, char *name, xvattr_t *xvap, vattr_t **vapp, + cred_t *cr, security_id_t *secidp) +{ + security_id_t cr_secid, secid; + security_class_t sclass; + security_context_t scontext; + uint32_t scontext_len; + xoptattr_t *xoap; + int error; + + _NOTE(ARGUNUSED(name)); /* future use in audit message */ + + if (!fmac_enabled) + return (0); + + /* + * Make sure we define a default secid for use by + * fmac_vnode_post_create even if the fs does not + * support xvattrs. + */ + *secidp = SECINITSID_FILE; + + if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR) == 0) + return (0); + + sclass = fmac_vtype_to_sclass((*vapp)->va_type); + if (!sclass) + return (0); + + cr_secid = crgetsecid(cr); + + /* + * Wrap the vattr with an xvattr so we can pass the + * secctx to the fs code. + */ + xva_init(xvap); + (void) memcpy(&xvap->xva_vattr, *vapp, sizeof (vattr_t)); + xvap->xva_vattr.va_mask |= AT_XVATTR; /* reset after memcpy */ + XVA_SET_REQ(xvap, XAT_SECCTX); + + error = security_transition_sid(cr_secid, dvp->v_secid, sclass, + &secid); + if (error) + return (error); + + error = security_sid_to_context(secid, &scontext, &scontext_len); + if (error) + return (error); + + if (scontext_len > sizeof (xoap->xoa_secctx)) + return (EINVAL); + + xoap = xva_getxoptattr(xvap); + if (!xoap) + return (EINVAL); + (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx)); + + *secidp = secid; + + /* + * Switch the vap pointer to the newly populated xvattr. + * fop_create/fop_mkdir will then pass the xvattr along to + * the underlying fs code. The original vattr is not mutated. + */ + *vapp = &xvap->xva_vattr; + return (0); +} + +void +fmac_vnode_post_create(vnode_t *vp, security_id_t secid) +{ + if (!fmac_enabled) + return; + mutex_enter(&(vp->v_lock)); + vp->v_secid = secid; + mutex_exit(&(vp->v_lock)); +} diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include #include #include @@ -2309,6 +2311,7 @@ vp->v_flag = 0; vp->v_type = VNON; vp->v_rdev = NODEV; + vp->v_secid = SECINITSID_UNLABELED; vp->v_filocks = NULL; vp->v_shrlocks = NULL; @@ -3333,6 +3336,7 @@ (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp); } if (ret == 0 && *vpp) { + (void) fmac_vnode_lookup(*vpp, cr, ct); VOPSTATS_UPDATE(*vpp, lookup); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, nm, strlen(nm)); @@ -3356,6 +3360,8 @@ vsecattr_t *vsecp) /* ACL to set during create */ { int ret; + xvattr_t xvattr; + security_id_t secid; if (vsecp != NULL && vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) { @@ -3369,12 +3375,17 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) return (EINVAL); + + ret = fmac_vnode_create(dvp, name, &xvattr, &vap, cr, &secid); + if (ret) + return (ret); VOPXID_MAP_CR(dvp, cr); ret = (*(dvp)->v_op->vop_create) (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp); if (ret == 0 && *vpp) { + fmac_vnode_post_create(*vpp, secid); VOPSTATS_UPDATE(*vpp, create); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, name, strlen(name)); @@ -3477,6 +3488,8 @@ int flags, vsecattr_t *vsecp) /* ACL to set during create */ { + xvattr_t xvattr; + security_id_t secid; int ret; if (vsecp != NULL && @@ -3491,12 +3504,17 @@ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) return (EINVAL); + + ret = fmac_vnode_create(dvp, dirname, &xvattr, &vap, cr, &secid); + if (ret) + return (ret); VOPXID_MAP_CR(dvp, cr); ret = (*(dvp)->v_op->vop_mkdir) (dvp, dirname, vap, vpp, cr, ct, flags, vsecp); if (ret == 0 && *vpp) { + fmac_vnode_post_create(*vpp, secid); VOPSTATS_UPDATE(*vpp, mkdir); if ((*vpp)->v_path == NULL) { vn_setpath(rootdir, dvp, *vpp, dirname, diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c --- a/usr/src/uts/common/fs/xattr.c +++ b/usr/src/uts/common/fs/xattr.c @@ -214,6 +214,9 @@ VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr), fsid) == 0); break; + case F_SECCTX: + XVA_SET_REQ(&xvattr, XAT_SECCTX); + break; default: break; } @@ -288,6 +291,11 @@ attr_to_name(F_AV_SCANSTAMP), xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp)) == 0); + } + if (XVA_ISSET_RTN(&xvattr, XAT_SECCTX)) { + VERIFY(nvlist_add_string(nvlp, + attr_to_name(F_SECCTX), + xoap->xoa_secctx) == 0); } if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) { VERIFY(nvlist_add_uint64_array(nvlp, @@ -511,6 +519,7 @@ uint_t elem, nelems; nvlist_t *nvp_sid; uint8_t *scanstamp; + char *secctx = NULL; /* * Validate the name and type of each attribute. @@ -569,6 +578,12 @@ case DATA_TYPE_UINT8_ARRAY: if (nvpair_value_uint8_array(pair, &scanstamp, &nelems)) { + nvlist_free(nvp); + return (EINVAL); + } + break; + case DATA_TYPE_STRING: + if (nvpair_value_string(pair, &secctx)) { nvlist_free(nvp); return (EINVAL); } @@ -665,6 +680,16 @@ nvlist_free(nvp); return (EINVAL); } + break; + case F_SECCTX: + if (!secctx || + strlen(secctx) >= sizeof (xoap->xoa_secctx)) { + nvlist_free(nvp); + return (EINVAL); + } + XVA_SET_REQ(&xvattr, XAT_SECCTX); + (void) strncpy(xoap->xoa_secctx, secctx, + sizeof (xoap->xoa_secctx)); break; default: break; diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h --- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h @@ -77,6 +77,7 @@ #define ZFS_ACL_DEFAULTED 0x20 /* ACL should be defaulted */ #define ZFS_ACL_AUTO_INHERIT 0x40 /* ACL should be inherited */ #define ZFS_BONUS_SCANSTAMP 0x80 /* Scanstamp in bonus area */ +#define ZFS_BONUS_SECCTX 0x100 /* Secctx in bonus area */ /* * Is ID ephemeral? @@ -159,6 +160,7 @@ * At present, we use this space for the following: * - symbolic links * - 32-byte anti-virus scanstamp (regular files only) + * - security context */ } znode_phys_t; @@ -333,7 +335,7 @@ znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp); extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp, vsecattr_t *vsecp, zfs_fuid_info_t *fuidp); -extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap); +extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx); extern void zfs_upgrade(zfsvfs_t *zfsvfs, dmu_tx_t *tx); extern caddr_t zfs_map_page(page_t *, enum seg_rw); diff --git a/usr/src/uts/common/fs/zfs/sys/zil.h b/usr/src/uts/common/fs/zfs/sys/zil.h --- a/usr/src/uts/common/fs/zfs/sys/zil.h +++ b/usr/src/uts/common/fs/zfs/sys/zil.h @@ -98,13 +98,13 @@ * size of xvattr log section. * its composed of lr_attr_t + xvattr bitmap + 2 64 bit timestamps * for create time and a single 64 bit integer for all of the attributes, - * and 4 64 bit integers (32 bytes) for the scanstamp. - * + * and either 4 64 bit integers (32 bytes) for the scanstamp or + * 56 bytes for the security context. */ #define ZIL_XVAT_SIZE(mapsize) \ sizeof (lr_attr_t) + (sizeof (uint32_t) * (mapsize - 1)) + \ - (sizeof (uint64_t) * 7) + (sizeof (uint64_t) * 7) + 24 /* * Size of ACL in log. The ACE data is padded out to properly align diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -1868,7 +1868,7 @@ /* Set optional attributes if any */ if (vap->va_mask & AT_XVATTR) - zfs_xvattr_set(zp, xvap); + zfs_xvattr_set(zp, xvap, tx); mutex_exit(&zp->z_lock); mutex_exit(&zp->z_acl_lock); diff --git a/usr/src/uts/common/fs/zfs/zfs_log.c b/usr/src/uts/common/fs/zfs/zfs_log.c --- a/usr/src/uts/common/fs/zfs/zfs_log.c +++ b/usr/src/uts/common/fs/zfs/zfs_log.c @@ -101,7 +101,7 @@ uint64_t *attrs; uint64_t *crtime; xoptattr_t *xoap; - void *scanstamp; + void *extradata; /* scanstamp or secctx */ int i; xoap = xva_getxoptattr(xvap); @@ -116,7 +116,7 @@ /* Now pack the attributes up in a single uint64_t */ attrs = (uint64_t *)bitmap; crtime = attrs + 1; - scanstamp = (caddr_t)(crtime + 2); + extradata = (caddr_t)(crtime + 2); *attrs = 0; if (XVA_ISSET_REQ(xvap, XAT_READONLY)) *attrs |= (xoap->xoa_readonly == 0) ? 0 : @@ -154,7 +154,9 @@ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime); if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) - bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ); + bcopy(xoap->xoa_av_scanstamp, extradata, AV_SCANSTAMP_SZ); + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) + bcopy(xoap->xoa_secctx, extradata, SECCTX_SZ); } static void * diff --git a/usr/src/uts/common/fs/zfs/zfs_replay.c b/usr/src/uts/common/fs/zfs/zfs_replay.c --- a/usr/src/uts/common/fs/zfs/zfs_replay.c +++ b/usr/src/uts/common/fs/zfs/zfs_replay.c @@ -83,7 +83,7 @@ uint64_t *attrs; uint64_t *crtime; uint32_t *bitmap; - void *scanstamp; + void *extradata; /* scanstamp or secctx */ int i; xvap->xva_vattr.va_mask |= AT_XVATTR; @@ -100,7 +100,7 @@ attrs = (uint64_t *)(lrattr + lrattr->lr_attr_masksize - 1); crtime = attrs + 1; - scanstamp = (caddr_t)(crtime + 2); + extradata = (caddr_t)(crtime + 2); if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) xoap->xoa_hidden = ((*attrs & XAT0_HIDDEN) != 0); @@ -128,7 +128,9 @@ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime); if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) - bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); + bcopy(extradata, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) + bcopy(extradata, xoap->xoa_secctx, SECCTX_SZ); } static int diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -1182,7 +1182,7 @@ if (vap->va_mask & AT_XVATTR) { if ((error = secpolicy_xvattr((xvattr_t *)vap, - crgetuid(cr), cr, vap->va_type)) != 0) { + crgetuid(cr), cr, vap->va_type, NULL)) != 0) { ZFS_EXIT(zfsvfs); return (error); } @@ -1637,7 +1637,7 @@ if (vap->va_mask & AT_XVATTR) if ((error = secpolicy_xvattr((xvattr_t *)vap, - crgetuid(cr), cr, vap->va_type)) != 0) { + crgetuid(cr), cr, vap->va_type, NULL)) != 0) { ZFS_EXIT(zfsvfs); return (error); } @@ -2316,6 +2316,28 @@ pzp + 1, sizeof (xoap->xoa_av_scanstamp)); XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); + } + } + + if (XVA_ISSET_REQ(xvap, XAT_SECCTX) && + vp->v_type != VLNK && + (pzp->zp_flags & ZFS_BONUS_SECCTX)) { + size_t len = 0; + dmu_object_info_t doi; + + dmu_object_info_from_db(zp->z_dbuf, &doi); + len = sizeof (xoap->xoa_secctx) + + sizeof (znode_phys_t); + if (len <= doi.doi_bonus_size) { + /* + * pzp points to the start of the + * znode_phys_t. pzp + 1 points to the + * first byte after the znode_phys_t. + */ + (void) memcpy(xoap->xoa_secctx, + pzp + 1, + sizeof (xoap->xoa_secctx)); + XVA_SET_RTN(xvap, XAT_SECCTX); } } @@ -2570,6 +2592,7 @@ xoap->xoa_av_quarantined != ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)))) || (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) || + (XVA_ISSET_REQ(xvap, XAT_SECCTX)) || (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { need_policy = TRUE; } @@ -2762,22 +2785,8 @@ * update from toggling bit */ - if (xoap && (mask & AT_XVATTR)) { - if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { - size_t len; - dmu_object_info_t doi; - - ASSERT(vp->v_type == VREG); - - /* Grow the bonus buffer if necessary. */ - dmu_object_info_from_db(zp->z_dbuf, &doi); - len = sizeof (xoap->xoa_av_scanstamp) + - sizeof (znode_phys_t); - if (len > doi.doi_bonus_size) - VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); - } - zfs_xvattr_set(zp, xvap); - } + if (xoap && (mask & AT_XVATTR)) + zfs_xvattr_set(zp, xvap, tx); if (mask != 0) zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp); diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c --- a/usr/src/uts/common/fs/zfs/zfs_znode.c +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c @@ -851,9 +851,16 @@ } void -zfs_xvattr_set(znode_t *zp, xvattr_t *xvap) +zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx) { xoptattr_t *xoap; + size_t len; + dmu_object_info_t doi; + vnode_t *vp; + znode_phys_t *pzp; + + vp = ZTOV(zp); + pzp = zp->z_phys; xoap = xva_getxoptattr(xvap); ASSERT(xoap); @@ -907,11 +914,51 @@ ZFS_ATTR_SET(zp, ZFS_AV_MODIFIED, xoap->xoa_av_modified); XVA_SET_RTN(xvap, XAT_AV_MODIFIED); } + if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) && + XVA_ISSET_REQ(xvap, XAT_SECCTX)) { + /* + * The av scanstamp and the secctx are presently + * exclusive of one another as they are both stored + * in the bonus buffer. + */ + return; + } if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { + ASSERT(vp->v_type == VREG); + + /* Don't allow a secctx to be overwritten by a scanstamp. */ + if (pzp->zp_flags & ZFS_BONUS_SECCTX) + return; + + /* Grow the bonus buffer if necessary. */ + dmu_object_info_from_db(zp->z_dbuf, &doi); + len = sizeof (xoap->xoa_av_scanstamp) + + sizeof (znode_phys_t); + if (len > doi.doi_bonus_size) + VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); + (void) memcpy(zp->z_phys + 1, xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp)); zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP; XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); + } + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) { + ASSERT(vp->v_type != VLNK); + + /* Don't allow a scanstamp to be overwritten by a secctx. */ + if (pzp->zp_flags & ZFS_BONUS_SCANSTAMP) + return; + + /* Grow the bonus buffer if necessary. */ + dmu_object_info_from_db(zp->z_dbuf, &doi); + len = sizeof (xoap->xoa_secctx) + + sizeof (znode_phys_t); + if (len > doi.doi_bonus_size) + VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); + (void) memcpy(zp->z_phys + 1, xoap->xoa_secctx, + sizeof (xoap->xoa_secctx)); + zp->z_phys->zp_flags |= ZFS_BONUS_SECCTX; + XVA_SET_RTN(xvap, XAT_SECCTX); } } diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1060,7 +1061,8 @@ * Check privileges for setting xvattr attributes */ int -secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) +secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype, + vnode_t *vp /* NULL on create */) { xoptattr_t *xoap; int error = 0; @@ -1112,6 +1114,12 @@ xoap->xoa_av_scanstamp, cr); if (error == 0 && vtype != VREG) error = EINVAL; + } + if (error == 0 && XVA_ISSET_REQ(xvap, XAT_SECCTX)) { + error = secpolicy_vnode_owner(cr, owner); + if (!error) + error = fmac_vnode_set_secctx(xoap->xoa_secctx, cr, + vtype, vp); } return (error); } @@ -1268,7 +1276,7 @@ */ if (mask & AT_XVATTR) error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr, - vp->v_type); + vp->v_type, vp); out: return (error); } diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h --- a/usr/src/uts/common/sys/attr.h +++ b/usr/src/uts/common/sys/attr.h @@ -56,6 +56,7 @@ #define A_AV_SCANSTAMP "av_scanstamp" #define A_OWNERSID "ownersid" #define A_GROUPSID "groupsid" +#define A_SECCTX "secctx" /* Attribute option for utilities */ #define O_HIDDEN "H" @@ -92,6 +93,7 @@ F_OWNERSID, F_GROUPSID, F_FSID, + F_SECCTX, F_ATTR_ALL } f_attr_t; diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -33,6 +33,7 @@ #if defined(_KERNEL) #include +#include #else #include #endif /* _KERNEL */ @@ -83,6 +84,11 @@ extern char *fmac_default_policy_file; void fmac_init(void); int fmac_load_policy(char *file); +int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); +int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *); +int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, + security_id_t *); +void fmac_vnode_post_create(vnode_t *, security_id_t); #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h --- a/usr/src/uts/common/sys/policy.h +++ b/usr/src/uts/common/sys/policy.h @@ -32,6 +32,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -160,7 +161,7 @@ void secpolicy_fs_mount_clearopts(cred_t *, struct vfs *); int secpolicy_setid_setsticky_clear(vnode_t *, vattr_t *, const vattr_t *, cred_t *); -int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t); +int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t, vnode_t *); int secpolicy_xvm_control(const cred_t *); int secpolicy_basic_exec(const cred_t *, vnode_t *); diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h --- a/usr/src/uts/common/sys/vnode.h +++ b/usr/src/uts/common/sys/vnode.h @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef _KERNEL #include #endif /* _KERNEL */ @@ -195,6 +196,7 @@ * v_path * v_vsd * v_xattrdir + * v_secid * * A special lock (implemented by vn_vfswlock in vnode.c) protects: * v_vfsmountedhere @@ -233,6 +235,7 @@ struct stdata *v_stream; /* associated stream */ enum vtype v_type; /* vnode type */ dev_t v_rdev; /* device (VCHR, VBLK) */ + security_id_t v_secid; /* FMAC security identifier */ /* PRIVATE FIELDS BELOW - DO NOT USE */ @@ -364,6 +367,8 @@ } vattr_t; #define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */ +#define SECCTX_SZ 56 /* length of secctx */ +/* XXX: This should be variable sized and support large sizes. TBD. */ /* * Structure of all optional attributes. @@ -382,6 +387,7 @@ uint8_t xoa_av_quarantined; uint8_t xoa_av_modified; uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ]; + char xoa_secctx[SECCTX_SZ]; } xoptattr_t; /* @@ -560,11 +566,12 @@ #define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */ #define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */ #define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */ +#define XAT0_SECCTX 0x00002000 /* security context */ #define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \ XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \ XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| \ - XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP) + XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP|XAT0_SECCTX) /* Support for XAT_* optional attributes */ #define XVA_MASK 0xffffffff /* Used to mask off 32 bits */ @@ -597,6 +604,7 @@ #define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED) #define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED) #define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP) +#define XAT_SECCTX ((XAT0_INDEX << XVA_SHFT) | XAT0_SECCTX) /* * The returned attribute map array (xva_rtnattrmap[]) is located past the -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Mon Sep 8 06:58:54 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 08 Sep 2008 09:58:54 -0400 Subject: [fmac-discuss] [PATCH v2] Basic process security context transition support Message-ID: <1220882334.19241.38.camel@moss-spartans.epoch.ncsc.mil> Implement basic process security context transition support, leveraging the prior patch for file security contexts on executables. With this support and a suitable labeled filesystem and policy, processes will automatically transition into an appropriate security context when they execute a program based on the program file's security context, and a process may explicitly transition to a given security context if authorized via the already existing setexeccon() interface. This only implements the core logic for a transition; a number of other checks will be added later, such as a check to decide whether the linker security flag needs to be set on the transition, ptrace-related checking, checks on the inheritance of state such as open file descriptors, the normal file execute check applied via VOP_ACCESS, mmap/mprotect PROT_EXEC checks, etc. The checks applied here are: - If not transitioning, may the process execute the file without transitioning to a new security context (:file execute_no_trans)? - If transitioning, may the process transition to the new security context (:process transition) and may the new process security context be entered via a program with this file security context (:file entrypoint)? Changes since the prior version of this patch include: - setsecid changed from int to boolean_t, with B_TRUE and B_FALSE as values. Webrev available at: http://cr.opensolaris.org/~sds/exec/ diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -319,3 +319,46 @@ vp->v_secid = secid; mutex_exit(&(vp->v_lock)); } + +int +fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, + security_id_t *prev_secidp, security_id_t *secidp) +{ + security_id_t prev_secid, secid; + int error; + + if (!fmac_enabled) + return (0); + + prev_secid = crgetsecid(cr); + secid = crgetexecsecid(cr); + if (!secid) { + error = security_transition_sid(prev_secid, vp->v_secid, + SECCLASS_PROCESS, &secid); + if (error) + return (error); + } + + if (prev_secid == secid) { + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, + FILE__EXECUTE_NO_TRANS); + if (error) + return (error); + *setsecid = B_FALSE; + return (0); + } + + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, + PROCESS__TRANSITION); + if (error) + return (error); + + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, + FILE__ENTRYPOINT); + if (error) + return (error); + *setsecid = B_TRUE; + *prev_secidp = prev_secid; + *secidp = secid; + return (0); +} diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -68,6 +68,7 @@ #include #include #include +#include #include @@ -522,6 +523,8 @@ int suidflags = 0; ssize_t resid; uid_t uid, gid; + security_id_t prev_secid, secid; + boolean_t setsecid = B_FALSE; struct vattr vattr; char magbuf[MAGIC_BYTES]; int setid; @@ -562,10 +565,25 @@ if ((eswp = findexec_by_hdr(magbuf)) == NULL) goto bad; - if (level == 0 && - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { + if (level == 0) { + privflags = execsetid(vp, &vattr, &uid, &gid); + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); + if (error) + goto bad; + + if (setsecid) + privflags |= PRIV_SETUGID; + } + + if (level == 0 && privflags != 0) { newcred = cred = crdup(cred); + + if (setsecid) { + cred->cr_prev_secid = prev_secid; + cred->cr_secid = secid; + cred->cr_exec_secid = SECSID_NULL; + } /* If we can, drop the PA bit */ if ((privflags & PRIV_RESET) != 0) diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -89,6 +89,8 @@ int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, security_id_t *); void fmac_vnode_post_create(vnode_t *, security_id_t); +int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, + security_id_t *prev_secidp, security_id_t *secidp); #endif /* _KERNEL */ #ifdef __cplusplus -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Mon Sep 8 06:59:54 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 08 Sep 2008 09:59:54 -0400 Subject: [fmac-discuss] [PATCH] File contexts and policy changes In-Reply-To: <1220465214.6034.168.camel@moss-spartans.epoch.ncsc.mil> References: <1220465214.6034.168.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <1220882394.19241.40.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-03 at 14:06 -0400, Stephen Smalley wrote: > This patch updates the file contexts and policy configurations to allow > the preceding prototype file security context support and basic security > context transition support to be demonstrated. After applying all three > patches, one can do the following: > # Label filesystems > $ setfiles /etc/security/fmac/file_contexts / > $ getfilecon /sbin/init /usr/lib/ssh/sshd /bin/bash > /sbin/init: system_u:object_r:init_exec_t > /usr/lib/ssh/sshd: system_u:object_r:sshd_exec_t > /bin/bash: system_u:object_r:shell_exec_t > $ reboot > and then upon logging into the system via ssh, the processes should have > typical domains for the user shell, sshd daemon, and init processes: > $ pcon $$ $PPID 1 > : system_u:system_r:user_t:unclassified > : system_u:system_r:sshd_t:unclassified > 1: system_u:system_r:init_t:unclassified > > Webrev available at: http://cr.opensolaris.org/~sds/policy/ This patch is unchanged from before; please apply the original. > > diff --git a/usr/src/cmd/fmac/policy/assert.te b/usr/src/cmd/fmac/policy/assert.te > --- a/usr/src/cmd/fmac/policy/assert.te > +++ b/usr/src/cmd/fmac/policy/assert.te > @@ -77,9 +77,8 @@ > # Verify that the authentication domains are the only other domains > # that can read this file. > # > -neverallow ~{ admin passwd_t } etc_auth_t:dir { add_name remove_name rename }; > -neverallow ~{ admin passwd_t } etc_auth_t:file { write append unlink rename }; > -neverallow ~{ admin auth } etc_auth_t:file { read }; > +neverallow ~{ admin passwd_t } shadow_t:file { write append unlink rename }; > +neverallow ~{ admin auth } shadow_t:file { read }; > > # > # Verify that only the administrator domain and the > diff --git a/usr/src/cmd/fmac/policy/domains/every.te b/usr/src/cmd/fmac/policy/domains/every.te > --- a/usr/src/cmd/fmac/policy/domains/every.te > +++ b/usr/src/cmd/fmac/policy/domains/every.te > @@ -179,7 +179,7 @@ > # Inherit and use descriptors from login. > allow domain local_login_t:fd inherit_fd_perms; > allow domain remote_login_t:fd inherit_fd_perms; > -allow domain sshd_login_t:fd inherit_fd_perms; > +allow domain sshd_t:fd inherit_fd_perms; > > # Create and use NFS files. > # FIXME! Only grant to domains that truly need this access. > diff --git a/usr/src/cmd/fmac/policy/domains/program/newrole.te b/usr/src/cmd/fmac/policy/domains/program/newrole.te > --- a/usr/src/cmd/fmac/policy/domains/program/newrole.te > +++ b/usr/src/cmd/fmac/policy/domains/program/newrole.te > @@ -51,8 +51,7 @@ > allow newrole_t self:capability { setuid setgid net_bind_service dac_override }; > > # Read password files > -allow newrole_t etc_auth_t:dir r_dir_perms; > -allow newrole_t etc_auth_t:file r_file_perms; > +allow newrole_t shadow_t:file r_file_perms; > > # Write to utmp > allow newrole_t initrc_var_run_t:file rw_file_perms; > diff --git a/usr/src/cmd/fmac/policy/domains/program/passwd.te b/usr/src/cmd/fmac/policy/domains/program/passwd.te > --- a/usr/src/cmd/fmac/policy/domains/program/passwd.te > +++ b/usr/src/cmd/fmac/policy/domains/program/passwd.te > @@ -44,17 +44,10 @@ > allow passwd_t local_login_t:fd inherit_fd_perms; > allow passwd_t remote_login_t:fd inherit_fd_perms; > > -# Execute /usr/bin/{passwd,chfn,chsh}. > -can_exec(passwd_t, bin_t) > - > # Update /etc/passwd. > allow passwd_t etc_t:dir rw_dir_perms; > allow passwd_t etc_t:file create_file_perms; > > -# Update /etc/auth/shadow. > -allow passwd_t etc_auth_t:dir rw_dir_perms; > -allow passwd_t etc_auth_t:file create_file_perms; > - > -# /usr/bin/passwd asks for w access to utmp, but it will operate > -# correctly without it. Do not audit write denials to utmp. > -auditdeny passwd_t initrc_var_run_t:file ~write; > +# Update /etc/shadow. > +allow passwd_t shadow_t:file create_file_perms; > +file_type_auto_trans(passwd_t, etc_t, shadow_t) > diff --git a/usr/src/cmd/fmac/policy/domains/program/su.te b/usr/src/cmd/fmac/policy/domains/program/su.te > --- a/usr/src/cmd/fmac/policy/domains/program/su.te > +++ b/usr/src/cmd/fmac/policy/domains/program/su.te > @@ -60,9 +60,8 @@ > allow $1_su_t $1_gph_t:fd inherit_fd_perms; > allow $1_t $1_gph_t:fd inherit_fd_perms; > > -# Read /etc/auth/shadow. > -allow $1_su_t etc_auth_t:dir r_dir_perms; > -allow $1_su_t etc_auth_t:file r_file_perms; > +# Read /etc/shadow. > +allow $1_su_t shadow_t:file r_file_perms; > > # Write to utmp. > allow $1_su_t initrc_var_run_t:file rw_file_perms; > diff --git a/usr/src/cmd/fmac/policy/domains/system/ftpd.te b/usr/src/cmd/fmac/policy/domains/system/ftpd.te > --- a/usr/src/cmd/fmac/policy/domains/system/ftpd.te > +++ b/usr/src/cmd/fmac/policy/domains/system/ftpd.te > @@ -55,9 +55,8 @@ > # Create pid files. > file_type_auto_trans(ftpd_t, var_run_t, ftpd_var_run_t) > > -# Read /etc/auth/shadow. > -allow ftpd_t etc_auth_t:dir r_dir_perms; > -allow ftpd_t etc_auth_t:file r_file_perms; > +# Read /etc/shadow. > +allow ftpd_t shadow_t:file r_file_perms; > > # Append to /var/log/wtmp. > allow ftpd_t wtmp_t:file append; > diff --git a/usr/src/cmd/fmac/policy/domains/system/init.te b/usr/src/cmd/fmac/policy/domains/system/init.te > --- a/usr/src/cmd/fmac/policy/domains/system/init.te > +++ b/usr/src/cmd/fmac/policy/domains/system/init.te > @@ -46,8 +46,7 @@ > # Run /etc/rc.sysinit, /etc/rc, /etc/rc.local in the initrc_t domain. > domain_auto_trans(init_t, initrc_exec_t, initrc_t) > > -# Run the shell or sulogin in the sysadm_t domain for single-user mode. > -domain_auto_trans(init_t, shell_exec_t, sysadm_t) > +# Run sulogin in the sysadm_t domain for single-user mode. > domain_auto_trans(init_t, sulogin_exec_t, sysadm_t) > > # Run mingetty in its own domain. > diff --git a/usr/src/cmd/fmac/policy/domains/system/login.te b/usr/src/cmd/fmac/policy/domains/system/login.te > --- a/usr/src/cmd/fmac/policy/domains/system/login.te > +++ b/usr/src/cmd/fmac/policy/domains/system/login.te > @@ -75,9 +75,8 @@ > allow local_login_t var_lock_t:dir rw_dir_perms; > allow local_login_t var_lock_t:file create_file_perms; > > -# Read /etc/auth/shadow. > -allow local_login_t etc_auth_t:dir r_dir_perms; > -allow local_login_t etc_auth_t:file r_file_perms; > +# Read /etc/shadow. > +allow local_login_t shadow_t:file r_file_perms; > > # Search for mail spool file. > allow local_login_t mail_spool_t:dir r_dir_perms; > @@ -123,9 +122,8 @@ > # Write to /var/log/lastlog. > allow remote_login_t var_log_t:file rw_file_perms; > > -# Read /etc/auth/shadow. > -allow remote_login_t etc_auth_t:dir r_dir_perms; > -allow remote_login_t etc_auth_t:file r_file_perms; > +# Read /etc/shadow. > +allow remote_login_t shadow_t:file r_file_perms; > > # Search for mail spool file. > allow remote_login_t mail_spool_t:dir r_dir_perms; > diff --git a/usr/src/cmd/fmac/policy/domains/system/rlogind.te b/usr/src/cmd/fmac/policy/domains/system/rlogind.te > --- a/usr/src/cmd/fmac/policy/domains/system/rlogind.te > +++ b/usr/src/cmd/fmac/policy/domains/system/rlogind.te > @@ -64,7 +64,6 @@ > # Modify /var/log/wtmp. > allow rlogind_t wtmp_t:file rw_file_perms; > > -# Read /etc/auth/shadow. > -allow rlogind_t etc_auth_t:dir r_dir_perms; > -allow rlogind_t etc_auth_t:file r_file_perms; > +# Read /etc/shadow. > +allow rlogind_t shadow_t:file r_file_perms; > > diff --git a/usr/src/cmd/fmac/policy/domains/system/rshd.te b/usr/src/cmd/fmac/policy/domains/system/rshd.te > --- a/usr/src/cmd/fmac/policy/domains/system/rshd.te > +++ b/usr/src/cmd/fmac/policy/domains/system/rshd.te > @@ -44,18 +44,10 @@ > can_network(rshd_t) > > # Run shells in user_t. > -# Commented out - modified rshd removed from distribution for now. > -#domain_auto_trans(rshd_t, shell_exec_t, user_t) > +domain_auto_trans(rshd_t, shell_exec_t, user_t) > > # Send SIGCHLD to inetd on death. > allow rshd_t inetd_t:process sigchld; > > # Allow socket ioctls not handled by other, more specific permissions. > allow rshd_t kernel_t:system net_io_control; > - > -# in.rshd likes to search /etc/auth and read & getattr /etc/auth/shadow. > -# in.rshd will operate correctly without these (dangerous) permissions, > -# so the rshd_t domain does not provide them. We tell the avc not to > -# log failures for these permissions. > -auditdeny rshd_t etc_auth_t:dir ~search; > -auditdeny rshd_t etc_auth_t:file ~{read getattr}; > diff --git a/usr/src/cmd/fmac/policy/domains/system/sshd.te b/usr/src/cmd/fmac/policy/domains/system/sshd.te > --- a/usr/src/cmd/fmac/policy/domains/system/sshd.te > +++ b/usr/src/cmd/fmac/policy/domains/system/sshd.te > @@ -33,8 +33,7 @@ > # sshd_exec_t is the type of the sshd executable. > # sshd_key_t is the type of the ssh private key files > # > -type sshd_t, domain, privlog; > -type sshd_login_t, domain, privuser, privrole, privlog, auth, privowner; > +type sshd_t, domain, privuser, privrole, privlog, auth; > type sshd_exec_t, file_type, exec_type; > type sshd_key_t, file_type; > > @@ -46,9 +45,6 @@ > > # Can create pty's > can_create_pty(sshd) > - > -# Execute Login > -domain_auto_trans(sshd_t, login_exec_t, sshd_login_t) > > # Fetch shell attributes > allow sshd_t shell_exec_t:file { getattr }; > @@ -72,46 +68,15 @@ > # Append to wtmp > allow sshd_t wtmp_t:file append; > > +# Run shells in user_t by default > +domain_auto_trans(sshd_t, shell_exec_t, user_t) > > -################################# > -# > -# Rules for the sshd_login_t domain > -# > -# sshd_login_t is the domain of a login process > -# spawned by sshd > +# Read /etc/shadow > +allow sshd_t shadow_t:file r_file_perms; > > -# Use capabilities > -allow sshd_login_t self:capability { setuid setgid chown fowner fsetid net_bind_service sys_tty_config dac_override }; > - > -# Use the network > -can_network(sshd_login_t) > - > -# Run shells in user_t by default > -domain_auto_trans(sshd_login_t, shell_exec_t, user_t) > - > -# Use the pty created by sshd > -allow sshd_login_t sshd_devpts_t:chr_file rw_file_perms; > - > -# Write to /var/run/utmp > -allow sshd_login_t initrc_var_run_t:file rw_file_perms; > - > -# Write to /var/log/wtmp > -allow sshd_login_t wtmp_t:file rw_file_perms; > - > -# Write to /var/log/lastlog > -allow sshd_login_t var_log_t:file rw_file_perms; > - > -# Read /etc/auth/shadow > -allow sshd_login_t etc_auth_t:dir r_dir_perms; > -allow sshd_login_t etc_auth_t:file r_file_perms; > - > -# Search for mail spool file > -allow sshd_login_t mail_spool_t:dir r_dir_perms; > -allow sshd_login_t mail_spool_t:file getattr; > - > -# Relabel ptys created by sshd > -allow sshd_login_t sshd_devpts_t:chr_file { relabelfrom relabelto }; > -allow sshd_login_t user_devpts_t:chr_file { relabelto relabelfrom getattr }; > +# Relabel ptys. > +allow sshd_t sshd_devpts_t:chr_file { relabelfrom relabelto }; > +allow sshd_t user_devpts_t:chr_file { relabelto relabelfrom getattr }; > > allow sshd_devpts_t user_devpts_t:chr_file transition; > allow user_devpts_t sshd_devpts_t:chr_file transition; > diff --git a/usr/src/cmd/fmac/policy/file_contexts b/usr/src/cmd/fmac/policy/file_contexts > --- a/usr/src/cmd/fmac/policy/file_contexts > +++ b/usr/src/cmd/fmac/policy/file_contexts > @@ -69,49 +69,25 @@ > # > / system_u:object_r:root_t > > -# > -# The policy configuration and its sources. > -# > -/etc/security/fmac/ss_policy system_u:object_r:policy_config_t > - > # > # The superuser home directory. > # > -/root(|/.*) system_u:object_r:sysadm_home_t > -/root/\.netscape(|/.*) system_u:object_r:sysadm_netscape_rw_t > -/root/\.mime\.types system_u:object_r:sysadm_netscape_rw_t > -/root/\.mailcap system_u:object_r:sysadm_netscape_rw_t > - > +/root(/.*)? system_u:object_r:sysadm_home_t > > # > # Other user home directories. > # > -/home(|/.*) system_u:object_r:user_home_t > -/home/.*/\.netscape(|/.*) system_u:object_r:user_netscape_rw_t > -/home/.*/\.mime\.types system_u:object_r:user_netscape_rw_t > -/home/.*/\.mailcap system_u:object_r:user_netscape_rw_t > - > -# > -# /bin > -# > -/bin(|/.*) system_u:object_r:bin_t > -/bin/login system_u:object_r:login_exec_t > -/bin/tcsh system_u:object_r:shell_exec_t > -/bin/bash system_u:object_r:shell_exec_t > -/bin/ash system_u:object_r:shell_exec_t > -/bin/su system_u:object_r:su_exec_t > -/bin/ls system_u:object_r:ls_exec_t > +/home(/.*)? system_u:object_r:user_home_t > > # > # /boot > # > -/boot(|/.*) system_u:object_r:boot_t > -/boot/kernel.h system_u:object_r:boot_runtime_t > +/boot(/.*)? system_u:object_r:boot_t > > # > -# /dev > +# /dev > # > -/dev(|/.*) system_u:object_r:device_t > +/dev(/.*)? system_u:object_r:device_t > /dev/null system_u:object_r:null_device_t > /dev/zero system_u:object_r:zero_device_t > /dev/console system_u:object_r:console_device_t > @@ -142,238 +118,141 @@ > # > # /etc > # > -/etc(|/.*) system_u:object_r:etc_t > -/etc/rc.d/rc system_u:object_r:initrc_exec_t > -/etc/rc.d/rc.sysinit system_u:object_r:initrc_exec_t > -/etc/rc.d/rc.local system_u:object_r:initrc_exec_t > -/etc/auth(|/.*) system_u:object_r:etc_auth_t > +/etc(/.*)? system_u:object_r:etc_t > +/etc/shadow system_u:object_r:shadow_t > +/etc/security/fmac/ss_policy system_u:object_r:policy_config_t > /etc/aliases system_u:object_r:etc_aliases_t > -/etc/aliases.db system_u:object_r:etc_aliases_t > -/etc/mail(|/.*) system_u:object_r:etc_mail_t > -/etc/conf.modules system_u:object_r:modules_conf_t > -/etc/HOSTNAME system_u:object_r:etc_runtime_t > -/etc/ioctl.save system_u:object_r:etc_runtime_t > -/etc/mtab system_u:object_r:etc_runtime_t > -/etc/issue system_u:object_r:etc_runtime_t > -/etc/issue.net system_u:object_r:etc_runtime_t > -/etc/crontab system_u:object_r:system_crond_script_t > -/etc/cron.d(|/.*) system_u:object_r:system_crond_script_t > -/etc/security/cron_context.* system_u:object_r:cron_context_t > -/etc/ssh_host_key system_u:object_r:sshd_key_t > -/etc/ssh_random_seed system_u:object_r:sshd_key_t > +/etc/mail(/.*)? system_u:object_r:etc_mail_t > +/etc/mail/aliases system_u:object_r:etc_aliases_t > +/etc/mail/aliases.db system_u:object_r:etc_aliases_t > +/etc/cron.d(/.*)? system_u:object_r:system_crond_script_t > +/etc/ssh/ssh_host_dsa_key system_u:object_r:sshd_key_t > +/etc/ssh/ssh_host_rsa_key system_u:object_r:sshd_key_t > > # > # /lib > # > -/lib(|/.*) system_u:object_r:lib_t > +/lib(/.*)? system_u:object_r:lib_t > +/lib/svc/bin/svc.startd system_u:object_r:initrc_exec_t > +/lib/svc/bin/svc.configd system_u:object_r:initrc_exec_t > /lib/ld.*\.so.* system_u:object_r:ld_so_t > /lib/lib.*\.so.* system_u:object_r:shlib_t > -/lib/security/.*\.so.* system_u:object_r:shlib_t > -/lib/modules(|/.*) system_u:object_r:modules_object_t > -/lib/modules/[^/]*/modules\.dep system_u:object_r:modules_dep_t > > # > # /sbin > # > -/sbin(|/.*) system_u:object_r:sbin_t > +/sbin(/.*)? system_u:object_r:sbin_t > +/sbin/sh system_u:object_r:shell_exec_t > /sbin/ifconfig system_u:object_r:ifconfig_exec_t > -/sbin/depmod system_u:object_r:depmod_exec_t > -/sbin/modprobe system_u:object_r:modprobe_exec_t > -/sbin/insmod system_u:object_r:insmod_exec_t > -/sbin/insmod.static system_u:object_r:insmod_exec_t > -/sbin/rmmod system_u:object_r:rmmod_exec_t > -/sbin/rmmod.static system_u:object_r:rmmod_exec_t > /sbin/init system_u:object_r:init_exec_t > /sbin/sulogin system_u:object_r:sulogin_exec_t > -/sbin/mingetty system_u:object_r:getty_exec_t > -/sbin/getty system_u:object_r:getty_exec_t > -/sbin/uugetty system_u:object_r:getty_exec_t > -/sbin/syslogd system_u:object_r:syslogd_exec_t > -/sbin/minilogd system_u:object_r:syslogd_exec_t > -/sbin/klogd system_u:object_r:klogd_exec_t > -/sbin/ypbind system_u:object_r:ypbind_exec_t > -/sbin/portmap system_u:object_r:portmap_exec_t > -/sbin/rpc\..* system_u:object_r:rpcd_exec_t > -/sbin/cardmgr system_u:object_r:cardmgr_exec_t > -/sbin/fsck system_u:object_r:fsadm_exec_t > -/sbin/fsck\.ext2 system_u:object_r:fsadm_exec_t > -/sbin/e2fsck system_u:object_r:fsadm_exec_t > -/sbin/e2label system_u:object_r:fsadm_exec_t > -/sbin/mkfs system_u:object_r:fsadm_exec_t > -/sbin/mke2fs system_u:object_r:fsadm_exec_t > -/sbin/mkfs.ext2 system_u:object_r:fsadm_exec_t > -/sbin/mkswap system_u:object_r:fsadm_exec_t > -/sbin/scsi_info system_u:object_r:fsadm_exec_t > -/sbin/sfdisk system_u:object_r:fsadm_exec_t > -/sbin/cfdisk system_u:object_r:fsadm_exec_t > -/sbin/fdisk system_u:object_r:fsadm_exec_t > -/sbin/tune2fs system_u:object_r:fsadm_exec_t > -/sbin/dumpe2fs system_u:object_r:fsadm_exec_t > -/sbin/swapon system_u:object_r:fsadm_exec_t > -/sbin/pwdb_chkpwd system_u:object_r:chkpwd_exec_t > > # > # /tmp > # > -/tmp(|/.*) system_u:object_r:tmp_t > +/tmp(/.*)? system_u:object_r:tmp_t > /tmp/orbit.* system_u:object_r:user_tmp_t > -/tmp/.ICE-unix(|/.*) system_u:object_r:user_tmp_t > -/tmp/.X11-unix(|/.*) system_u:object_r:user_xserver_tmp_t > +/tmp/.ICE-unix(/.*)? system_u:object_r:user_tmp_t > +/tmp/.X11-unix(/.*)? system_u:object_r:user_xserver_tmp_t > /tmp/.X0-lock system_u:object_r:user_xserver_tmp_t > -/tmp/.font-unix(|/.*) system_u:object_r:xfs_tmp_t > +/tmp/.font-unix(/.*)? system_u:object_r:xfs_tmp_t > > # > # /usr > # > -/usr(|/.*) system_u:object_r:usr_t > -/usr/etc(|/.*) system_u:object_r:etc_t > -/usr/libexec(|/.*) system_u:object_r:lib_t > -/usr/src(|/.*) system_u:object_r:src_t > -/usr/tmp(|/.*) system_u:object_r:tmp_t > -/usr/man(|/.*) system_u:object_r:man_t > +/usr(/.*)? system_u:object_r:usr_t > +/usr/src(/.*)? system_u:object_r:src_t > +/usr/tmp(/.*)? system_u:object_r:tmp_t > +/usr/share/man(/.*)? system_u:object_r:man_t > > # > # /usr/bin > # > -/usr/bin(|/.*) system_u:object_r:bin_t > +/usr/bin(/.*)? system_u:object_r:bin_t > +/usr/bin/login system_u:object_r:login_exec_t > +/usr/bin/csh system_u:object_r:shell_exec_t > +/usr/bin/tcsh system_u:object_r:shell_exec_t > +/usr/bin/bash system_u:object_r:shell_exec_t > +/usr/bin/ksh system_u:object_r:shell_exec_t > +/usr/bin/zsh system_u:object_r:shell_exec_t > +/usr/bin/su system_u:object_r:su_exec_t > +/usr/bin/ls system_u:object_r:ls_exec_t > /usr/bin/lpr system_u:object_r:lpr_exec_t > /usr/bin/lpq system_u:object_r:lpr_exec_t > /usr/bin/lprm system_u:object_r:lpr_exec_t > -/usr/bin/makemap system_u:object_r:sbin_t > -/usr/bin/netscape system_u:object_r:netscape_exec_t > /usr/bin/crontab system_u:object_r:crontab_exec_t > +/usr/bin/passwd system_u:object_r:passwd_exec_t > > > # > # /usr/lib > # > -/usr/lib(|/.*) system_u:object_r:lib_t > +/usr/lib(/.*)? system_u:object_r:lib_t > +/usr/lib/ssh/sshd system_u:object_r:sshd_exec_t > +/usr/lib/saf/ttymon system_u:object_r:getty_exec_t > /usr/lib/lib.*\.so.* system_u:object_r:shlib_t > -/usr/lib/perl5/man(|/.*) system_u:object_r:man_t > - > -# > -# /usr/local > -# > -/usr/local/etc(|/.*) system_u:object_r:etc_t > -/usr/local/etc/ssh_host_key system_u:object_r:sshd_key_t > -/usr/local/etc/ssh_host_dsa_key system_u:object_r:sshd_key_t > -/usr/local/src(|/.*) system_u:object_r:src_t > -/usr/local/sbin(|/.*) system_u:object_r:sbin_t > -/usr/local/sbin/sshd system_u:object_r:sshd_exec_t > -/usr/local/man(|/.*) system_u:object_r:man_t > - > -# > -# /usr/local/bin > -# > -/usr/local/bin(|/.*) system_u:object_r:bin_t > -/usr/local/bin/tcsh system_u:object_r:shell_exec_t > - > -# > -# /usr/local/lib > -# > -/usr/local/lib(|/.*) system_u:object_r:lib_t > -/usr/local/lib/lib.*\.so.* system_u:object_r:shlib_t > +/usr/lib/inet/inetd system_u:object_r:inetd_exec_t > +/usr/lib/inet/in\..*d system_u:object_r:inetd_child_exec_t > +/usr/lib/sendmail system_u:object_r:sendmail_exec_t > > # > # /usr/sbin > # > -/usr/sbin(|/.*) system_u:object_r:sbin_t > +/usr/sbin(/.*)? system_u:object_r:sbin_t > +/usr/sbin/fsck system_u:object_r:fsadm_exec_t > +/usr/sbin/mkfs system_u:object_r:fsadm_exec_t > +/usr/sbin/fdisk system_u:object_r:fsadm_exec_t > /usr/sbin/syslogd system_u:object_r:syslogd_exec_t > -/usr/sbin/klogd system_u:object_r:klogd_exec_t > -/usr/sbin/apmd system_u:object_r:apmd_exec_t > -/usr/sbin/crond system_u:object_r:crond_exec_t > -/usr/sbin/atd system_u:object_r:atd_exec_t > -/usr/sbin/lpd system_u:object_r:lpd_exec_t > -/usr/sbin/inetd system_u:object_r:inetd_exec_t > -/usr/sbin/tcpd system_u:object_r:tcpd_exec_t > -/usr/sbin/identd system_u:object_r:inetd_child_exec_t > +/usr/sbin/cron system_u:object_r:crond_exec_t > /usr/sbin/in\..*d system_u:object_r:inetd_child_exec_t > /usr/sbin/in.rlogind system_u:object_r:rlogind_exec_t > /usr/sbin/in.telnetd system_u:object_r:rlogind_exec_t > /usr/sbin/in.rshd system_u:object_r:rshd_exec_t > /usr/sbin/in.ftpd system_u:object_r:ftpd_exec_t > -/usr/sbin/in.ftpd-stage2 system_u:object_r:ftpd_stage2_exec_t > -/usr/sbin/sendmail system_u:object_r:sendmail_exec_t > +/usr/sbin/rpcbind system_u:object_r:portmap_exec_t > /usr/sbin/rpc\..* system_u:object_r:rpcd_exec_t > -/usr/sbin/gpm system_u:object_r:gpm_exec_t > /usr/sbin/makemap system_u:object_r:sbin_t > -/usr/sbin/utempter system_u:object_r:utempter_exec_t > -/usr/sbin/gnome-pty-helper system_u:object_r:gph_exec_t > -/usr/sbin/logrotate system_u:object_r:logrotate_exec_t > > # > -# /usr/X11R6/bin > +# /usr/sadm > # > -/usr/X11R6/bin(|/.*) system_u:object_r:bin_t > -/usr/X11R6/bin/xfs system_u:object_r:xfs_exec_t > -/usr/X11R6/bin/Xwrapper system_u:object_r:xserver_exec_t > +/usr/sadm/bin(/.*)? system_u:object_r:bin_t > +/usr/sadm/admin/bin(/.*)? system_u:object_r:bin_t > +/usr/sadm/lib(/.*)? system_u:object_r:lib_t > > # > -# /usr/X11R6/lib > +# /usr/X11 > # > -/usr/X11R6/lib(|/.*) system_u:object_r:lib_t > -/usr/X11R6/lib/lib.*\.so.* system_u:object_r:shlib_t > - > -# > -# /usr/X11R6/man > -# > -/usr/X11R6/man(|/.*) system_u:object_r:man_t > - > -# > -# /usr/flask > -# > -/usr/flask/bin(|/.*) system_u:object_r:bin_t > -/usr/flask/sbin(|/.*) system_u:object_r:bin_t > -/usr/flask/libexec(|/.*) system_u:object_r:lib_t > -/usr/flask/bin/spasswd system_u:object_r:passwd_exec_t > -/usr/flask/bin/schsh system_u:object_r:passwd_exec_t > -/usr/flask/bin/schfn system_u:object_r:passwd_exec_t > -/usr/flask/bin/newrole system_u:object_r:newrole_exec_t > +/usr/X11/bin(/.*)? system_u:object_r:bin_t > +/usr/X11/bin/Xorg system_u:object_r:xserver_exec_t > +/usr/X11/lib(/.*)? system_u:object_r:lib_t > +/usr/X11/lib/lib.*\.so.* system_u:object_r:shlib_t > +/usr/X11/share/man(/.*)? system_u:object_r:man_t > > # > # /var > # > -/var(|/.*) system_u:object_r:var_t > -/var/catman(|/.*) system_u:object_r:catman_t > -/var/yp(|/.*) system_u:object_r:var_yp_t > -/var/lib(|/.*) system_u:object_r:var_lib_t > -/var/lock(|/.*) system_u:object_r:var_lock_t > -/var/tmp(|/.*) system_u:object_r:tmp_t > +/var(/.*)? system_u:object_r:var_t > +/var/yp(/.*)? system_u:object_r:var_yp_t > +/var/lib(/.*)? system_u:object_r:var_lib_t > +/var/tmp(/.*)? system_u:object_r:tmp_t > > # > # /var/run > # > -/var/run(|/.*) system_u:object_r:var_run_t > -/var/run/utmp system_u:object_r:initrc_var_run_t > -/var/run/runlevel.dir system_u:object_r:initrc_var_run_t > -/var/run/random-seed system_u:object_r:initrc_var_run_t > +/var/run(/.*)? system_u:object_r:var_run_t > /var/run/.*\.*pid <> > > # > # /var/spool > # > -/var/spool(|/.*) system_u:object_r:var_spool_t > -/var/spool/at(|/.*) system_u:object_r:at_spool_t > -/var/spool/cron(|/.*) system_u:object_r:cron_spool_t > -/var/spool/lpd(|/.*) system_u:object_r:lpd_spool_t > -/var/spool/mail(|/.*) system_u:object_r:mail_spool_t > -/var/spool/mqueue(|/.*) system_u:object_r:mqueue_spool_t > +/var/spool(/.*)? system_u:object_r:var_spool_t > +/var/spool/cron(/.*)? system_u:object_r:cron_spool_t > +/var/spool/lp(/.*)? system_u:object_r:lpd_spool_t > +/var/mail(/.*)? system_u:object_r:mail_spool_t > +/var/spool/mqueue(/.*)? system_u:object_r:mqueue_spool_t > > # > # /var/log > # > -/var/log(|/.*) system_u:object_r:var_log_t > -/var/log/wtmp system_u:object_r:wtmp_t > -/var/log/sendmail.st system_u:object_r:sendmail_var_log_t > -/var/log/cron system_u:object_r:cron_log_t > - > -# > -# Persistent label mappings. > -# > -.*/\.\.\.security(|/.*) system_u:object_r:file_labels_t > - > -# > -# Lost and found directories. > -# > -.*/lost\+found(|/.*) system_u:object_r:lost_found_t > - > +/var/log(/.*)? system_u:object_r:var_log_t > diff --git a/usr/src/cmd/fmac/policy/rbac b/usr/src/cmd/fmac/policy/rbac > --- a/usr/src/cmd/fmac/policy/rbac > +++ b/usr/src/cmd/fmac/policy/rbac > @@ -77,7 +77,6 @@ > xfs_t > local_login_t > remote_login_t > - sshd_login_t > depmod_t > modprobe_t > insmod_t > @@ -87,6 +86,7 @@ > logrotate_t > sysadm_t # single-user mode > user_mail_t # mail sent by crond > + user_t > }; > > # > diff --git a/usr/src/cmd/fmac/policy/types/file.te b/usr/src/cmd/fmac/policy/types/file.te > --- a/usr/src/cmd/fmac/policy/types/file.te > +++ b/usr/src/cmd/fmac/policy/types/file.te > @@ -97,10 +97,9 @@ > type etc_runtime_t, file_type, sysadmfile; > > # > -# etc_auth_t is the type of /etc/auth, > -# which contains the shadow password file. > +# shadow_t is the type of /etc/shadow. > # > -type etc_auth_t, file_type, sysadmfile; > +type shadow_t, file_type, sysadmfile; > > # > # etc_aliases_t is the type of the aliases database. > > -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Mon Sep 8 08:32:29 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 08 Sep 2008 11:32:29 -0400 Subject: [fmac-discuss] [RFC][PATCH] Basic security context transition support In-Reply-To: <48C195F3.1030401@sun.com> References: <1220464148.6034.150.camel@moss-spartans.epoch.ncsc.mil> <48BEF17F.3030509@sun.com> <1220475277.6034.224.camel@moss-spartans.epoch.ncsc.mil> <48BF05EE.4080908@sun.com> <1220530216.17197.19.camel@moss-spartans.epoch.ncsc.mil> <48C01A63.4080606@sun.com> <1220557266.17197.243.camel@moss-spartans.epoch.ncsc.mil> <48C048B9.6070701@sun.com> <1220622499.17197.329.camel@moss-spartans.epoch.ncsc.mil> <48C17AD8.4060607@sun.com> <1220640609.17197.407.camel@moss-spartans.epoch.ncsc.mil> <48C195F3.1030401@sun.com> Message-ID: <1220887949.19241.115.camel@moss-spartans.epoch.ncsc.mil> On Fri, 2008-09-05 at 13:26 -0700, Glenn Faden wrote: > Stephen Smalley wrote: > > On Fri, 2008-09-05 at 11:30 -0700, Glenn Faden wrote: > > > >> Stephen Smalley wrote: > >> > >> This looks like a good first attempt, but I'm not sure it's correct. I'm > >> concerned that it might wind up calling avc_has_perm() twice for a > >> single operation. > >> > > > > That's intentional - it is checking two different permissions (read vs. > > priv_read, write vs. priv_write, etc). The first is "Can subject S > > read/write/execute object O?". The second is "Can subject S override > > DAC restrictions on read/write/execute on object O?". > > > > The equivalent in SELinux is: > > "Can subject S read/write/execute object O?" > > "Does subject S have dac_override capability?" > > > > OK, but it's confusing that the FMAC permission to override DAC > restrictions for read is not sufficient to actually read the vnode. I view them as logically distinct: "Does the MAC policy allow subject S to read/write/execute object O?" "Does the MAC policy allow subject S the priv_file_dac_read privilege (and thus override DAC restrictions) when accessing object O?" > The > subject might need both the priv_read and priv_read_force FMAC > permissions. Is this because you want to treat the authoritative and > restrictive aspects of the policy independently? Won't that make writing > policy even more difficult? Shouldn't priv_read_force imply priv_read? Just to clarify, we are talking about 3 distinct permissions: read, priv_read, and priv_read_force, where the last one was just introduced by Darren's request to not make authoritative vs. restrictive a global setting. So, yes, priv_read_force would logically imply priv_read, and that would be easy to implement directly in the code since both would be checked within fmac_vnode_priv_access(). Making the priv_read* permissions imply read permission would be more complicated in the code, although one could certainly do that in policy by wrapping both permissions with a single macro/interface. But I'm not certain you want to do that. I'm not entirely sure though that we absolutely want per-object priv_read_force checks; possibly the privilege grantings should be kept per-subject and applied at exec time and only the privilege restrictions should be applied at access time. -- Stephen Smalley National Security Agency From john.weeks at sun.com Tue Sep 9 12:38:52 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 09 Sep 2008 12:38:52 -0700 Subject: [fmac-discuss] [PATCH v2] Prototype file security context support In-Reply-To: <1220881121.19241.24.camel@moss-spartans.epoch.ncsc.mil> References: <1220881121.19241.24.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C6D0CC.90006@sun.com> Acked-by: John Weeks Stephen Smalley wrote: > Implement prototype file security context support to enable progress on > developing other parts of FMAC that depend on file security contexts > until system attribute support in ZFS is reworked. > > In the kernel, introduce support for a "secctx" system attribute, fetch > this attribute for existing files on the lookup code path and map to an > incore vnode secid for internal use by FMAC, and compute and set this > attribute and the incore vnode secid on the create and mkdir code paths. > Current limitations of this prototype support include a 56-byte maximum > length for the security context, inability to use both secctx and > av_scanstamp together on a file, and inability to assign a security > context to file types other than regular files and directories. > > In userland, introduce getfilecon() and setfilecon() libc interfaces and > corresponding utilities for getting and setting the file security > context. Also update the setfiles utility to use the new interfaces and > to deal with the current limitation to regular files and directories. > > Changes from the first version of the patch include: > - moving the resizing of the bonus buffer into zfs_xvattr_set(), thereby > fixing the setting of the attribute on new files, > - fixing libc_nvlist_alloc whitespace and error return, > - moved vfs_has_feature check earlier in fmac_vnode_create(), > - added comments to clarify certain aspects of the code > > New libc interfaces: > int getfilecon(const char *path, char **secctxp); > int setfilecon(const char *path, char *secctx); > > New utilities: > getfilecon path... > setfilecon context path... > setfiles spec-file path... > > Example usage: > # setfilecon system_u:object_r:shadow_t /etc/shadow > # getfilecon /etc/shadow > /etc/shadow: system_u:object_r:shadow_t > # setfiles /etc/security/fmac/file_contexts / > > Webrev available at: http://cr.opensolaris.org/~sds/secctx/ > > diff --git a/usr/src/cmd/fmac/Makefile b/usr/src/cmd/fmac/Makefile > --- a/usr/src/cmd/fmac/Makefile > +++ b/usr/src/cmd/fmac/Makefile > @@ -32,7 +32,9 @@ > loadpolicy \ > setenforce \ > getenforce \ > - pcon > + pcon \ > + getfilecon \ > + setfilecon > > SUBDIR_POLICY = \ > policy > diff --git a/usr/src/cmd/fmac/getfilecon/Makefile b/usr/src/cmd/fmac/getfilecon/Makefile > new file mode 100644 > --- /dev/null > +++ b/usr/src/cmd/fmac/getfilecon/Makefile > @@ -0,0 +1,42 @@ > +# > +# CDDL HEADER START > +# > +# The contents of this file are subject to the terms of the > +# Common Development and Distribution License, Version 1.0 only > +# (the "License"). You may not use this file except in compliance > +# with the License. > +# > +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE > +# or http://www.opensolaris.org/os/licensing. > +# See the License for the specific language governing permissions > +# and limitations under the License. > +# > +# When distributing Covered Code, include this CDDL HEADER in each > +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. > +# If applicable, add the following below this CDDL HEADER, with the > +# fields enclosed by brackets "[]" replaced with your own identifying > +# information: Portions Copyright [yyyy] [name of copyright owner] > +# > +# CDDL HEADER END > +# > +# > +# > +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. > +# Use is subject to license terms. > +# > + > +PROG= getfilecon > + > +include ../../Makefile.cmd > + > +.KEEP_STATE: > + > +all: $(PROG) > + > +install: all $(ROOTPROG) > + > +clean: > + > +lint: lint_PROG > + > +include ../../Makefile.targ > diff --git a/usr/src/cmd/fmac/getfilecon/getfilecon.c b/usr/src/cmd/fmac/getfilecon/getfilecon.c > new file mode 100644 > --- /dev/null > +++ b/usr/src/cmd/fmac/getfilecon/getfilecon.c > @@ -0,0 +1,69 @@ > +/* > + * CDDL HEADER START > + * > + * The contents of this file are subject to the terms of the > + * Common Development and Distribution License (the "License"). > + * You may not use this file except in compliance with the License. > + * > + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE > + * or http://www.opensolaris.org/os/licensing. > + * See the License for the specific language governing permissions > + * and limitations under the License. > + * > + * When distributing Covered Code, include this CDDL HEADER in each > + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. > + * If applicable, add the following below this CDDL HEADER, with the > + * fields enclosed by brackets "[]" replaced with your own identifying > + * information: Portions Copyright [yyyy] [name of copyright owner] > + * > + * CDDL HEADER END > + */ > + > +/* > + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. > + * Use is subject to license terms. > + */ > + > +/* > + * Display context for specified files. > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +int > +main(int argc, char **argv) > +{ > + int i, error; > + char *secctx; > + > + (void) setlocale(LC_ALL, ""); > +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ > +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ > +#endif > + (void) textdomain(TEXT_DOMAIN); > + > + if (argc <= 1) { > + (void) fprintf(stderr, gettext("usage: getfilecon path ...\n")); > + return (1); > + } > + > + for (i = 1; i < argc; i++) { > + error = getfilecon(argv[i], &secctx); > + if (error) { > + (void) fprintf(stderr, > + gettext("getfilecon: getting file context of %s failed: %s\n"), > + argv[i], strerror(errno)); > + exit(1); > + } > + (void) printf("%s: %s\n", argv[i], secctx); > + free(secctx); > + } > + > + return (0); > +} > diff --git a/usr/src/cmd/fmac/policy/Makefile b/usr/src/cmd/fmac/policy/Makefile > --- a/usr/src/cmd/fmac/policy/Makefile > +++ b/usr/src/cmd/fmac/policy/Makefile > @@ -130,8 +130,6 @@ > fs_use$(MLS_SUFFIX) \ > net_contexts$(MLS_SUFFIX) > > -FILECONTEXT_FILE = file_contexts$(MLS_SUFFIX) > - > MLS_FILE = $(MLS_FLAG:yes=mls) > > MLS_SUFFIX = $(MLS_FLAG:yes=.mls) > @@ -179,19 +177,17 @@ > users.mls: users > $(SED) 's/;/ ranges u;/' $^ > $@ > > -install: policy > +install: policy file_contexts > install -s -m 744 -d $(ROOT)/etc/security/fmac > cp policy ss_policy > install -s -m 644 -f $(ROOT)/etc/security/fmac ss_policy > + install -s -m 644 -f $(ROOT)/etc/security/fmac file_contexts > > load: install > - load_policy /ss_policy > + load_policy $(ROOT)/etc/security/fmac/ss_policy > > -file_contexts.mls: file_contexts > - $(SED) 's/_t/_t:u/g' $^ > $@ > - > -relabel: $(FILECONTEXT_FILE) > - $(SETFILES) -v $(FILECONTEXT_FILE) `mount -p | awk '/ufs/{print $$3}; /zfs/{print $$3}'` > +relabel: file_contexts > + $(SETFILES) -v file_contexts `mount -p | awk '/zfs/{print $$3}'` > $(TOUCH) relabel > > all.te: macros.te attrib.te all_types.te all_domains.te assert.te > diff --git a/usr/src/cmd/fmac/setfilecon/Makefile b/usr/src/cmd/fmac/setfilecon/Makefile > new file mode 100644 > --- /dev/null > +++ b/usr/src/cmd/fmac/setfilecon/Makefile > @@ -0,0 +1,42 @@ > +# > +# CDDL HEADER START > +# > +# The contents of this file are subject to the terms of the > +# Common Development and Distribution License, Version 1.0 only > +# (the "License"). You may not use this file except in compliance > +# with the License. > +# > +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE > +# or http://www.opensolaris.org/os/licensing. > +# See the License for the specific language governing permissions > +# and limitations under the License. > +# > +# When distributing Covered Code, include this CDDL HEADER in each > +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. > +# If applicable, add the following below this CDDL HEADER, with the > +# fields enclosed by brackets "[]" replaced with your own identifying > +# information: Portions Copyright [yyyy] [name of copyright owner] > +# > +# CDDL HEADER END > +# > +# > +# > +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. > +# Use is subject to license terms. > +# > + > +PROG= setfilecon > + > +include ../../Makefile.cmd > + > +.KEEP_STATE: > + > +all: $(PROG) > + > +install: all $(ROOTPROG) > + > +clean: > + > +lint: lint_PROG > + > +include ../../Makefile.targ > diff --git a/usr/src/cmd/fmac/setfilecon/setfilecon.c b/usr/src/cmd/fmac/setfilecon/setfilecon.c > new file mode 100644 > --- /dev/null > +++ b/usr/src/cmd/fmac/setfilecon/setfilecon.c > @@ -0,0 +1,66 @@ > +/* > + * CDDL HEADER START > + * > + * The contents of this file are subject to the terms of the > + * Common Development and Distribution License (the "License"). > + * You may not use this file except in compliance with the License. > + * > + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE > + * or http://www.opensolaris.org/os/licensing. > + * See the License for the specific language governing permissions > + * and limitations under the License. > + * > + * When distributing Covered Code, include this CDDL HEADER in each > + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. > + * If applicable, add the following below this CDDL HEADER, with the > + * fields enclosed by brackets "[]" replaced with your own identifying > + * information: Portions Copyright [yyyy] [name of copyright owner] > + * > + * CDDL HEADER END > + */ > + > +/* > + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. > + * Use is subject to license terms. > + */ > + > +/* > + * Set context for specified files. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +int > +main(int argc, char **argv) > +{ > + int i, error; > + > + (void) setlocale(LC_ALL, ""); > +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ > +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ > +#endif > + (void) textdomain(TEXT_DOMAIN); > + > + if (argc < 3) { > + (void) fprintf(stderr, gettext("usage: %s context path...\n"), argv[0]); > + exit(1); > + } > + > + for (i = 2; i < argc; i++) { > + error = setfilecon(argv[i], argv[1]); > + if (error) { > + (void) fprintf(stderr, > + gettext("setfilecon: setting file context of %s to %s failed: %s\n"), > + argv[i], argv[1], strerror(errno)); > + exit(1); > + } > + } > + return (0); > +} > diff --git a/usr/src/cmd/fmac/setfiles/Makefile b/usr/src/cmd/fmac/setfiles/Makefile > --- a/usr/src/cmd/fmac/setfiles/Makefile > +++ b/usr/src/cmd/fmac/setfiles/Makefile > @@ -37,7 +37,7 @@ > > all: $(PROG) > > -install: all $(ROOTSBINPROG) > +install: all $(ROOTPROG) > > clean: > > diff --git a/usr/src/cmd/fmac/setfiles/setfiles.c b/usr/src/cmd/fmac/setfiles/setfiles.c > --- a/usr/src/cmd/fmac/setfiles/setfiles.c > +++ b/usr/src/cmd/fmac/setfiles/setfiles.c > @@ -94,37 +94,7 @@ > #include > #include > #include > -#ifdef jweeks > #include > -#endif > - > -/* jweeks - until we have library support */ > -int > -lgetfilecon(const char *c, char **context) > -{ > - *context = strdup("system_u:object_r:file_t"); > - return (0); > -} > - > -int > -lsetfilecon(const char *c, const char *context) > -{ > - return (0); > -} > - > -void > -freecon(char *context) > -{ > - if (context != NULL) > - free(context); > -} > - > -int > -security_check_context(const char *context) > -{ > - return (0); > -} > -/* jweeks - until we have library support */ > > static int add_assoc = 1; > > @@ -370,14 +340,6 @@ > return (i); > } > > -/* Used with qsort to sort specs from lowest to highest hasMetaChars value */ > -int > -spec_compare(const void* specA, const void* specB) > -{ > - return (((struct spec *)specB)->hasMetaChars - > - ((struct spec *)specA)->hasMetaChars); > -} > - > /* > * Check for duplicate specifications. If a duplicate specification is found > * and the context is the same, give a warning to the user. If a duplicate > @@ -501,6 +463,14 @@ > return (0); > } > > + /* > + * At present only regular files and directories can be labeled. > + * XXX This needs to be fixed in the kernel. > + */ > + if (flag == FTW_SL || > + (!S_ISDIR(sb->st_mode) && !S_ISREG(sb->st_mode))) > + return (0); > + > i = match(my_file, &my_sb); > if (i < 0) > /* No matching specification. */ > @@ -539,16 +509,15 @@ > } > > /* Get the current context of the file. */ > - ret = lgetfilecon(my_file, &context); > + ret = getfilecon(my_file, &context); > if (ret < 0) { > if (errno == ENODATA) { > context = malloc(10); > strcpy(context, "<>"); > } else { > - perror(my_file); > fprintf(stderr, "%s: unable to obtain attribute for " > - "file %s\n", > - progname, my_file); > + "file %s: %s\n", > + progname, my_file, strerror(errno)); > return (-1); > } > } > @@ -580,7 +549,7 @@ > /* > * Relabel the file to the specified context. > */ > - ret = lsetfilecon(my_file, spec[i].context); > + ret = setfilecon(my_file, spec[i].context); > if (ret) { > perror(my_file); > fprintf(stderr, "%s: unable to relabel %s to %s\n", > @@ -599,7 +568,8 @@ > char buf[255 + 1], *buf_p; > char regex[256], type[256], context[256]; > char *anchored_regex; > - int opt, items, len, lineno, pass, nerr, regerr, i; > + int opt, items, len, lineno, pass, nerr, regerr, i, j; > + spec_t *spec_copy; > > /* Process any options. */ > while ((opt = getopt(argc, argv, "dnpqvxW")) > 0) { > @@ -819,8 +789,25 @@ > } > fclose(fp); > > - /* Sort the specifications with most general first */ > - qsort(spec, nspec, sizeof (struct spec), spec_compare); > + /* Move exact pathname specifications to the end. */ > + spec_copy = malloc(sizeof (spec_t) * nspec); > + if (!spec_copy) { > + fprintf(stderr, > + "%s: insufficient memory for specifications\n", > + argv[0]); > + exit(1); > + } > + j = 0; > + for (i = 0; i < nspec; i++) { > + if (spec[i].hasMetaChars) > + memcpy(&spec_copy[j++], &spec[i], sizeof (spec_t)); > + } > + for (i = 0; i < nspec; i++) { > + if (!spec[i].hasMetaChars) > + memcpy(&spec_copy[j++], &spec[i], sizeof (spec_t)); > + } > + free(spec); > + spec = spec_copy; > > /* Verify no exact duplicates */ > if (nodups_specs() != 0) { > diff --git a/usr/src/common/fmac/ss/services.c b/usr/src/common/fmac/ss/services.c > --- a/usr/src/common/fmac/ss/services.c > +++ b/usr/src/common/fmac/ss/services.c > @@ -502,9 +502,6 @@ > return (0); > } > } > - (void) printf("security_context_to_sid: called before initial " > - "load_policy on unknown context %s\n", > - scontext); > return (EINVAL); > } > *sid = SECSID_NULL; > diff --git a/usr/src/common/xattr/xattr_common.c b/usr/src/common/xattr/xattr_common.c > --- a/usr/src/common/xattr/xattr_common.c > +++ b/usr/src/common/xattr/xattr_common.c > @@ -63,6 +63,7 @@ > { A_OWNERSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST }, > { A_GROUPSID, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_NVLIST }, > { A_FSID, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT64 }, > + { A_SECCTX, O_NONE, XATTR_VIEW_READWRITE, DATA_TYPE_STRING }, > }; > > const char * > diff --git a/usr/src/head/fmac/fmac.h b/usr/src/head/fmac/fmac.h > --- a/usr/src/head/fmac/fmac.h > +++ b/usr/src/head/fmac/fmac.h > @@ -55,7 +55,8 @@ > int setexeccon(security_context_t context); > int getprevcon(security_context_t *context); > void freecon(security_context_t context); > - > +int getfilecon(const char *path, char **secctxp); > +int setfilecon(const char *path, char *secctx); > #ifdef __cplusplus > } > #endif > diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile > --- a/usr/src/lib/libc/amd64/Makefile > +++ b/usr/src/lib/libc/amd64/Makefile > @@ -107,6 +107,7 @@ > cuexit.o \ > ecvt.o \ > errlst.o \ > + filecon.o \ > amd64_data.o \ > ldivide.o \ > lock.o \ > diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com > --- a/usr/src/lib/libc/i386/Makefile.com > +++ b/usr/src/lib/libc/i386/Makefile.com > @@ -426,6 +426,7 @@ > fattach.o \ > fdetach.o \ > fdopendir.o \ > + filecon.o \ > fmtmsg.o \ > ftime.o \ > ftok.o \ > diff --git a/usr/src/lib/libc/inc/libc.h b/usr/src/lib/libc/inc/libc.h > --- a/usr/src/lib/libc/inc/libc.h > +++ b/usr/src/lib/libc/inc/libc.h > @@ -72,8 +72,11 @@ > extern void callout_lock_exit(void); > extern void *lmalloc(size_t); > extern void lfree(void *, size_t); > +extern int libc_nvlist_alloc(nvlist_t **,uint_t, int); > extern void libc_nvlist_free(nvlist_t *); > extern int libc_nvlist_lookup_uint64(nvlist_t *, const char *, uint64_t *); > +extern int libc_nvlist_lookup_string(nvlist_t *, const char *, char **); > +extern int libc_nvlist_add_string(nvlist_t *, const char *, const char *); > extern void *libc_malloc(size_t); > extern void *libc_realloc(void *, size_t); > extern void libc_free(void *); > diff --git a/usr/src/lib/libc/port/gen/attrat.c b/usr/src/lib/libc/port/gen/attrat.c > --- a/usr/src/lib/libc/port/gen/attrat.c > +++ b/usr/src/lib/libc/port/gen/attrat.c > @@ -44,8 +44,11 @@ > static int (*nvpacker)(nvlist_t *, char **, size_t *, int, int); > static int (*nvsize)(nvlist_t *, size_t *, int); > static int (*nvunpacker)(char *, size_t, nvlist_t **); > +static int (*nvalloc)(nvlist_t **, uint_t, int); > static int (*nvfree)(nvlist_t *); > static int (*nvlookupint64)(nvlist_t *, const char *, uint64_t *); > +static int (*nvlookupstring)(nvlist_t *, const char *, char **); > +static int (*nvaddstring)(nvlist_t *, const char *, const char *); > > static mutex_t attrlock = DEFAULTMUTEX; > static int initialized; > @@ -62,8 +65,11 @@ > void *packer; > void *sizer; > void *unpacker; > + void *allocer; > void *freer; > void *looker; > + void *lookupstr; > + void *addstr; > > if (initialized == 0) { > void *handle = dlopen("libnvpair.so.1", RTLD_LAZY); > @@ -72,8 +78,12 @@ > (packer = dlsym(handle, "nvlist_pack")) == NULL || > (sizer = dlsym(handle, "nvlist_size")) == NULL || > (unpacker = dlsym(handle, "nvlist_unpack")) == NULL || > + (allocer = dlsym(handle, "nvlist_alloc")) == NULL || > (freer = dlsym(handle, "nvlist_free")) == NULL || > - (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL) { > + (looker = dlsym(handle, "nvlist_lookup_uint64")) == NULL || > + (lookupstr = dlsym(handle, "nvlist_lookup_string")) > + == NULL || > + (addstr = dlsym(handle, "nvlist_add_string")) == NULL) { > if (handle) > dlclose(handle); > return (-1); > @@ -93,10 +103,16 @@ > sizer; > nvunpacker = (int (*)(char *, size_t, nvlist_t **)) > unpacker; > + nvalloc = (int (*)(nvlist_t **, uint_t, int)) > + allocer; > nvfree = (int (*)(nvlist_t *)) > freer; > nvlookupint64 = (int (*)(nvlist_t *, const char *, uint64_t *)) > looker; > + nvlookupstring = (int (*)(nvlist_t *, const char *, char **)) > + lookupstr; > + nvaddstring = (int (*)(nvlist_t *, const char *, const char *)) > + addstr; > > membar_producer(); > initialized = 1; > @@ -303,6 +319,15 @@ > return (error); > } > > +int > +libc_nvlist_alloc(nvlist_t **nvp, uint_t nvflag, int flag) > +{ > + if (attrat_init()) > + return (errno ? errno : EINVAL); > + > + return (nvalloc(nvp, nvflag, flag)); > +} > + > void > libc_nvlist_free(nvlist_t *nvp) > { > @@ -314,3 +339,15 @@ > { > return (nvlookupint64(nvp, name, value)); > } > + > +int > +libc_nvlist_lookup_string(nvlist_t *nvp, const char *name, char **value) > +{ > + return (nvlookupstring(nvp, name, value)); > +} > + > +int > +libc_nvlist_add_string(nvlist_t *nvp, const char *name, const char *value) > +{ > + return (nvaddstring(nvp, name, value)); > +} > diff --git a/usr/src/lib/libc/port/gen/filecon.c b/usr/src/lib/libc/port/gen/filecon.c > new file mode 100644 > --- /dev/null > +++ b/usr/src/lib/libc/port/gen/filecon.c > @@ -0,0 +1,90 @@ > +/* > + * CDDL HEADER START > + * > + * The contents of this file are subject to the terms of the > + * Common Development and Distribution License (the "License"). > + * You may not use this file except in compliance with the License. > + * > + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE > + * or http://www.opensolaris.org/os/licensing. > + * See the License for the specific language governing permissions > + * and limitations under the License. > + * > + * When distributing Covered Code, include this CDDL HEADER in each > + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. > + * If applicable, add the following below this CDDL HEADER, with the > + * fields enclosed by brackets "[]" replaced with your own identifying > + * information: Portions Copyright [yyyy] [name of copyright owner] > + * > + * CDDL HEADER END > + */ > + > +/* > + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. > + * Use is subject to license terms. > + */ > + > +#pragma weak _getfilecon = getfilecon > +#pragma weak _setfilecon = setfilecon > + > +#include "lint.h" > +#include "libc.h" > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#ifndef A_SECCTX > +#define A_SECCTX "secctx" > +#endif > + > +int > +getfilecon(const char *path, char **secctxp) > +{ > + nvlist_t *nvp; > + int error; > + char *secctx; > + > + error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, path, &nvp); > + if (error) > + return (-1); > + error = libc_nvlist_lookup_string(nvp, A_SECCTX, &secctx); > + if (error) { > + errno = ENODATA; > + libc_nvlist_free(nvp); > + return (-1); > + } > + *secctxp = strdup(secctx); > + libc_nvlist_free(nvp); > + if (!(*secctxp)) > + return (-1); > + return (0); > +} > + > +int > +setfilecon(const char *path, char *secctx) > +{ > + nvlist_t *nvp; > + int error; > + > + error = libc_nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0); > + if (error) { > + errno = error; > + return (-1); > + } > + > + error = libc_nvlist_add_string(nvp, A_SECCTX, secctx); > + if (error) { > + errno = error; > + error = -1; > + goto out; > + } > + > + error = setattrat(AT_FDCWD, XATTR_VIEW_READWRITE, path, nvp); > +out: > + libc_nvlist_free(nvp); > + return (error); > +} > diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers > --- a/usr/src/lib/libc/port/mapfile-vers > +++ b/usr/src/lib/libc/port/mapfile-vers > @@ -82,6 +82,7 @@ > getattrat; > getcon; > getexeccon; > + getfilecon; > getpagesizes2; > getpidcon; > getprevcon; > @@ -137,6 +138,7 @@ > sem_wait; > setattrat; > setexeccon; > + setfilecon; > _sharefs; > shm_open; > shm_unlink; > diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile > --- a/usr/src/lib/libc/sparc/Makefile > +++ b/usr/src/lib/libc/sparc/Makefile > @@ -450,6 +450,7 @@ > fattach.o \ > fdetach.o \ > fdopendir.o \ > + filecon.o \ > fmtmsg.o \ > ftime.o \ > ftok.o \ > diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile > --- a/usr/src/lib/libc/sparcv9/Makefile > +++ b/usr/src/lib/libc/sparcv9/Makefile > @@ -411,6 +411,7 @@ > fattach.o \ > fdetach.o \ > fdopendir.o \ > + filecon.o \ > fmtmsg.o \ > ftime.o \ > ftok.o \ > diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com > --- a/usr/src/pkgdefs/SUNWcsr/prototype_com > +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com > @@ -286,6 +286,7 @@ > f none etc/security/dev/st1 400 root bin > d none etc/security/fmac 755 root bin > f none etc/security/fmac/ss_policy 644 root sys > +f none etc/security/fmac/file_contexts 644 root sys > f none etc/security/kmfpolicy.xml 644 root bin > d none etc/security/lib 755 root sys > f none etc/security/lib/audio_clean 555 root sys > diff --git a/usr/src/pkgdefs/SUNWesu/prototype_com b/usr/src/pkgdefs/SUNWesu/prototype_com > --- a/usr/src/pkgdefs/SUNWesu/prototype_com > +++ b/usr/src/pkgdefs/SUNWesu/prototype_com > @@ -66,6 +66,7 @@ > f none usr/bin/dos2unix 555 root bin > f none usr/bin/expand 555 root bin > f none usr/bin/factor 555 root bin > +f none usr/bin/getfilecon 555 root bin > f none usr/bin/graph 555 root bin > f none usr/bin/kstat 555 root bin > f none usr/bin/last 555 root bin > @@ -103,6 +104,8 @@ > l none usr/bin/pwait=../../usr/lib/isaexec > l none usr/bin/pwdx=../../usr/lib/isaexec > f none usr/bin/sdiff 555 root bin > +f none usr/bin/setfilecon 555 root bin > +f none usr/bin/setfiles 555 root bin > l none usr/bin/sort=../../usr/lib/isaexec > f none usr/bin/spell 555 root bin > f none usr/bin/spline 555 root bin > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -34,8 +34,11 @@ > #include > #include > #include > +#include > #include > #include > +#include > +#include > > /* Tunables */ > int fmac_enabled = 1; /* policy enabled */ > @@ -125,3 +128,194 @@ > > return (0); > } > + > +security_class_t > +fmac_vtype_to_sclass(vtype_t vtype) > +{ > + switch (vtype) { > + case VREG: > + return (SECCLASS_FILE); > + case VDIR: > + return (SECCLASS_DIR); > + case VBLK: > + return (SECCLASS_BLK_FILE); > + case VCHR: > + return (SECCLASS_CHR_FILE); > + case VLNK: > + return (SECCLASS_LNK_FILE); > + case VFIFO: > + return (SECCLASS_FIFO_FILE); > + case VSOCK: > + return (SECCLASS_SOCK_FILE); > + case VDOOR: > + /* TBD */ > + case VPROC: > + /* TBD */ > + case VPORT: > + /* TBD */ > + case VNON: > + return (SECCLASS_NULL); > + } > + return (SECCLASS_NULL); > +} > + > +int > +fmac_vnode_lookup(vnode_t *vp, cred_t *cr, caller_context_t *ct) > +{ > + int error; > + xvattr_t xvattr; > + xoptattr_t *xoap; > + security_id_t secid; > + > + if (!fmac_enabled) > + return (0); > + if (vp->v_secid != SECINITSID_UNLABELED) > + return (0); /* already set */ > + > + xva_init(&xvattr); > + if ((xoap = xva_getxoptattr(&xvattr)) == NULL) > + return (EINVAL); > + XVA_SET_REQ(&xvattr, XAT_SECCTX); > + > + error = VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct); > + if (error) > + return (error); > + > + if (XVA_ISSET_RTN(&xvattr, XAT_SECCTX)) { > + error = security_context_to_sid(xoap->xoa_secctx, > + strlen(xoap->xoa_secctx), &secid); > + if (error) > + return (error); > + } else { > + /* default SID for files without a secctx. */ > + secid = SECINITSID_FILE; > + } > + > + mutex_enter(&(vp->v_lock)); > + if (vp->v_secid == SECINITSID_UNLABELED) > + vp->v_secid = secid; > + mutex_exit(&(vp->v_lock)); > + > + return (0); > +} > + > +int > +fmac_vnode_set_secctx(char *secctx, cred_t *cr, vtype_t vtype, vnode_t *vp) > +{ > + security_id_t cr_secid, old_secid, new_secid; > + security_class_t sclass; > + int error; > + > + if (!fmac_enabled) > + return (EINVAL); > + > + cr_secid = crgetsecid(cr); > + > + sclass = fmac_vtype_to_sclass(vtype); > + if (!sclass) > + return (EINVAL); > + > + error = security_context_to_sid(secctx, strlen(secctx), &new_secid); > + if (error) > + return (error); > + > + if (vp) { > + /* > + * Relabeling an existing file. > + */ > + mutex_enter(&(vp->v_lock)); > + old_secid = vp->v_secid; > + error = avc_has_perm(cr_secid, old_secid, sclass, > + FILE__RELABELFROM); > + if (!error) > + error = avc_has_perm(cr_secid, new_secid, sclass, > + FILE__RELABELTO); > + vp->v_secid = new_secid; > + mutex_exit(&(vp->v_lock)); > + } else { > + /* Creating a new file. */ > + error = avc_has_perm(cr_secid, new_secid, sclass, > + FILE__CREATE); > + } > + > + return (error); > +} > + > +int > +fmac_vnode_create(vnode_t *dvp, char *name, xvattr_t *xvap, vattr_t **vapp, > + cred_t *cr, security_id_t *secidp) > +{ > + security_id_t cr_secid, secid; > + security_class_t sclass; > + security_context_t scontext; > + uint32_t scontext_len; > + xoptattr_t *xoap; > + int error; > + > + _NOTE(ARGUNUSED(name)); /* future use in audit message */ > + > + if (!fmac_enabled) > + return (0); > + > + /* > + * Make sure we define a default secid for use by > + * fmac_vnode_post_create even if the fs does not > + * support xvattrs. > + */ > + *secidp = SECINITSID_FILE; > + > + if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR) == 0) > + return (0); > + > + sclass = fmac_vtype_to_sclass((*vapp)->va_type); > + if (!sclass) > + return (0); > + > + cr_secid = crgetsecid(cr); > + > + /* > + * Wrap the vattr with an xvattr so we can pass the > + * secctx to the fs code. > + */ > + xva_init(xvap); > + (void) memcpy(&xvap->xva_vattr, *vapp, sizeof (vattr_t)); > + xvap->xva_vattr.va_mask |= AT_XVATTR; /* reset after memcpy */ > + XVA_SET_REQ(xvap, XAT_SECCTX); > + > + error = security_transition_sid(cr_secid, dvp->v_secid, sclass, > + &secid); > + if (error) > + return (error); > + > + error = security_sid_to_context(secid, &scontext, &scontext_len); > + if (error) > + return (error); > + > + if (scontext_len > sizeof (xoap->xoa_secctx)) > + return (EINVAL); > + > + xoap = xva_getxoptattr(xvap); > + if (!xoap) > + return (EINVAL); > + (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx)); > + > + *secidp = secid; > + > + /* > + * Switch the vap pointer to the newly populated xvattr. > + * fop_create/fop_mkdir will then pass the xvattr along to > + * the underlying fs code. The original vattr is not mutated. > + */ > + *vapp = &xvap->xva_vattr; > + return (0); > +} > + > +void > +fmac_vnode_post_create(vnode_t *vp, security_id_t secid) > +{ > + if (!fmac_enabled) > + return; > + mutex_enter(&(vp->v_lock)); > + vp->v_secid = secid; > + mutex_exit(&(vp->v_lock)); > +} > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -61,6 +61,8 @@ > #include > #include > #include > +#include > +#include > #include > #include > #include > @@ -2309,6 +2311,7 @@ > vp->v_flag = 0; > vp->v_type = VNON; > vp->v_rdev = NODEV; > + vp->v_secid = SECINITSID_UNLABELED; > > vp->v_filocks = NULL; > vp->v_shrlocks = NULL; > @@ -3333,6 +3336,7 @@ > (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp); > } > if (ret == 0 && *vpp) { > + (void) fmac_vnode_lookup(*vpp, cr, ct); > VOPSTATS_UPDATE(*vpp, lookup); > if ((*vpp)->v_path == NULL) { > vn_setpath(rootdir, dvp, *vpp, nm, strlen(nm)); > @@ -3356,6 +3360,8 @@ > vsecattr_t *vsecp) /* ACL to set during create */ > { > int ret; > + xvattr_t xvattr; > + security_id_t secid; > > if (vsecp != NULL && > vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) { > @@ -3369,12 +3375,17 @@ > (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && > vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) > return (EINVAL); > + > + ret = fmac_vnode_create(dvp, name, &xvattr, &vap, cr, &secid); > + if (ret) > + return (ret); > > VOPXID_MAP_CR(dvp, cr); > > ret = (*(dvp)->v_op->vop_create) > (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp); > if (ret == 0 && *vpp) { > + fmac_vnode_post_create(*vpp, secid); > VOPSTATS_UPDATE(*vpp, create); > if ((*vpp)->v_path == NULL) { > vn_setpath(rootdir, dvp, *vpp, name, strlen(name)); > @@ -3477,6 +3488,8 @@ > int flags, > vsecattr_t *vsecp) /* ACL to set during create */ > { > + xvattr_t xvattr; > + security_id_t secid; > int ret; > > if (vsecp != NULL && > @@ -3491,12 +3504,17 @@ > (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 && > vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)) > return (EINVAL); > + > + ret = fmac_vnode_create(dvp, dirname, &xvattr, &vap, cr, &secid); > + if (ret) > + return (ret); > > VOPXID_MAP_CR(dvp, cr); > > ret = (*(dvp)->v_op->vop_mkdir) > (dvp, dirname, vap, vpp, cr, ct, flags, vsecp); > if (ret == 0 && *vpp) { > + fmac_vnode_post_create(*vpp, secid); > VOPSTATS_UPDATE(*vpp, mkdir); > if ((*vpp)->v_path == NULL) { > vn_setpath(rootdir, dvp, *vpp, dirname, > diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c > --- a/usr/src/uts/common/fs/xattr.c > +++ b/usr/src/uts/common/fs/xattr.c > @@ -214,6 +214,9 @@ > VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr), > fsid) == 0); > break; > + case F_SECCTX: > + XVA_SET_REQ(&xvattr, XAT_SECCTX); > + break; > default: > break; > } > @@ -288,6 +291,11 @@ > attr_to_name(F_AV_SCANSTAMP), > xoap->xoa_av_scanstamp, > sizeof (xoap->xoa_av_scanstamp)) == 0); > + } > + if (XVA_ISSET_RTN(&xvattr, XAT_SECCTX)) { > + VERIFY(nvlist_add_string(nvlp, > + attr_to_name(F_SECCTX), > + xoap->xoa_secctx) == 0); > } > if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) { > VERIFY(nvlist_add_uint64_array(nvlp, > @@ -511,6 +519,7 @@ > uint_t elem, nelems; > nvlist_t *nvp_sid; > uint8_t *scanstamp; > + char *secctx = NULL; > > /* > * Validate the name and type of each attribute. > @@ -569,6 +578,12 @@ > case DATA_TYPE_UINT8_ARRAY: > if (nvpair_value_uint8_array(pair, > &scanstamp, &nelems)) { > + nvlist_free(nvp); > + return (EINVAL); > + } > + break; > + case DATA_TYPE_STRING: > + if (nvpair_value_string(pair, &secctx)) { > nvlist_free(nvp); > return (EINVAL); > } > @@ -665,6 +680,16 @@ > nvlist_free(nvp); > return (EINVAL); > } > + break; > + case F_SECCTX: > + if (!secctx || > + strlen(secctx) >= sizeof (xoap->xoa_secctx)) { > + nvlist_free(nvp); > + return (EINVAL); > + } > + XVA_SET_REQ(&xvattr, XAT_SECCTX); > + (void) strncpy(xoap->xoa_secctx, secctx, > + sizeof (xoap->xoa_secctx)); > break; > default: > break; > diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h > --- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h > +++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h > @@ -77,6 +77,7 @@ > #define ZFS_ACL_DEFAULTED 0x20 /* ACL should be defaulted */ > #define ZFS_ACL_AUTO_INHERIT 0x40 /* ACL should be inherited */ > #define ZFS_BONUS_SCANSTAMP 0x80 /* Scanstamp in bonus area */ > +#define ZFS_BONUS_SECCTX 0x100 /* Secctx in bonus area */ > > /* > * Is ID ephemeral? > @@ -159,6 +160,7 @@ > * At present, we use this space for the following: > * - symbolic links > * - 32-byte anti-virus scanstamp (regular files only) > + * - security context > */ > } znode_phys_t; > > @@ -333,7 +335,7 @@ > znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp); > extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp, > vsecattr_t *vsecp, zfs_fuid_info_t *fuidp); > -extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap); > +extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx); > extern void zfs_upgrade(zfsvfs_t *zfsvfs, dmu_tx_t *tx); > > extern caddr_t zfs_map_page(page_t *, enum seg_rw); > diff --git a/usr/src/uts/common/fs/zfs/sys/zil.h b/usr/src/uts/common/fs/zfs/sys/zil.h > --- a/usr/src/uts/common/fs/zfs/sys/zil.h > +++ b/usr/src/uts/common/fs/zfs/sys/zil.h > @@ -98,13 +98,13 @@ > * size of xvattr log section. > * its composed of lr_attr_t + xvattr bitmap + 2 64 bit timestamps > * for create time and a single 64 bit integer for all of the attributes, > - * and 4 64 bit integers (32 bytes) for the scanstamp. > - * > + * and either 4 64 bit integers (32 bytes) for the scanstamp or > + * 56 bytes for the security context. > */ > > #define ZIL_XVAT_SIZE(mapsize) \ > sizeof (lr_attr_t) + (sizeof (uint32_t) * (mapsize - 1)) + \ > - (sizeof (uint64_t) * 7) > + (sizeof (uint64_t) * 7) + 24 > > /* > * Size of ACL in log. The ACE data is padded out to properly align > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > @@ -1868,7 +1868,7 @@ > > /* Set optional attributes if any */ > if (vap->va_mask & AT_XVATTR) > - zfs_xvattr_set(zp, xvap); > + zfs_xvattr_set(zp, xvap, tx); > > mutex_exit(&zp->z_lock); > mutex_exit(&zp->z_acl_lock); > diff --git a/usr/src/uts/common/fs/zfs/zfs_log.c b/usr/src/uts/common/fs/zfs/zfs_log.c > --- a/usr/src/uts/common/fs/zfs/zfs_log.c > +++ b/usr/src/uts/common/fs/zfs/zfs_log.c > @@ -101,7 +101,7 @@ > uint64_t *attrs; > uint64_t *crtime; > xoptattr_t *xoap; > - void *scanstamp; > + void *extradata; /* scanstamp or secctx */ > int i; > > xoap = xva_getxoptattr(xvap); > @@ -116,7 +116,7 @@ > /* Now pack the attributes up in a single uint64_t */ > attrs = (uint64_t *)bitmap; > crtime = attrs + 1; > - scanstamp = (caddr_t)(crtime + 2); > + extradata = (caddr_t)(crtime + 2); > *attrs = 0; > if (XVA_ISSET_REQ(xvap, XAT_READONLY)) > *attrs |= (xoap->xoa_readonly == 0) ? 0 : > @@ -154,7 +154,9 @@ > if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) > ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime); > if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) > - bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ); > + bcopy(xoap->xoa_av_scanstamp, extradata, AV_SCANSTAMP_SZ); > + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) > + bcopy(xoap->xoa_secctx, extradata, SECCTX_SZ); > } > > static void * > diff --git a/usr/src/uts/common/fs/zfs/zfs_replay.c b/usr/src/uts/common/fs/zfs/zfs_replay.c > --- a/usr/src/uts/common/fs/zfs/zfs_replay.c > +++ b/usr/src/uts/common/fs/zfs/zfs_replay.c > @@ -83,7 +83,7 @@ > uint64_t *attrs; > uint64_t *crtime; > uint32_t *bitmap; > - void *scanstamp; > + void *extradata; /* scanstamp or secctx */ > int i; > > xvap->xva_vattr.va_mask |= AT_XVATTR; > @@ -100,7 +100,7 @@ > > attrs = (uint64_t *)(lrattr + lrattr->lr_attr_masksize - 1); > crtime = attrs + 1; > - scanstamp = (caddr_t)(crtime + 2); > + extradata = (caddr_t)(crtime + 2); > > if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) > xoap->xoa_hidden = ((*attrs & XAT0_HIDDEN) != 0); > @@ -128,7 +128,9 @@ > if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) > ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime); > if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) > - bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); > + bcopy(extradata, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); > + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) > + bcopy(extradata, xoap->xoa_secctx, SECCTX_SZ); > } > > static int > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -1182,7 +1182,7 @@ > > if (vap->va_mask & AT_XVATTR) { > if ((error = secpolicy_xvattr((xvattr_t *)vap, > - crgetuid(cr), cr, vap->va_type)) != 0) { > + crgetuid(cr), cr, vap->va_type, NULL)) != 0) { > ZFS_EXIT(zfsvfs); > return (error); > } > @@ -1637,7 +1637,7 @@ > > if (vap->va_mask & AT_XVATTR) > if ((error = secpolicy_xvattr((xvattr_t *)vap, > - crgetuid(cr), cr, vap->va_type)) != 0) { > + crgetuid(cr), cr, vap->va_type, NULL)) != 0) { > ZFS_EXIT(zfsvfs); > return (error); > } > @@ -2316,6 +2316,28 @@ > pzp + 1, > sizeof (xoap->xoa_av_scanstamp)); > XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); > + } > + } > + > + if (XVA_ISSET_REQ(xvap, XAT_SECCTX) && > + vp->v_type != VLNK && > + (pzp->zp_flags & ZFS_BONUS_SECCTX)) { > + size_t len = 0; > + dmu_object_info_t doi; > + > + dmu_object_info_from_db(zp->z_dbuf, &doi); > + len = sizeof (xoap->xoa_secctx) + > + sizeof (znode_phys_t); > + if (len <= doi.doi_bonus_size) { > + /* > + * pzp points to the start of the > + * znode_phys_t. pzp + 1 points to the > + * first byte after the znode_phys_t. > + */ > + (void) memcpy(xoap->xoa_secctx, > + pzp + 1, > + sizeof (xoap->xoa_secctx)); > + XVA_SET_RTN(xvap, XAT_SECCTX); > } > } > > @@ -2570,6 +2592,7 @@ > xoap->xoa_av_quarantined != > ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)))) || > (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) || > + (XVA_ISSET_REQ(xvap, XAT_SECCTX)) || > (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { > need_policy = TRUE; > } > @@ -2762,22 +2785,8 @@ > * update from toggling bit > */ > > - if (xoap && (mask & AT_XVATTR)) { > - if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { > - size_t len; > - dmu_object_info_t doi; > - > - ASSERT(vp->v_type == VREG); > - > - /* Grow the bonus buffer if necessary. */ > - dmu_object_info_from_db(zp->z_dbuf, &doi); > - len = sizeof (xoap->xoa_av_scanstamp) + > - sizeof (znode_phys_t); > - if (len > doi.doi_bonus_size) > - VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); > - } > - zfs_xvattr_set(zp, xvap); > - } > + if (xoap && (mask & AT_XVATTR)) > + zfs_xvattr_set(zp, xvap, tx); > > if (mask != 0) > zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp); > diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c > --- a/usr/src/uts/common/fs/zfs/zfs_znode.c > +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c > @@ -851,9 +851,16 @@ > } > > void > -zfs_xvattr_set(znode_t *zp, xvattr_t *xvap) > +zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx) > { > xoptattr_t *xoap; > + size_t len; > + dmu_object_info_t doi; > + vnode_t *vp; > + znode_phys_t *pzp; > + > + vp = ZTOV(zp); > + pzp = zp->z_phys; > > xoap = xva_getxoptattr(xvap); > ASSERT(xoap); > @@ -907,11 +914,51 @@ > ZFS_ATTR_SET(zp, ZFS_AV_MODIFIED, xoap->xoa_av_modified); > XVA_SET_RTN(xvap, XAT_AV_MODIFIED); > } > + if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) && > + XVA_ISSET_REQ(xvap, XAT_SECCTX)) { > + /* > + * The av scanstamp and the secctx are presently > + * exclusive of one another as they are both stored > + * in the bonus buffer. > + */ > + return; > + } > if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { > + ASSERT(vp->v_type == VREG); > + > + /* Don't allow a secctx to be overwritten by a scanstamp. */ > + if (pzp->zp_flags & ZFS_BONUS_SECCTX) > + return; > + > + /* Grow the bonus buffer if necessary. */ > + dmu_object_info_from_db(zp->z_dbuf, &doi); > + len = sizeof (xoap->xoa_av_scanstamp) + > + sizeof (znode_phys_t); > + if (len > doi.doi_bonus_size) > + VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); > + > (void) memcpy(zp->z_phys + 1, xoap->xoa_av_scanstamp, > sizeof (xoap->xoa_av_scanstamp)); > zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP; > XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP); > + } > + if (XVA_ISSET_REQ(xvap, XAT_SECCTX)) { > + ASSERT(vp->v_type != VLNK); > + > + /* Don't allow a scanstamp to be overwritten by a secctx. */ > + if (pzp->zp_flags & ZFS_BONUS_SCANSTAMP) > + return; > + > + /* Grow the bonus buffer if necessary. */ > + dmu_object_info_from_db(zp->z_dbuf, &doi); > + len = sizeof (xoap->xoa_secctx) + > + sizeof (znode_phys_t); > + if (len > doi.doi_bonus_size) > + VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0); > + (void) memcpy(zp->z_phys + 1, xoap->xoa_secctx, > + sizeof (xoap->xoa_secctx)); > + zp->z_phys->zp_flags |= ZFS_BONUS_SECCTX; > + XVA_SET_RTN(xvap, XAT_SECCTX); > } > } > > diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c > --- a/usr/src/uts/common/os/policy.c > +++ b/usr/src/uts/common/os/policy.c > @@ -42,6 +42,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -1060,7 +1061,8 @@ > * Check privileges for setting xvattr attributes > */ > int > -secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) > +secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype, > + vnode_t *vp /* NULL on create */) > { > xoptattr_t *xoap; > int error = 0; > @@ -1112,6 +1114,12 @@ > xoap->xoa_av_scanstamp, cr); > if (error == 0 && vtype != VREG) > error = EINVAL; > + } > + if (error == 0 && XVA_ISSET_REQ(xvap, XAT_SECCTX)) { > + error = secpolicy_vnode_owner(cr, owner); > + if (!error) > + error = fmac_vnode_set_secctx(xoap->xoa_secctx, cr, > + vtype, vp); > } > return (error); > } > @@ -1268,7 +1276,7 @@ > */ > if (mask & AT_XVATTR) > error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr, > - vp->v_type); > + vp->v_type, vp); > out: > return (error); > } > diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h > --- a/usr/src/uts/common/sys/attr.h > +++ b/usr/src/uts/common/sys/attr.h > @@ -56,6 +56,7 @@ > #define A_AV_SCANSTAMP "av_scanstamp" > #define A_OWNERSID "ownersid" > #define A_GROUPSID "groupsid" > +#define A_SECCTX "secctx" > > /* Attribute option for utilities */ > #define O_HIDDEN "H" > @@ -92,6 +93,7 @@ > F_OWNERSID, > F_GROUPSID, > F_FSID, > + F_SECCTX, > F_ATTR_ALL > } f_attr_t; > > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -33,6 +33,7 @@ > > #if defined(_KERNEL) > #include > +#include > #else > #include > #endif /* _KERNEL */ > @@ -83,6 +84,11 @@ > extern char *fmac_default_policy_file; > void fmac_init(void); > int fmac_load_policy(char *file); > +int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); > +int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *); > +int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > + security_id_t *); > +void fmac_vnode_post_create(vnode_t *, security_id_t); > #endif /* _KERNEL */ > > #ifdef __cplusplus > diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h > --- a/usr/src/uts/common/sys/policy.h > +++ b/usr/src/uts/common/sys/policy.h > @@ -32,6 +32,7 @@ > #include > #include > #include > +#include > > #ifdef __cplusplus > extern "C" { > @@ -160,7 +161,7 @@ > void secpolicy_fs_mount_clearopts(cred_t *, struct vfs *); > int secpolicy_setid_setsticky_clear(vnode_t *, vattr_t *, > const vattr_t *, cred_t *); > -int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t); > +int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t, vnode_t *); > int secpolicy_xvm_control(const cred_t *); > > int secpolicy_basic_exec(const cred_t *, vnode_t *); > diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h > --- a/usr/src/uts/common/sys/vnode.h > +++ b/usr/src/uts/common/sys/vnode.h > @@ -52,6 +52,7 @@ > #include > #include > #include > +#include > #ifdef _KERNEL > #include > #endif /* _KERNEL */ > @@ -195,6 +196,7 @@ > * v_path > * v_vsd > * v_xattrdir > + * v_secid > * > * A special lock (implemented by vn_vfswlock in vnode.c) protects: > * v_vfsmountedhere > @@ -233,6 +235,7 @@ > struct stdata *v_stream; /* associated stream */ > enum vtype v_type; /* vnode type */ > dev_t v_rdev; /* device (VCHR, VBLK) */ > + security_id_t v_secid; /* FMAC security identifier */ > > /* PRIVATE FIELDS BELOW - DO NOT USE */ > > @@ -364,6 +367,8 @@ > } vattr_t; > > #define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */ > +#define SECCTX_SZ 56 /* length of secctx */ > +/* XXX: This should be variable sized and support large sizes. TBD. */ > > /* > * Structure of all optional attributes. > @@ -382,6 +387,7 @@ > uint8_t xoa_av_quarantined; > uint8_t xoa_av_modified; > uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ]; > + char xoa_secctx[SECCTX_SZ]; > } xoptattr_t; > > /* > @@ -560,11 +566,12 @@ > #define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */ > #define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */ > #define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */ > +#define XAT0_SECCTX 0x00002000 /* security context */ > > #define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \ > XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \ > XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| \ > - XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP) > + XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP|XAT0_SECCTX) > > /* Support for XAT_* optional attributes */ > #define XVA_MASK 0xffffffff /* Used to mask off 32 bits */ > @@ -597,6 +604,7 @@ > #define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED) > #define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED) > #define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP) > +#define XAT_SECCTX ((XAT0_INDEX << XVA_SHFT) | XAT0_SECCTX) > > /* > * The returned attribute map array (xva_rtnattrmap[]) is located past the > > > > From john.weeks at sun.com Tue Sep 9 12:39:43 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 09 Sep 2008 12:39:43 -0700 Subject: [fmac-discuss] [PATCH v2] Basic process security context transition support In-Reply-To: <1220882334.19241.38.camel@moss-spartans.epoch.ncsc.mil> References: <1220882334.19241.38.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C6D0FF.9020401@sun.com> Acked-by: John Weeks Stephen Smalley wrote: > Implement basic process security context transition support, leveraging > the prior patch for file security contexts on executables. With this > support and a suitable labeled filesystem and policy, processes will > automatically transition into an appropriate security context when they > execute a program based on the program file's security context, and a > process may explicitly transition to a given security context if > authorized via the already existing setexeccon() interface. > > This only implements the core logic for a transition; a number of other > checks will be added later, such as a check to decide whether the linker > security flag needs to be set on the transition, ptrace-related > checking, checks on the inheritance of state such as open file > descriptors, the normal file execute check applied via VOP_ACCESS, > mmap/mprotect PROT_EXEC checks, etc. > > The checks applied here are: > - If not transitioning, may the process execute the file without > transitioning to a new security context (:file execute_no_trans)? > - If transitioning, may the process transition to the new security > context (:process transition) and may the new process security context > be entered via a program with this file security context (:file > entrypoint)? > > Changes since the prior version of this patch include: > - setsecid changed from int to boolean_t, with B_TRUE and B_FALSE as > values. > > Webrev available at: http://cr.opensolaris.org/~sds/exec/ > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -319,3 +319,46 @@ > vp->v_secid = secid; > mutex_exit(&(vp->v_lock)); > } > + > +int > +fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp) > +{ > + security_id_t prev_secid, secid; > + int error; > + > + if (!fmac_enabled) > + return (0); > + > + prev_secid = crgetsecid(cr); > + secid = crgetexecsecid(cr); > + if (!secid) { > + error = security_transition_sid(prev_secid, vp->v_secid, > + SECCLASS_PROCESS, &secid); > + if (error) > + return (error); > + } > + > + if (prev_secid == secid) { > + error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, > + FILE__EXECUTE_NO_TRANS); > + if (error) > + return (error); > + *setsecid = B_FALSE; > + return (0); > + } > + > + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, > + PROCESS__TRANSITION); > + if (error) > + return (error); > + > + error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, > + FILE__ENTRYPOINT); > + if (error) > + return (error); > + *setsecid = B_TRUE; > + *prev_secidp = prev_secid; > + *secidp = secid; > + return (0); > +} > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > --- a/usr/src/uts/common/os/exec.c > +++ b/usr/src/uts/common/os/exec.c > @@ -68,6 +68,7 @@ > #include > #include > #include > +#include > > #include > > @@ -522,6 +523,8 @@ > int suidflags = 0; > ssize_t resid; > uid_t uid, gid; > + security_id_t prev_secid, secid; > + boolean_t setsecid = B_FALSE; > struct vattr vattr; > char magbuf[MAGIC_BYTES]; > int setid; > @@ -562,10 +565,25 @@ > if ((eswp = findexec_by_hdr(magbuf)) == NULL) > goto bad; > > - if (level == 0 && > - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { > + if (level == 0) { > + privflags = execsetid(vp, &vattr, &uid, &gid); > > + error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > + if (error) > + goto bad; > + > + if (setsecid) > + privflags |= PRIV_SETUGID; > + } > + > + if (level == 0 && privflags != 0) { > newcred = cred = crdup(cred); > + > + if (setsecid) { > + cred->cr_prev_secid = prev_secid; > + cred->cr_secid = secid; > + cred->cr_exec_secid = SECSID_NULL; > + } > > /* If we can, drop the PA bit */ > if ((privflags & PRIV_RESET) != 0) > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -89,6 +89,8 @@ > int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > security_id_t *); > void fmac_vnode_post_create(vnode_t *, security_id_t); > +int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > + security_id_t *prev_secidp, security_id_t *secidp); > #endif /* _KERNEL */ > > #ifdef __cplusplus > > From john.weeks at sun.com Tue Sep 9 12:40:16 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 09 Sep 2008 12:40:16 -0700 Subject: [fmac-discuss] [PATCH] File contexts and policy changes In-Reply-To: <1220882394.19241.40.camel@moss-spartans.epoch.ncsc.mil> References: <1220465214.6034.168.camel@moss-spartans.epoch.ncsc.mil> <1220882394.19241.40.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C6D120.9080007@sun.com> Acked-by: John Weeks Stephen Smalley wrote: > On Wed, 2008-09-03 at 14:06 -0400, Stephen Smalley wrote: >> This patch updates the file contexts and policy configurations to allow >> the preceding prototype file security context support and basic security >> context transition support to be demonstrated. After applying all three >> patches, one can do the following: >> # Label filesystems >> $ setfiles /etc/security/fmac/file_contexts / >> $ getfilecon /sbin/init /usr/lib/ssh/sshd /bin/bash >> /sbin/init: system_u:object_r:init_exec_t >> /usr/lib/ssh/sshd: system_u:object_r:sshd_exec_t >> /bin/bash: system_u:object_r:shell_exec_t >> $ reboot >> and then upon logging into the system via ssh, the processes should have >> typical domains for the user shell, sshd daemon, and init processes: >> $ pcon $$ $PPID 1 >> : system_u:system_r:user_t:unclassified >> : system_u:system_r:sshd_t:unclassified >> 1: system_u:system_r:init_t:unclassified >> >> Webrev available at: http://cr.opensolaris.org/~sds/policy/ > > This patch is unchanged from before; please apply the original. > >> diff --git a/usr/src/cmd/fmac/policy/assert.te b/usr/src/cmd/fmac/policy/assert.te >> --- a/usr/src/cmd/fmac/policy/assert.te >> +++ b/usr/src/cmd/fmac/policy/assert.te >> @@ -77,9 +77,8 @@ >> # Verify that the authentication domains are the only other domains >> # that can read this file. >> # >> -neverallow ~{ admin passwd_t } etc_auth_t:dir { add_name remove_name rename }; >> -neverallow ~{ admin passwd_t } etc_auth_t:file { write append unlink rename }; >> -neverallow ~{ admin auth } etc_auth_t:file { read }; >> +neverallow ~{ admin passwd_t } shadow_t:file { write append unlink rename }; >> +neverallow ~{ admin auth } shadow_t:file { read }; >> >> # >> # Verify that only the administrator domain and the >> diff --git a/usr/src/cmd/fmac/policy/domains/every.te b/usr/src/cmd/fmac/policy/domains/every.te >> --- a/usr/src/cmd/fmac/policy/domains/every.te >> +++ b/usr/src/cmd/fmac/policy/domains/every.te >> @@ -179,7 +179,7 @@ >> # Inherit and use descriptors from login. >> allow domain local_login_t:fd inherit_fd_perms; >> allow domain remote_login_t:fd inherit_fd_perms; >> -allow domain sshd_login_t:fd inherit_fd_perms; >> +allow domain sshd_t:fd inherit_fd_perms; >> >> # Create and use NFS files. >> # FIXME! Only grant to domains that truly need this access. >> diff --git a/usr/src/cmd/fmac/policy/domains/program/newrole.te b/usr/src/cmd/fmac/policy/domains/program/newrole.te >> --- a/usr/src/cmd/fmac/policy/domains/program/newrole.te >> +++ b/usr/src/cmd/fmac/policy/domains/program/newrole.te >> @@ -51,8 +51,7 @@ >> allow newrole_t self:capability { setuid setgid net_bind_service dac_override }; >> >> # Read password files >> -allow newrole_t etc_auth_t:dir r_dir_perms; >> -allow newrole_t etc_auth_t:file r_file_perms; >> +allow newrole_t shadow_t:file r_file_perms; >> >> # Write to utmp >> allow newrole_t initrc_var_run_t:file rw_file_perms; >> diff --git a/usr/src/cmd/fmac/policy/domains/program/passwd.te b/usr/src/cmd/fmac/policy/domains/program/passwd.te >> --- a/usr/src/cmd/fmac/policy/domains/program/passwd.te >> +++ b/usr/src/cmd/fmac/policy/domains/program/passwd.te >> @@ -44,17 +44,10 @@ >> allow passwd_t local_login_t:fd inherit_fd_perms; >> allow passwd_t remote_login_t:fd inherit_fd_perms; >> >> -# Execute /usr/bin/{passwd,chfn,chsh}. >> -can_exec(passwd_t, bin_t) >> - >> # Update /etc/passwd. >> allow passwd_t etc_t:dir rw_dir_perms; >> allow passwd_t etc_t:file create_file_perms; >> >> -# Update /etc/auth/shadow. >> -allow passwd_t etc_auth_t:dir rw_dir_perms; >> -allow passwd_t etc_auth_t:file create_file_perms; >> - >> -# /usr/bin/passwd asks for w access to utmp, but it will operate >> -# correctly without it. Do not audit write denials to utmp. >> -auditdeny passwd_t initrc_var_run_t:file ~write; >> +# Update /etc/shadow. >> +allow passwd_t shadow_t:file create_file_perms; >> +file_type_auto_trans(passwd_t, etc_t, shadow_t) >> diff --git a/usr/src/cmd/fmac/policy/domains/program/su.te b/usr/src/cmd/fmac/policy/domains/program/su.te >> --- a/usr/src/cmd/fmac/policy/domains/program/su.te >> +++ b/usr/src/cmd/fmac/policy/domains/program/su.te >> @@ -60,9 +60,8 @@ >> allow $1_su_t $1_gph_t:fd inherit_fd_perms; >> allow $1_t $1_gph_t:fd inherit_fd_perms; >> >> -# Read /etc/auth/shadow. >> -allow $1_su_t etc_auth_t:dir r_dir_perms; >> -allow $1_su_t etc_auth_t:file r_file_perms; >> +# Read /etc/shadow. >> +allow $1_su_t shadow_t:file r_file_perms; >> >> # Write to utmp. >> allow $1_su_t initrc_var_run_t:file rw_file_perms; >> diff --git a/usr/src/cmd/fmac/policy/domains/system/ftpd.te b/usr/src/cmd/fmac/policy/domains/system/ftpd.te >> --- a/usr/src/cmd/fmac/policy/domains/system/ftpd.te >> +++ b/usr/src/cmd/fmac/policy/domains/system/ftpd.te >> @@ -55,9 +55,8 @@ >> # Create pid files. >> file_type_auto_trans(ftpd_t, var_run_t, ftpd_var_run_t) >> >> -# Read /etc/auth/shadow. >> -allow ftpd_t etc_auth_t:dir r_dir_perms; >> -allow ftpd_t etc_auth_t:file r_file_perms; >> +# Read /etc/shadow. >> +allow ftpd_t shadow_t:file r_file_perms; >> >> # Append to /var/log/wtmp. >> allow ftpd_t wtmp_t:file append; >> diff --git a/usr/src/cmd/fmac/policy/domains/system/init.te b/usr/src/cmd/fmac/policy/domains/system/init.te >> --- a/usr/src/cmd/fmac/policy/domains/system/init.te >> +++ b/usr/src/cmd/fmac/policy/domains/system/init.te >> @@ -46,8 +46,7 @@ >> # Run /etc/rc.sysinit, /etc/rc, /etc/rc.local in the initrc_t domain. >> domain_auto_trans(init_t, initrc_exec_t, initrc_t) >> >> -# Run the shell or sulogin in the sysadm_t domain for single-user mode. >> -domain_auto_trans(init_t, shell_exec_t, sysadm_t) >> +# Run sulogin in the sysadm_t domain for single-user mode. >> domain_auto_trans(init_t, sulogin_exec_t, sysadm_t) >> >> # Run mingetty in its own domain. >> diff --git a/usr/src/cmd/fmac/policy/domains/system/login.te b/usr/src/cmd/fmac/policy/domains/system/login.te >> --- a/usr/src/cmd/fmac/policy/domains/system/login.te >> +++ b/usr/src/cmd/fmac/policy/domains/system/login.te >> @@ -75,9 +75,8 @@ >> allow local_login_t var_lock_t:dir rw_dir_perms; >> allow local_login_t var_lock_t:file create_file_perms; >> >> -# Read /etc/auth/shadow. >> -allow local_login_t etc_auth_t:dir r_dir_perms; >> -allow local_login_t etc_auth_t:file r_file_perms; >> +# Read /etc/shadow. >> +allow local_login_t shadow_t:file r_file_perms; >> >> # Search for mail spool file. >> allow local_login_t mail_spool_t:dir r_dir_perms; >> @@ -123,9 +122,8 @@ >> # Write to /var/log/lastlog. >> allow remote_login_t var_log_t:file rw_file_perms; >> >> -# Read /etc/auth/shadow. >> -allow remote_login_t etc_auth_t:dir r_dir_perms; >> -allow remote_login_t etc_auth_t:file r_file_perms; >> +# Read /etc/shadow. >> +allow remote_login_t shadow_t:file r_file_perms; >> >> # Search for mail spool file. >> allow remote_login_t mail_spool_t:dir r_dir_perms; >> diff --git a/usr/src/cmd/fmac/policy/domains/system/rlogind.te b/usr/src/cmd/fmac/policy/domains/system/rlogind.te >> --- a/usr/src/cmd/fmac/policy/domains/system/rlogind.te >> +++ b/usr/src/cmd/fmac/policy/domains/system/rlogind.te >> @@ -64,7 +64,6 @@ >> # Modify /var/log/wtmp. >> allow rlogind_t wtmp_t:file rw_file_perms; >> >> -# Read /etc/auth/shadow. >> -allow rlogind_t etc_auth_t:dir r_dir_perms; >> -allow rlogind_t etc_auth_t:file r_file_perms; >> +# Read /etc/shadow. >> +allow rlogind_t shadow_t:file r_file_perms; >> >> diff --git a/usr/src/cmd/fmac/policy/domains/system/rshd.te b/usr/src/cmd/fmac/policy/domains/system/rshd.te >> --- a/usr/src/cmd/fmac/policy/domains/system/rshd.te >> +++ b/usr/src/cmd/fmac/policy/domains/system/rshd.te >> @@ -44,18 +44,10 @@ >> can_network(rshd_t) >> >> # Run shells in user_t. >> -# Commented out - modified rshd removed from distribution for now. >> -#domain_auto_trans(rshd_t, shell_exec_t, user_t) >> +domain_auto_trans(rshd_t, shell_exec_t, user_t) >> >> # Send SIGCHLD to inetd on death. >> allow rshd_t inetd_t:process sigchld; >> >> # Allow socket ioctls not handled by other, more specific permissions. >> allow rshd_t kernel_t:system net_io_control; >> - >> -# in.rshd likes to search /etc/auth and read & getattr /etc/auth/shadow. >> -# in.rshd will operate correctly without these (dangerous) permissions, >> -# so the rshd_t domain does not provide them. We tell the avc not to >> -# log failures for these permissions. >> -auditdeny rshd_t etc_auth_t:dir ~search; >> -auditdeny rshd_t etc_auth_t:file ~{read getattr}; >> diff --git a/usr/src/cmd/fmac/policy/domains/system/sshd.te b/usr/src/cmd/fmac/policy/domains/system/sshd.te >> --- a/usr/src/cmd/fmac/policy/domains/system/sshd.te >> +++ b/usr/src/cmd/fmac/policy/domains/system/sshd.te >> @@ -33,8 +33,7 @@ >> # sshd_exec_t is the type of the sshd executable. >> # sshd_key_t is the type of the ssh private key files >> # >> -type sshd_t, domain, privlog; >> -type sshd_login_t, domain, privuser, privrole, privlog, auth, privowner; >> +type sshd_t, domain, privuser, privrole, privlog, auth; >> type sshd_exec_t, file_type, exec_type; >> type sshd_key_t, file_type; >> >> @@ -46,9 +45,6 @@ >> >> # Can create pty's >> can_create_pty(sshd) >> - >> -# Execute Login >> -domain_auto_trans(sshd_t, login_exec_t, sshd_login_t) >> >> # Fetch shell attributes >> allow sshd_t shell_exec_t:file { getattr }; >> @@ -72,46 +68,15 @@ >> # Append to wtmp >> allow sshd_t wtmp_t:file append; >> >> +# Run shells in user_t by default >> +domain_auto_trans(sshd_t, shell_exec_t, user_t) >> >> -################################# >> -# >> -# Rules for the sshd_login_t domain >> -# >> -# sshd_login_t is the domain of a login process >> -# spawned by sshd >> +# Read /etc/shadow >> +allow sshd_t shadow_t:file r_file_perms; >> >> -# Use capabilities >> -allow sshd_login_t self:capability { setuid setgid chown fowner fsetid net_bind_service sys_tty_config dac_override }; >> - >> -# Use the network >> -can_network(sshd_login_t) >> - >> -# Run shells in user_t by default >> -domain_auto_trans(sshd_login_t, shell_exec_t, user_t) >> - >> -# Use the pty created by sshd >> -allow sshd_login_t sshd_devpts_t:chr_file rw_file_perms; >> - >> -# Write to /var/run/utmp >> -allow sshd_login_t initrc_var_run_t:file rw_file_perms; >> - >> -# Write to /var/log/wtmp >> -allow sshd_login_t wtmp_t:file rw_file_perms; >> - >> -# Write to /var/log/lastlog >> -allow sshd_login_t var_log_t:file rw_file_perms; >> - >> -# Read /etc/auth/shadow >> -allow sshd_login_t etc_auth_t:dir r_dir_perms; >> -allow sshd_login_t etc_auth_t:file r_file_perms; >> - >> -# Search for mail spool file >> -allow sshd_login_t mail_spool_t:dir r_dir_perms; >> -allow sshd_login_t mail_spool_t:file getattr; >> - >> -# Relabel ptys created by sshd >> -allow sshd_login_t sshd_devpts_t:chr_file { relabelfrom relabelto }; >> -allow sshd_login_t user_devpts_t:chr_file { relabelto relabelfrom getattr }; >> +# Relabel ptys. >> +allow sshd_t sshd_devpts_t:chr_file { relabelfrom relabelto }; >> +allow sshd_t user_devpts_t:chr_file { relabelto relabelfrom getattr }; >> >> allow sshd_devpts_t user_devpts_t:chr_file transition; >> allow user_devpts_t sshd_devpts_t:chr_file transition; >> diff --git a/usr/src/cmd/fmac/policy/file_contexts b/usr/src/cmd/fmac/policy/file_contexts >> --- a/usr/src/cmd/fmac/policy/file_contexts >> +++ b/usr/src/cmd/fmac/policy/file_contexts >> @@ -69,49 +69,25 @@ >> # >> / system_u:object_r:root_t >> >> -# >> -# The policy configuration and its sources. >> -# >> -/etc/security/fmac/ss_policy system_u:object_r:policy_config_t >> - >> # >> # The superuser home directory. >> # >> -/root(|/.*) system_u:object_r:sysadm_home_t >> -/root/\.netscape(|/.*) system_u:object_r:sysadm_netscape_rw_t >> -/root/\.mime\.types system_u:object_r:sysadm_netscape_rw_t >> -/root/\.mailcap system_u:object_r:sysadm_netscape_rw_t >> - >> +/root(/.*)? system_u:object_r:sysadm_home_t >> >> # >> # Other user home directories. >> # >> -/home(|/.*) system_u:object_r:user_home_t >> -/home/.*/\.netscape(|/.*) system_u:object_r:user_netscape_rw_t >> -/home/.*/\.mime\.types system_u:object_r:user_netscape_rw_t >> -/home/.*/\.mailcap system_u:object_r:user_netscape_rw_t >> - >> -# >> -# /bin >> -# >> -/bin(|/.*) system_u:object_r:bin_t >> -/bin/login system_u:object_r:login_exec_t >> -/bin/tcsh system_u:object_r:shell_exec_t >> -/bin/bash system_u:object_r:shell_exec_t >> -/bin/ash system_u:object_r:shell_exec_t >> -/bin/su system_u:object_r:su_exec_t >> -/bin/ls system_u:object_r:ls_exec_t >> +/home(/.*)? system_u:object_r:user_home_t >> >> # >> # /boot >> # >> -/boot(|/.*) system_u:object_r:boot_t >> -/boot/kernel.h system_u:object_r:boot_runtime_t >> +/boot(/.*)? system_u:object_r:boot_t >> >> # >> -# /dev >> +# /dev >> # >> -/dev(|/.*) system_u:object_r:device_t >> +/dev(/.*)? system_u:object_r:device_t >> /dev/null system_u:object_r:null_device_t >> /dev/zero system_u:object_r:zero_device_t >> /dev/console system_u:object_r:console_device_t >> @@ -142,238 +118,141 @@ >> # >> # /etc >> # >> -/etc(|/.*) system_u:object_r:etc_t >> -/etc/rc.d/rc system_u:object_r:initrc_exec_t >> -/etc/rc.d/rc.sysinit system_u:object_r:initrc_exec_t >> -/etc/rc.d/rc.local system_u:object_r:initrc_exec_t >> -/etc/auth(|/.*) system_u:object_r:etc_auth_t >> +/etc(/.*)? system_u:object_r:etc_t >> +/etc/shadow system_u:object_r:shadow_t >> +/etc/security/fmac/ss_policy system_u:object_r:policy_config_t >> /etc/aliases system_u:object_r:etc_aliases_t >> -/etc/aliases.db system_u:object_r:etc_aliases_t >> -/etc/mail(|/.*) system_u:object_r:etc_mail_t >> -/etc/conf.modules system_u:object_r:modules_conf_t >> -/etc/HOSTNAME system_u:object_r:etc_runtime_t >> -/etc/ioctl.save system_u:object_r:etc_runtime_t >> -/etc/mtab system_u:object_r:etc_runtime_t >> -/etc/issue system_u:object_r:etc_runtime_t >> -/etc/issue.net system_u:object_r:etc_runtime_t >> -/etc/crontab system_u:object_r:system_crond_script_t >> -/etc/cron.d(|/.*) system_u:object_r:system_crond_script_t >> -/etc/security/cron_context.* system_u:object_r:cron_context_t >> -/etc/ssh_host_key system_u:object_r:sshd_key_t >> -/etc/ssh_random_seed system_u:object_r:sshd_key_t >> +/etc/mail(/.*)? system_u:object_r:etc_mail_t >> +/etc/mail/aliases system_u:object_r:etc_aliases_t >> +/etc/mail/aliases.db system_u:object_r:etc_aliases_t >> +/etc/cron.d(/.*)? system_u:object_r:system_crond_script_t >> +/etc/ssh/ssh_host_dsa_key system_u:object_r:sshd_key_t >> +/etc/ssh/ssh_host_rsa_key system_u:object_r:sshd_key_t >> >> # >> # /lib >> # >> -/lib(|/.*) system_u:object_r:lib_t >> +/lib(/.*)? system_u:object_r:lib_t >> +/lib/svc/bin/svc.startd system_u:object_r:initrc_exec_t >> +/lib/svc/bin/svc.configd system_u:object_r:initrc_exec_t >> /lib/ld.*\.so.* system_u:object_r:ld_so_t >> /lib/lib.*\.so.* system_u:object_r:shlib_t >> -/lib/security/.*\.so.* system_u:object_r:shlib_t >> -/lib/modules(|/.*) system_u:object_r:modules_object_t >> -/lib/modules/[^/]*/modules\.dep system_u:object_r:modules_dep_t >> >> # >> # /sbin >> # >> -/sbin(|/.*) system_u:object_r:sbin_t >> +/sbin(/.*)? system_u:object_r:sbin_t >> +/sbin/sh system_u:object_r:shell_exec_t >> /sbin/ifconfig system_u:object_r:ifconfig_exec_t >> -/sbin/depmod system_u:object_r:depmod_exec_t >> -/sbin/modprobe system_u:object_r:modprobe_exec_t >> -/sbin/insmod system_u:object_r:insmod_exec_t >> -/sbin/insmod.static system_u:object_r:insmod_exec_t >> -/sbin/rmmod system_u:object_r:rmmod_exec_t >> -/sbin/rmmod.static system_u:object_r:rmmod_exec_t >> /sbin/init system_u:object_r:init_exec_t >> /sbin/sulogin system_u:object_r:sulogin_exec_t >> -/sbin/mingetty system_u:object_r:getty_exec_t >> -/sbin/getty system_u:object_r:getty_exec_t >> -/sbin/uugetty system_u:object_r:getty_exec_t >> -/sbin/syslogd system_u:object_r:syslogd_exec_t >> -/sbin/minilogd system_u:object_r:syslogd_exec_t >> -/sbin/klogd system_u:object_r:klogd_exec_t >> -/sbin/ypbind system_u:object_r:ypbind_exec_t >> -/sbin/portmap system_u:object_r:portmap_exec_t >> -/sbin/rpc\..* system_u:object_r:rpcd_exec_t >> -/sbin/cardmgr system_u:object_r:cardmgr_exec_t >> -/sbin/fsck system_u:object_r:fsadm_exec_t >> -/sbin/fsck\.ext2 system_u:object_r:fsadm_exec_t >> -/sbin/e2fsck system_u:object_r:fsadm_exec_t >> -/sbin/e2label system_u:object_r:fsadm_exec_t >> -/sbin/mkfs system_u:object_r:fsadm_exec_t >> -/sbin/mke2fs system_u:object_r:fsadm_exec_t >> -/sbin/mkfs.ext2 system_u:object_r:fsadm_exec_t >> -/sbin/mkswap system_u:object_r:fsadm_exec_t >> -/sbin/scsi_info system_u:object_r:fsadm_exec_t >> -/sbin/sfdisk system_u:object_r:fsadm_exec_t >> -/sbin/cfdisk system_u:object_r:fsadm_exec_t >> -/sbin/fdisk system_u:object_r:fsadm_exec_t >> -/sbin/tune2fs system_u:object_r:fsadm_exec_t >> -/sbin/dumpe2fs system_u:object_r:fsadm_exec_t >> -/sbin/swapon system_u:object_r:fsadm_exec_t >> -/sbin/pwdb_chkpwd system_u:object_r:chkpwd_exec_t >> >> # >> # /tmp >> # >> -/tmp(|/.*) system_u:object_r:tmp_t >> +/tmp(/.*)? system_u:object_r:tmp_t >> /tmp/orbit.* system_u:object_r:user_tmp_t >> -/tmp/.ICE-unix(|/.*) system_u:object_r:user_tmp_t >> -/tmp/.X11-unix(|/.*) system_u:object_r:user_xserver_tmp_t >> +/tmp/.ICE-unix(/.*)? system_u:object_r:user_tmp_t >> +/tmp/.X11-unix(/.*)? system_u:object_r:user_xserver_tmp_t >> /tmp/.X0-lock system_u:object_r:user_xserver_tmp_t >> -/tmp/.font-unix(|/.*) system_u:object_r:xfs_tmp_t >> +/tmp/.font-unix(/.*)? system_u:object_r:xfs_tmp_t >> >> # >> # /usr >> # >> -/usr(|/.*) system_u:object_r:usr_t >> -/usr/etc(|/.*) system_u:object_r:etc_t >> -/usr/libexec(|/.*) system_u:object_r:lib_t >> -/usr/src(|/.*) system_u:object_r:src_t >> -/usr/tmp(|/.*) system_u:object_r:tmp_t >> -/usr/man(|/.*) system_u:object_r:man_t >> +/usr(/.*)? system_u:object_r:usr_t >> +/usr/src(/.*)? system_u:object_r:src_t >> +/usr/tmp(/.*)? system_u:object_r:tmp_t >> +/usr/share/man(/.*)? system_u:object_r:man_t >> >> # >> # /usr/bin >> # >> -/usr/bin(|/.*) system_u:object_r:bin_t >> +/usr/bin(/.*)? system_u:object_r:bin_t >> +/usr/bin/login system_u:object_r:login_exec_t >> +/usr/bin/csh system_u:object_r:shell_exec_t >> +/usr/bin/tcsh system_u:object_r:shell_exec_t >> +/usr/bin/bash system_u:object_r:shell_exec_t >> +/usr/bin/ksh system_u:object_r:shell_exec_t >> +/usr/bin/zsh system_u:object_r:shell_exec_t >> +/usr/bin/su system_u:object_r:su_exec_t >> +/usr/bin/ls system_u:object_r:ls_exec_t >> /usr/bin/lpr system_u:object_r:lpr_exec_t >> /usr/bin/lpq system_u:object_r:lpr_exec_t >> /usr/bin/lprm system_u:object_r:lpr_exec_t >> -/usr/bin/makemap system_u:object_r:sbin_t >> -/usr/bin/netscape system_u:object_r:netscape_exec_t >> /usr/bin/crontab system_u:object_r:crontab_exec_t >> +/usr/bin/passwd system_u:object_r:passwd_exec_t >> >> >> # >> # /usr/lib >> # >> -/usr/lib(|/.*) system_u:object_r:lib_t >> +/usr/lib(/.*)? system_u:object_r:lib_t >> +/usr/lib/ssh/sshd system_u:object_r:sshd_exec_t >> +/usr/lib/saf/ttymon system_u:object_r:getty_exec_t >> /usr/lib/lib.*\.so.* system_u:object_r:shlib_t >> -/usr/lib/perl5/man(|/.*) system_u:object_r:man_t >> - >> -# >> -# /usr/local >> -# >> -/usr/local/etc(|/.*) system_u:object_r:etc_t >> -/usr/local/etc/ssh_host_key system_u:object_r:sshd_key_t >> -/usr/local/etc/ssh_host_dsa_key system_u:object_r:sshd_key_t >> -/usr/local/src(|/.*) system_u:object_r:src_t >> -/usr/local/sbin(|/.*) system_u:object_r:sbin_t >> -/usr/local/sbin/sshd system_u:object_r:sshd_exec_t >> -/usr/local/man(|/.*) system_u:object_r:man_t >> - >> -# >> -# /usr/local/bin >> -# >> -/usr/local/bin(|/.*) system_u:object_r:bin_t >> -/usr/local/bin/tcsh system_u:object_r:shell_exec_t >> - >> -# >> -# /usr/local/lib >> -# >> -/usr/local/lib(|/.*) system_u:object_r:lib_t >> -/usr/local/lib/lib.*\.so.* system_u:object_r:shlib_t >> +/usr/lib/inet/inetd system_u:object_r:inetd_exec_t >> +/usr/lib/inet/in\..*d system_u:object_r:inetd_child_exec_t >> +/usr/lib/sendmail system_u:object_r:sendmail_exec_t >> >> # >> # /usr/sbin >> # >> -/usr/sbin(|/.*) system_u:object_r:sbin_t >> +/usr/sbin(/.*)? system_u:object_r:sbin_t >> +/usr/sbin/fsck system_u:object_r:fsadm_exec_t >> +/usr/sbin/mkfs system_u:object_r:fsadm_exec_t >> +/usr/sbin/fdisk system_u:object_r:fsadm_exec_t >> /usr/sbin/syslogd system_u:object_r:syslogd_exec_t >> -/usr/sbin/klogd system_u:object_r:klogd_exec_t >> -/usr/sbin/apmd system_u:object_r:apmd_exec_t >> -/usr/sbin/crond system_u:object_r:crond_exec_t >> -/usr/sbin/atd system_u:object_r:atd_exec_t >> -/usr/sbin/lpd system_u:object_r:lpd_exec_t >> -/usr/sbin/inetd system_u:object_r:inetd_exec_t >> -/usr/sbin/tcpd system_u:object_r:tcpd_exec_t >> -/usr/sbin/identd system_u:object_r:inetd_child_exec_t >> +/usr/sbin/cron system_u:object_r:crond_exec_t >> /usr/sbin/in\..*d system_u:object_r:inetd_child_exec_t >> /usr/sbin/in.rlogind system_u:object_r:rlogind_exec_t >> /usr/sbin/in.telnetd system_u:object_r:rlogind_exec_t >> /usr/sbin/in.rshd system_u:object_r:rshd_exec_t >> /usr/sbin/in.ftpd system_u:object_r:ftpd_exec_t >> -/usr/sbin/in.ftpd-stage2 system_u:object_r:ftpd_stage2_exec_t >> -/usr/sbin/sendmail system_u:object_r:sendmail_exec_t >> +/usr/sbin/rpcbind system_u:object_r:portmap_exec_t >> /usr/sbin/rpc\..* system_u:object_r:rpcd_exec_t >> -/usr/sbin/gpm system_u:object_r:gpm_exec_t >> /usr/sbin/makemap system_u:object_r:sbin_t >> -/usr/sbin/utempter system_u:object_r:utempter_exec_t >> -/usr/sbin/gnome-pty-helper system_u:object_r:gph_exec_t >> -/usr/sbin/logrotate system_u:object_r:logrotate_exec_t >> >> # >> -# /usr/X11R6/bin >> +# /usr/sadm >> # >> -/usr/X11R6/bin(|/.*) system_u:object_r:bin_t >> -/usr/X11R6/bin/xfs system_u:object_r:xfs_exec_t >> -/usr/X11R6/bin/Xwrapper system_u:object_r:xserver_exec_t >> +/usr/sadm/bin(/.*)? system_u:object_r:bin_t >> +/usr/sadm/admin/bin(/.*)? system_u:object_r:bin_t >> +/usr/sadm/lib(/.*)? system_u:object_r:lib_t >> >> # >> -# /usr/X11R6/lib >> +# /usr/X11 >> # >> -/usr/X11R6/lib(|/.*) system_u:object_r:lib_t >> -/usr/X11R6/lib/lib.*\.so.* system_u:object_r:shlib_t >> - >> -# >> -# /usr/X11R6/man >> -# >> -/usr/X11R6/man(|/.*) system_u:object_r:man_t >> - >> -# >> -# /usr/flask >> -# >> -/usr/flask/bin(|/.*) system_u:object_r:bin_t >> -/usr/flask/sbin(|/.*) system_u:object_r:bin_t >> -/usr/flask/libexec(|/.*) system_u:object_r:lib_t >> -/usr/flask/bin/spasswd system_u:object_r:passwd_exec_t >> -/usr/flask/bin/schsh system_u:object_r:passwd_exec_t >> -/usr/flask/bin/schfn system_u:object_r:passwd_exec_t >> -/usr/flask/bin/newrole system_u:object_r:newrole_exec_t >> +/usr/X11/bin(/.*)? system_u:object_r:bin_t >> +/usr/X11/bin/Xorg system_u:object_r:xserver_exec_t >> +/usr/X11/lib(/.*)? system_u:object_r:lib_t >> +/usr/X11/lib/lib.*\.so.* system_u:object_r:shlib_t >> +/usr/X11/share/man(/.*)? system_u:object_r:man_t >> >> # >> # /var >> # >> -/var(|/.*) system_u:object_r:var_t >> -/var/catman(|/.*) system_u:object_r:catman_t >> -/var/yp(|/.*) system_u:object_r:var_yp_t >> -/var/lib(|/.*) system_u:object_r:var_lib_t >> -/var/lock(|/.*) system_u:object_r:var_lock_t >> -/var/tmp(|/.*) system_u:object_r:tmp_t >> +/var(/.*)? system_u:object_r:var_t >> +/var/yp(/.*)? system_u:object_r:var_yp_t >> +/var/lib(/.*)? system_u:object_r:var_lib_t >> +/var/tmp(/.*)? system_u:object_r:tmp_t >> >> # >> # /var/run >> # >> -/var/run(|/.*) system_u:object_r:var_run_t >> -/var/run/utmp system_u:object_r:initrc_var_run_t >> -/var/run/runlevel.dir system_u:object_r:initrc_var_run_t >> -/var/run/random-seed system_u:object_r:initrc_var_run_t >> +/var/run(/.*)? system_u:object_r:var_run_t >> /var/run/.*\.*pid <> >> >> # >> # /var/spool >> # >> -/var/spool(|/.*) system_u:object_r:var_spool_t >> -/var/spool/at(|/.*) system_u:object_r:at_spool_t >> -/var/spool/cron(|/.*) system_u:object_r:cron_spool_t >> -/var/spool/lpd(|/.*) system_u:object_r:lpd_spool_t >> -/var/spool/mail(|/.*) system_u:object_r:mail_spool_t >> -/var/spool/mqueue(|/.*) system_u:object_r:mqueue_spool_t >> +/var/spool(/.*)? system_u:object_r:var_spool_t >> +/var/spool/cron(/.*)? system_u:object_r:cron_spool_t >> +/var/spool/lp(/.*)? system_u:object_r:lpd_spool_t >> +/var/mail(/.*)? system_u:object_r:mail_spool_t >> +/var/spool/mqueue(/.*)? system_u:object_r:mqueue_spool_t >> >> # >> # /var/log >> # >> -/var/log(|/.*) system_u:object_r:var_log_t >> -/var/log/wtmp system_u:object_r:wtmp_t >> -/var/log/sendmail.st system_u:object_r:sendmail_var_log_t >> -/var/log/cron system_u:object_r:cron_log_t >> - >> -# >> -# Persistent label mappings. >> -# >> -.*/\.\.\.security(|/.*) system_u:object_r:file_labels_t >> - >> -# >> -# Lost and found directories. >> -# >> -.*/lost\+found(|/.*) system_u:object_r:lost_found_t >> - >> +/var/log(/.*)? system_u:object_r:var_log_t >> diff --git a/usr/src/cmd/fmac/policy/rbac b/usr/src/cmd/fmac/policy/rbac >> --- a/usr/src/cmd/fmac/policy/rbac >> +++ b/usr/src/cmd/fmac/policy/rbac >> @@ -77,7 +77,6 @@ >> xfs_t >> local_login_t >> remote_login_t >> - sshd_login_t >> depmod_t >> modprobe_t >> insmod_t >> @@ -87,6 +86,7 @@ >> logrotate_t >> sysadm_t # single-user mode >> user_mail_t # mail sent by crond >> + user_t >> }; >> >> # >> diff --git a/usr/src/cmd/fmac/policy/types/file.te b/usr/src/cmd/fmac/policy/types/file.te >> --- a/usr/src/cmd/fmac/policy/types/file.te >> +++ b/usr/src/cmd/fmac/policy/types/file.te >> @@ -97,10 +97,9 @@ >> type etc_runtime_t, file_type, sysadmfile; >> >> # >> -# etc_auth_t is the type of /etc/auth, >> -# which contains the shadow password file. >> +# shadow_t is the type of /etc/shadow. >> # >> -type etc_auth_t, file_type, sysadmfile; >> +type shadow_t, file_type, sysadmfile; >> >> # >> # etc_aliases_t is the type of the aliases database. >> >> From sds at tycho.nsa.gov Wed Sep 10 07:24:32 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 10 Sep 2008 10:24:32 -0400 Subject: [fmac-discuss] Hard links in Solaris Message-ID: <1221056672.8658.74.camel@moss-spartans.epoch.ncsc.mil> When labeling filesystems, the setfiles[1] utility detects multiple hard links to the same file that would match different file context specifications and warns about them. In running setfiles on Solaris, I've noticed that it has complained about some links that I wouldn't expect to resolve to the same binary, but independently checking them has confirmed that they are in fact the same inode and that this is not a bug in setfiles. Two examples are given below. Does anyone know off-hand why these are links to the same file - I would have expected them to be completely different programs? ls -i /usr/X11/bin/Xorg /usr/lib/libvirtd ls -i /usr/bin/ppgsz /usr/benchmarks/filebench/bin/go_filebench [1] http://www.opensolaris.org/os/project/fmac/docs/setfiles.1m.txt -- Stephen Smalley National Security Agency From darrenm at opensolaris.org Wed Sep 10 07:34:04 2008 From: darrenm at opensolaris.org (Darren J Moffat) Date: Wed, 10 Sep 2008 15:34:04 +0100 Subject: [fmac-discuss] Hard links in Solaris In-Reply-To: <1221056672.8658.74.camel@moss-spartans.epoch.ncsc.mil> References: <1221056672.8658.74.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48C7DADC.5060400@opensolaris.org> Stephen Smalley wrote: > When labeling filesystems, the setfiles[1] utility detects multiple hard > links to the same file that would match different file context > specifications and warns about them. In running setfiles on Solaris, > I've noticed that it has complained about some links that I wouldn't > expect to resolve to the same binary, but independently checking them > has confirmed that they are in fact the same inode and that this is not > a bug in setfiles. Two examples are given below. Does anyone know > off-hand why these are links to the same file - I would have expected > them to be completely different programs? > > ls -i /usr/X11/bin/Xorg /usr/lib/libvirtd > ls -i /usr/bin/ppgsz /usr/benchmarks/filebench/bin/go_filebench What you have discovered is how Solaris ensures that the correct ELF binary is run when there is a choice of multiple implementations. In almost all cases this is a 32 bit vs 64 bit choice and on a 64 bit kernel we need to run the 64 bit one and on a 32 bit kernel the 32 bit one. On Solaris even with a 64 bit kernel the majority of userland is 32 bit and only those programs that need to be 64 because of there interfaces to the kernel or there is a strong performance reason for them being 64 bit are made available as 64 bit ELF binaries, everything else is 32 bit. For libraries however the situation is different and the policy is that we should in almost all cases ship both the 32 bit and 64 bit version of a library. What you will probably see is that all those programs are hardlinks to /usr/lib/isaexec, I count 77 such programs on a snv_95 SPARC system. The /usr/lib/isaexec program isn't documented but the corresponding library function is in isaexec(3C). The /usr/lib/isaexec binary is roughly equivalent to the following shell script: #!/bin/sh fname=`basename $0` pathname=`dirname $0` if [ ! -x /usr/bin/isalist ]; then arch=`arch` if [ ! -x $pathname/$arch/$fname ]; then echo "$0: cannot find the ISA list"; else exec $pathname/$arch/$fname echo "$0: cannon find/execute $fname in ISA subdirectories" fi fi for isa in `/usr/bin/isalist` ; do execpath="${pathname}/${isa}/${fname}" if [ -x $execpath ]; then exec $execpath "$@" echo "$0 exec $execpath failed" fi done echo "$0: cannon find/execute $fname in ISA subdirectories" exit 1; -- Darren J Moffat From john.weeks at sun.com Thu Sep 11 10:34:50 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 11 Sep 2008 10:34:50 -0700 Subject: [fmac-discuss] cp -/ error on files with a SECCTX attribute set Message-ID: <48C956BA.2080207@sun.com> I ran into an interesting problem when copying files on an FMAC system that contain extended system attributes. It's a tricky to explain, but here goes... zfs_vnops.c:zfs_setattr ... if (mask & AT_XVATTR) { if ((need_policy == FALSE) && (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) && xoap->xoa_appendonly != ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) || (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) && xoap->xoa_nounlink != ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) || (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) && xoap->xoa_immutable != ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) || (XVA_ISSET_REQ(xvap, XAT_NODUMP) && xoap->xoa_nodump != ((pzp->zp_flags & ZFS_NODUMP) != 0)) || (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) && xoap->xoa_av_modified != ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) || ((XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) && ((vp->v_type != VREG && xoap->xoa_av_quarantined) || xoap->xoa_av_quarantined != ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)))) || (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) || (XVA_ISSET_REQ(xvap, XAT_SECCTX)) || (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) { need_policy = TRUE; } } The attribute checks above are trying to determine if the requested attribute/values are different from what's currently set on the file. This is fine in general, but if the attribute value is not changing, it's still left in the mask. If XAT_SECCTX is in the requested set, need_policy is set to TRUE which causes secpolicy_xattr() to be called. secpolicy_xattr() then checks for special attributes and returns an error since some of them are set to their default values policy.c:secpolicy_xvattr(): ... /* * Now handle special attributes */ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) error = ATTR_FLAG_PRIV(XAT_IMMUTABLE, xoap->xoa_immutable, cr); if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) error = ATTR_FLAG_PRIV(XAT_NOUNLINK, xoap->xoa_nounlink, cr); If you only set SECCTX, the other attribute bits are not set and everything works fine. I'm thinking that the attribute bits should be removed if the requested attribute is the same as what is currently on the file (object). This seems to be an existing problem, but the introduction of SECCTX surfaced it ;-) -John From sds at tycho.nsa.gov Fri Sep 12 08:09:39 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 12 Sep 2008 11:09:39 -0400 Subject: [fmac-discuss] [PATCH 1/5] Fix fmac_vnode_set_secctx Message-ID: <1221232179.4712.31.camel@moss-spartans.epoch.ncsc.mil> Fix a bug in fmac_vnode_set_secctx: do not update the vnode secid if the permission checks failed. diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -230,7 +230,8 @@ if (!error) error = avc_has_perm(cr_secid, new_secid, sclass, FILE__RELABELTO); - vp->v_secid = new_secid; + if (!error) + vp->v_secid = new_secid; mutex_exit(&(vp->v_lock)); } else { /* Creating a new file. */ -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 12 08:10:59 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 12 Sep 2008 11:10:59 -0400 Subject: [fmac-discuss] [PATCH 2/5] Add fmac_vfs_root Message-ID: <1221232259.4712.33.camel@moss-spartans.epoch.ncsc.mil> Add a fmac_vfs_root() function to set up root vnodes. Internally this applies fmac_vnode_lookup() to the root vnode to fetch its attribute and map it to an incore secid. diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -200,6 +200,13 @@ } int +fmac_vfs_root(vfs_t *vfsp, vnode_t *vp) +{ + _NOTE(ARGUNUSED(vfsp)); /* future use for context mounts? */ + return (fmac_vnode_lookup(vp, CRED(), NULL)); +} + +int fmac_vnode_set_secctx(char *secctx, cred_t *cr, vtype_t vtype, vnode_t *vp) { security_id_t cr_secid, old_secid, new_secid; diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c --- a/usr/src/uts/common/fs/vfs.c +++ b/usr/src/uts/common/fs/vfs.c @@ -86,6 +86,7 @@ #include #include #include +#include #include @@ -243,6 +244,8 @@ strlen(refstr_value(mntpt))); refstr_rele(mntpt); } + if (ret == 0) + (void) fmac_vfs_root(vfsp, *vpp); return (ret); } diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -33,6 +33,7 @@ #if defined(_KERNEL) #include +#include #include #else #include @@ -85,6 +86,7 @@ void fmac_init(void); int fmac_load_policy(char *file); int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); +int fmac_vfs_root(vfs_t *, vnode_t *); int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *); int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, security_id_t *); -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 12 08:11:56 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 12 Sep 2008 11:11:56 -0400 Subject: [fmac-discuss] [PATCH 3/5] Extend avc_audit() Message-ID: <1221232316.4712.35.camel@moss-spartans.epoch.ncsc.mil> Extend avc_audit() to report pid, comm, and optionally path information in avc messages. This is helpful in debugging policy denials. This may be obsoleted later by integration of FMAC with audit. diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c --- a/usr/src/uts/common/fmac/avc.c +++ b/usr/src/uts/common/fmac/avc.c @@ -150,7 +150,7 @@ int i2; int perm; - if (av == 0) { + if (av == 0) { avc_audit_append(" null"); return; } @@ -547,6 +547,8 @@ uint32_t denied, /* IN */ avc_audit_data_t *a) /* IN */ { + struct proc *p = curproc; + struct vnode *vp; _NOTE(ARGUNUSED(ae)); @@ -558,6 +560,16 @@ avc_dump_av(tclass, audited); avc_audit_append(" for "); avc_dump_query(ssid, tsid, tclass); + avc_audit_append(" pid=%d comm=%s", p->p_pid, p->p_user.u_comm); + if (a) { + switch (a->type) { + case AVC_AUDIT_DATA_FS: + vp = a->u.fs.vp; + if (vp && vp->v_path) + avc_audit_append(" path=%s", vp->v_path); + break; + } + } avc_audit_end(); } diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h --- a/usr/src/uts/common/sys/fmac/avc.h +++ b/usr/src/uts/common/sys/fmac/avc.h @@ -71,6 +71,7 @@ #define AVC_ENTRY_REF_CPY(dst, src) (dst)->ae = (src)->ae +struct vnode; typedef struct avc_audit_data { char type; @@ -80,15 +81,16 @@ #define AVC_AUDIT_DATA_IPC 4 #define AVC_AUDIT_DATA_DONTAUDIT 5 /* never audit this permission check */ union { - /* add ancillary audit data here for your OS */ - int fill; + struct { + struct vnode *vp; + } fs; } u; } avc_audit_data_t; /* Initialize an AVC audit data structure. */ #define AVC_AUDIT_DATA_INIT(_d, _t) { \ - memset((_d), 0, sizeof (struct avc_audit_data)); \ + (void) memset((_d), 0, sizeof (struct avc_audit_data)); \ (_d)->type = AVC_AUDIT_DATA_##_t; \ } -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 12 08:13:07 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 12 Sep 2008 11:13:07 -0400 Subject: [fmac-discuss] [PATCH 4/5] Add fmac_vnode_access Message-ID: <1221232387.4712.38.camel@moss-spartans.epoch.ncsc.mil> Add a FMAC hook in fop_access to mediate the file read / write / exec checks. This only introduces the regular mandatory access check; handling privileges is left for a later patch. For now, ignore file types other than regular files and directories since we only support labeling those two file types presently. diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -137,6 +137,8 @@ return (SECCLASS_FILE); case VDIR: return (SECCLASS_DIR); +#if notyet + /* Wait until we have labeling support for all file types. */ case VBLK: return (SECCLASS_BLK_FILE); case VCHR: @@ -147,6 +149,7 @@ return (SECCLASS_FIFO_FILE); case VSOCK: return (SECCLASS_SOCK_FILE); +#endif case VDOOR: /* TBD */ case VPROC: @@ -370,3 +373,46 @@ *secidp = secid; return (0); } + +int +fmac_vnode_access(vnode_t *vp, int mode, int flags, cred_t *cr, + boolean_t audit) +{ + security_id_t cr_secid; + security_class_t sclass; + access_vector_t av; + avc_audit_data_t ad; + + if (!fmac_enabled) + return (0); + + cr_secid = crgetsecid(cr); + + sclass = fmac_vtype_to_sclass(vp->v_type); + if (!sclass) + return (0); + + av = 0; + if (mode & VREAD) + av |= FILE__READ; + if (flags & V_APPEND) + av |= FILE__APPEND; + else if (mode & VWRITE) + av |= FILE__WRITE; + if (mode & VEXEC) { + if (sclass == SECCLASS_DIR) + av |= DIR__SEARCH; + else + av |= FILE__EXECUTE; + } + + if (!av) + return (0); + + if (audit) { + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = vp; + } else + AVC_AUDIT_DATA_INIT(&ad, DONTAUDIT); + return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); +} diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -3298,7 +3298,9 @@ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); VOPSTATS_UPDATE(vp, access); - return (err); + if (err) + return (err); + return (fmac_vnode_access(vp, mode, flags, cr, B_TRUE)); } int diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -93,6 +93,7 @@ void fmac_vnode_post_create(vnode_t *, security_id_t); int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, security_id_t *prev_secidp, security_id_t *secidp); +int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); #endif /* _KERNEL */ #ifdef __cplusplus -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 12 08:14:23 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 12 Sep 2008 11:14:23 -0400 Subject: [fmac-discuss] [PATCH 5/5] Mediate PROT_EXEC file mappings Message-ID: <1221232463.4712.40.camel@moss-spartans.epoch.ncsc.mil> Call fmac_vnode_access from mmap to mediate PROT_EXEC mappings of files. There are two cases: 1) Caller requested PROT_EXEC. In this case, we check execute access to the vnode, audit any denial and immediately return an error to the caller if access is not allowed. 2) Caller did not request PROT_EXEC. In this case, we check execute access to the vnode solely in order to set maxprot appropriately for later checking by mprotect. As the caller did not request it, we do not need to audit a lack of execute access or return an error to the caller on the mmap call. Handling of failure on the mprotect path will be handled via a separate patch. Controlling PROT_EXEC file mappings is part of the overall code execution controls provided by Flask/TE in order to bind specific domains to specific code vetted for that purpose. diff --git a/usr/src/uts/common/os/grow.c b/usr/src/uts/common/os/grow.c --- a/usr/src/uts/common/os/grow.c +++ b/usr/src/uts/common/os/grow.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -665,6 +666,24 @@ if ((vp->v_vfsp->vfs_flag & VFS_NOEXEC) != 0) maxprot &= ~PROT_EXEC; + if (prot & PROT_EXEC) { + /* + * Caller requested PROT_EXEC; fail immediately if + * it isn't allowed. + */ + error = fmac_vnode_access(vp, VEXEC, 0, CRED(), B_TRUE); + if (error) + return (error); + } else { + /* + * Caller did not request PROT_EXEC; limit maxprot based + * on whether it is allowed so that mprotect cannot exceed + * the allowed permissions. + */ + if (fmac_vnode_access(vp, VEXEC, 0, CRED(), B_FALSE)) + maxprot &= ~PROT_EXEC; + } + /* * These checks were added as part of large files. * -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 12 08:36:03 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 12 Sep 2008 11:36:03 -0400 Subject: [fmac-discuss] Summary for last 5 patches and next steps In-Reply-To: <1221232179.4712.31.camel@moss-spartans.epoch.ncsc.mil> References: <1221232179.4712.31.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <1221233763.4712.60.camel@moss-spartans.epoch.ncsc.mil> A single webrev for all 5 patches is at: http://cr.opensolaris.org/~sds/vnode/ These changes enable basic file read/write/execute permission checking by FMAC. With these changes applied, one can see FMAC avc denials such as: avc: denied { append } for scontext=system_u:system_r:user_t:unclassified tcontext=system_u:object_r:var_t:unclassified tclass=file pid=100927 comm=reboot path=/var/adm/wtmpx These are only the basic file permission checks; the various other specific checks on particular file operations (link, unlink, rename, ...) are yet to be implemented, but these can be introduced incrementally. See: http://www.nsa.gov/selinux/papers/slinux/node44.html for discussion of the file permissions and how they were applied to various system calls in Linux as an example. The next step is basic domain isolation/protection, e.g. ptrace checking both on ptrace calls and across domain-changing exec calls, protection of proc vnodes, signal controls, setting of the linker security flag on domain transitions, etc. Then with some policy configuration work, we should be able to demonstrate a basic working example of Flask/TE in action. Input and help on any of the above are of course welcome. -- Stephen Smalley National Security Agency From john.weeks at sun.com Fri Sep 12 10:42:31 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 12 Sep 2008 10:42:31 -0700 Subject: [fmac-discuss] [PATCH 1/5] Fix fmac_vnode_set_secctx In-Reply-To: <1221232179.4712.31.camel@moss-spartans.epoch.ncsc.mil> References: <1221232179.4712.31.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CAAA07.8080807@sun.com> Acked-by: John Weeks On 09/12/08 08:09, Stephen Smalley wrote: > Fix a bug in fmac_vnode_set_secctx: do not update the vnode secid > if the permission checks failed. > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -230,7 +230,8 @@ > if (!error) > error = avc_has_perm(cr_secid, new_secid, sclass, > FILE__RELABELTO); > - vp->v_secid = new_secid; > + if (!error) > + vp->v_secid = new_secid; > mutex_exit(&(vp->v_lock)); > } else { > /* Creating a new file. */ > From john.weeks at sun.com Fri Sep 12 10:44:13 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 12 Sep 2008 10:44:13 -0700 Subject: [fmac-discuss] [PATCH 2/5] Add fmac_vfs_root In-Reply-To: <1221232259.4712.33.camel@moss-spartans.epoch.ncsc.mil> References: <1221232259.4712.33.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CAAA6D.7070704@sun.com> Acked-by: John Weeks On 09/12/08 08:10, Stephen Smalley wrote: > Add a fmac_vfs_root() function to set up root vnodes. > Internally this applies fmac_vnode_lookup() to the root vnode > to fetch its attribute and map it to an incore secid. > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -200,6 +200,13 @@ > } > > int > +fmac_vfs_root(vfs_t *vfsp, vnode_t *vp) > +{ > + _NOTE(ARGUNUSED(vfsp)); /* future use for context mounts? */ > + return (fmac_vnode_lookup(vp, CRED(), NULL)); > +} > + > +int > fmac_vnode_set_secctx(char *secctx, cred_t *cr, vtype_t vtype, vnode_t *vp) > { > security_id_t cr_secid, old_secid, new_secid; > diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c > --- a/usr/src/uts/common/fs/vfs.c > +++ b/usr/src/uts/common/fs/vfs.c > @@ -86,6 +86,7 @@ > #include > #include > #include > +#include > > #include > > @@ -243,6 +244,8 @@ > strlen(refstr_value(mntpt))); > refstr_rele(mntpt); > } > + if (ret == 0) > + (void) fmac_vfs_root(vfsp, *vpp); > > return (ret); > } > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -33,6 +33,7 @@ > > #if defined(_KERNEL) > #include > +#include > #include > #else > #include > @@ -85,6 +86,7 @@ > void fmac_init(void); > int fmac_load_policy(char *file); > int fmac_vnode_lookup(vnode_t *, cred_t *, caller_context_t *); > +int fmac_vfs_root(vfs_t *, vnode_t *); > int fmac_vnode_set_secctx(char *, cred_t *, vtype_t, vnode_t *); > int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > security_id_t *); > From john.weeks at sun.com Fri Sep 12 10:44:37 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 12 Sep 2008 10:44:37 -0700 Subject: [fmac-discuss] [PATCH 3/5] Extend avc_audit() In-Reply-To: <1221232316.4712.35.camel@moss-spartans.epoch.ncsc.mil> References: <1221232316.4712.35.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CAAA85.5000109@sun.com> Acked-by: John Weeks On 09/12/08 08:11, Stephen Smalley wrote: > Extend avc_audit() to report pid, comm, and optionally path information > in avc messages. This is helpful in debugging policy denials. > This may be obsoleted later by integration of FMAC with audit. > > diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c > --- a/usr/src/uts/common/fmac/avc.c > +++ b/usr/src/uts/common/fmac/avc.c > @@ -150,7 +150,7 @@ > int i2; > int perm; > > - if (av == 0) { > + if (av == 0) { > avc_audit_append(" null"); > return; > } > @@ -547,6 +547,8 @@ > uint32_t denied, /* IN */ > avc_audit_data_t *a) /* IN */ > { > + struct proc *p = curproc; > + struct vnode *vp; > > _NOTE(ARGUNUSED(ae)); > > @@ -558,6 +560,16 @@ > avc_dump_av(tclass, audited); > avc_audit_append(" for "); > avc_dump_query(ssid, tsid, tclass); > + avc_audit_append(" pid=%d comm=%s", p->p_pid, p->p_user.u_comm); > + if (a) { > + switch (a->type) { > + case AVC_AUDIT_DATA_FS: > + vp = a->u.fs.vp; > + if (vp && vp->v_path) > + avc_audit_append(" path=%s", vp->v_path); > + break; > + } > + } > avc_audit_end(); > } > > diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h > --- a/usr/src/uts/common/sys/fmac/avc.h > +++ b/usr/src/uts/common/sys/fmac/avc.h > @@ -71,6 +71,7 @@ > > #define AVC_ENTRY_REF_CPY(dst, src) (dst)->ae = (src)->ae > > +struct vnode; > > typedef struct avc_audit_data { > char type; > @@ -80,15 +81,16 @@ > #define AVC_AUDIT_DATA_IPC 4 > #define AVC_AUDIT_DATA_DONTAUDIT 5 /* never audit this permission check */ > union { > - /* add ancillary audit data here for your OS */ > - int fill; > + struct { > + struct vnode *vp; > + } fs; > } u; > > } avc_audit_data_t; > > /* Initialize an AVC audit data structure. */ > #define AVC_AUDIT_DATA_INIT(_d, _t) { \ > - memset((_d), 0, sizeof (struct avc_audit_data)); \ > + (void) memset((_d), 0, sizeof (struct avc_audit_data)); \ > (_d)->type = AVC_AUDIT_DATA_##_t; \ > } > > From john.weeks at sun.com Fri Sep 12 10:45:05 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 12 Sep 2008 10:45:05 -0700 Subject: [fmac-discuss] [PATCH 4/5] Add fmac_vnode_access In-Reply-To: <1221232387.4712.38.camel@moss-spartans.epoch.ncsc.mil> References: <1221232387.4712.38.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CAAAA1.7090609@sun.com> Acked-by: John Weeks On 09/12/08 08:13, Stephen Smalley wrote: > Add a FMAC hook in fop_access to mediate the file read / write / exec checks. > This only introduces the regular mandatory access check; handling privileges > is left for a later patch. For now, ignore file types other than regular > files and directories since we only support labeling those two file types > presently. > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -137,6 +137,8 @@ > return (SECCLASS_FILE); > case VDIR: > return (SECCLASS_DIR); > +#if notyet > + /* Wait until we have labeling support for all file types. */ > case VBLK: > return (SECCLASS_BLK_FILE); > case VCHR: > @@ -147,6 +149,7 @@ > return (SECCLASS_FIFO_FILE); > case VSOCK: > return (SECCLASS_SOCK_FILE); > +#endif > case VDOOR: > /* TBD */ > case VPROC: > @@ -370,3 +373,46 @@ > *secidp = secid; > return (0); > } > + > +int > +fmac_vnode_access(vnode_t *vp, int mode, int flags, cred_t *cr, > + boolean_t audit) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + access_vector_t av; > + avc_audit_data_t ad; > + > + if (!fmac_enabled) > + return (0); > + > + cr_secid = crgetsecid(cr); > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (0); > + > + av = 0; > + if (mode & VREAD) > + av |= FILE__READ; > + if (flags & V_APPEND) > + av |= FILE__APPEND; > + else if (mode & VWRITE) > + av |= FILE__WRITE; > + if (mode & VEXEC) { > + if (sclass == SECCLASS_DIR) > + av |= DIR__SEARCH; > + else > + av |= FILE__EXECUTE; > + } > + > + if (!av) > + return (0); > + > + if (audit) { > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = vp; > + } else > + AVC_AUDIT_DATA_INIT(&ad, DONTAUDIT); > + return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); > +} > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -3298,7 +3298,9 @@ > > err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct); > VOPSTATS_UPDATE(vp, access); > - return (err); > + if (err) > + return (err); > + return (fmac_vnode_access(vp, mode, flags, cr, B_TRUE)); > } > > int > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -93,6 +93,7 @@ > void fmac_vnode_post_create(vnode_t *, security_id_t); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > security_id_t *prev_secidp, security_id_t *secidp); > +int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > #endif /* _KERNEL */ > > #ifdef __cplusplus > From john.weeks at sun.com Fri Sep 12 10:45:30 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 12 Sep 2008 10:45:30 -0700 Subject: [fmac-discuss] [PATCH 5/5] Mediate PROT_EXEC file mappings In-Reply-To: <1221232463.4712.40.camel@moss-spartans.epoch.ncsc.mil> References: <1221232463.4712.40.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CAAABA.3090205@sun.com> Acked-by: John Weeks On 09/12/08 08:14, Stephen Smalley wrote: > Call fmac_vnode_access from mmap to mediate PROT_EXEC mappings of files. > There are two cases: > 1) Caller requested PROT_EXEC. In this case, we check execute access to > the vnode, audit any denial and immediately return an error to the caller > if access is not allowed. > 2) Caller did not request PROT_EXEC. In this case, we check execute access > to the vnode solely in order to set maxprot appropriately for later checking > by mprotect. As the caller did not request it, we do not need to audit a > lack of execute access or return an error to the caller on the mmap call. > Handling of failure on the mprotect path will be handled via a separate patch. > > Controlling PROT_EXEC file mappings is part of the overall code execution > controls provided by Flask/TE in order to bind specific domains to specific > code vetted for that purpose. > > diff --git a/usr/src/uts/common/os/grow.c b/usr/src/uts/common/os/grow.c > --- a/usr/src/uts/common/os/grow.c > +++ b/usr/src/uts/common/os/grow.c > @@ -47,6 +47,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -665,6 +666,24 @@ > if ((vp->v_vfsp->vfs_flag & VFS_NOEXEC) != 0) > maxprot &= ~PROT_EXEC; > > + if (prot & PROT_EXEC) { > + /* > + * Caller requested PROT_EXEC; fail immediately if > + * it isn't allowed. > + */ > + error = fmac_vnode_access(vp, VEXEC, 0, CRED(), B_TRUE); > + if (error) > + return (error); > + } else { > + /* > + * Caller did not request PROT_EXEC; limit maxprot based > + * on whether it is allowed so that mprotect cannot exceed > + * the allowed permissions. > + */ > + if (fmac_vnode_access(vp, VEXEC, 0, CRED(), B_FALSE)) > + maxprot &= ~PROT_EXEC; > + } > + > /* > * These checks were added as part of large files. > * > From sds at tycho.nsa.gov Fri Sep 12 13:12:08 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 12 Sep 2008 16:12:08 -0400 Subject: [fmac-discuss] [PATCH] Mediate access to proc vnodes Message-ID: <1221250328.4712.137.camel@moss-spartans.epoch.ncsc.mil> Mediate access to the proc vnodes of another process. We will need further hooks elsewhere for complete coverage, e.g. praccess() allows certain proc files to be read by anyone. Result of running "truss passwd" as a root process running in the unprivileged user_t domain: avc: denied { ptrace } for scontext=system_u:system_r:user_t:unclassified tcontext=system_u:system_r:passwd_t:unclassified tclass=process pid=100779 comm=truss diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -416,3 +416,12 @@ AVC_AUDIT_DATA_INIT(&ad, DONTAUDIT); return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); } + +int +fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode) +{ + if (!fmac_enabled) + return (0); + return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), + SECCLASS_PROCESS, PROCESS__PTRACE)); +} diff --git a/usr/src/uts/common/os/priv.c b/usr/src/uts/common/os/priv.c --- a/usr/src/uts/common/os/priv.c +++ b/usr/src/uts/common/os/priv.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -605,9 +606,12 @@ if (!priv_issubset(&CR_IPRIV(tcr), eset) || !priv_issubset(&CR_OPPRIV(tcr), eset) || !priv_issubset(&CR_LPRIV(tcr), &CR_LPRIV(scr)) || - !idsmatch && secpolicy_proc_owner(scr, tcr, mode) != 0) + !idsmatch && secpolicy_proc_owner(scr, tcr, mode) != 0) { res = EACCES; + goto out; + } + res = fmac_priv_proc_cred_perm(scr, tcr, mode); out: if (res == 0 && pcr != NULL) *pcr = tcr; diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -94,6 +94,7 @@ int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, security_id_t *prev_secidp, security_id_t *secidp); int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); +int fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode); #endif /* _KERNEL */ #ifdef __cplusplus -- Stephen Smalley National Security Agency From Cathleen.Reiher at Sun.COM Fri Sep 12 16:37:43 2008 From: Cathleen.Reiher at Sun.COM (Cathleen Reiher) Date: Fri, 12 Sep 2008 16:37:43 -0700 Subject: [fmac-discuss] REVIEW: fmac(5) update Message-ID: Hi all, I've updated the fmac(5) man page to describe the updated AVC message format. The sample denial message, as well as descriptions of the comm, path, and pid properties have been added. These changes are in response to Stephen Smalley's basic file permission checking patches (set of 5) from 9/12. The updated page is available on the FMAC project page: http://opensolaris.org/os/project/fmac/docs/ Thanks in advance for your feedback! Cathleen. From john.weeks at sun.com Fri Sep 12 16:55:32 2008 From: john.weeks at sun.com (John Weeks) Date: Fri, 12 Sep 2008 16:55:32 -0700 Subject: [fmac-discuss] REVIEW: fmac(5) update In-Reply-To: References: Message-ID: <48CB0174.4060700@sun.com> Thanks Cathleen :-) On 09/12/08 16:37, Cathleen Reiher wrote: > Hi all, > > I've updated the fmac(5) man page to > describe the updated AVC message > format. The sample denial message, > as well as descriptions of the comm, > path, and pid properties have been > added. > > These changes are in response to > Stephen Smalley's basic file permission > checking patches (set of 5) from 9/12. > > The updated page is available on the > FMAC project page: > > http://opensolaris.org/os/project/fmac/docs/ > > Thanks in advance for your feedback! > > Cathleen. > _______________________________________________ > fmac-discuss mailing list > fmac-discuss at opensolaris.org > http://mail.opensolaris.org/mailman/listinfo/fmac-discuss From john.weeks at sun.com Sun Sep 14 20:30:34 2008 From: john.weeks at sun.com (John Weeks) Date: Sun, 14 Sep 2008 20:30:34 -0700 Subject: [fmac-discuss] [PATCH] Mediate access to proc vnodes In-Reply-To: <1221250328.4712.137.camel@moss-spartans.epoch.ncsc.mil> References: <1221250328.4712.137.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CDD6DA.7060305@sun.com> Acked-by: John Weeks On 09/12/08 13:12, Stephen Smalley wrote: > Mediate access to the proc vnodes of another process. > We will need further hooks elsewhere for complete coverage, e.g. > praccess() allows certain proc files to be read by anyone. > > Result of running "truss passwd" as a root process running in the > unprivileged user_t domain: > > avc: denied { ptrace } for > scontext=system_u:system_r:user_t:unclassified > tcontext=system_u:system_r:passwd_t:unclassified tclass=process > pid=100779 comm=truss > > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -416,3 +416,12 @@ > AVC_AUDIT_DATA_INIT(&ad, DONTAUDIT); > return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); > } > + > +int > +fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode) > +{ > + if (!fmac_enabled) > + return (0); > + return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), > + SECCLASS_PROCESS, PROCESS__PTRACE)); > +} > diff --git a/usr/src/uts/common/os/priv.c b/usr/src/uts/common/os/priv.c > --- a/usr/src/uts/common/os/priv.c > +++ b/usr/src/uts/common/os/priv.c > @@ -56,6 +56,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -605,9 +606,12 @@ > if (!priv_issubset(&CR_IPRIV(tcr), eset) || > !priv_issubset(&CR_OPPRIV(tcr), eset) || > !priv_issubset(&CR_LPRIV(tcr), &CR_LPRIV(scr)) || > - !idsmatch && secpolicy_proc_owner(scr, tcr, mode) != 0) > + !idsmatch && secpolicy_proc_owner(scr, tcr, mode) != 0) { > res = EACCES; > + goto out; > + } > > + res = fmac_priv_proc_cred_perm(scr, tcr, mode); > out: > if (res == 0 && pcr != NULL) > *pcr = tcr; > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -94,6 +94,7 @@ > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > security_id_t *prev_secidp, security_id_t *secidp); > int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > +int fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode); > #endif /* _KERNEL */ > > #ifdef __cplusplus > From sds at tycho.nsa.gov Mon Sep 15 08:07:01 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 15 Sep 2008 11:07:01 -0400 Subject: [fmac-discuss] prochasprocperm Message-ID: <1221491221.29542.11.camel@moss-spartans.epoch.ncsc.mil> The procphasprocperm() interface in os/cred.c is used for checking access for a variety of inter-process operations, including but not limited to signal sending. It unfortunately does not specify any information about the particular operation. We have several options for handling this in FMAC: 1) Define a single permission in the process class for this interface and always check that permission in this function between the two process security contexts/ids. 2) Extend the interface to pass information about the particular operation and optionally supplemental data, and use this information to determine which FMAC permission to check, defining different permissions for different operations. 3) Define and implement discrete FMAC permission checks in the callers rather than in prochasprocperm(). Suggestions? -- Stephen Smalley National Security Agency From Darren.Moffat at Sun.COM Mon Sep 15 08:25:57 2008 From: Darren.Moffat at Sun.COM (Darren J Moffat) Date: Mon, 15 Sep 2008 16:25:57 +0100 Subject: [fmac-discuss] prochasprocperm In-Reply-To: <1221491221.29542.11.camel@moss-spartans.epoch.ncsc.mil> References: <1221491221.29542.11.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CE7E85.7080908@Sun.COM> Stephen Smalley wrote: > The procphasprocperm() interface in os/cred.c is used for checking > access for a variety of inter-process operations, including but not > limited to signal sending. It unfortunately does not specify any > information about the particular operation. You gave three options but are there positives and negatives with each of the solutions ? > 2) Extend the interface to pass information about the particular > operation and optionally supplemental data, and use this information to > determine which FMAC permission to check, defining different permissions > for different operations. This seems like the best long term solution for FMAC and everything else, given no other information on how to choose between the three. -- Darren J Moffat From john.weeks at sun.com Mon Sep 15 08:51:08 2008 From: john.weeks at sun.com (John Weeks) Date: Mon, 15 Sep 2008 08:51:08 -0700 Subject: [fmac-discuss] prochasprocperm In-Reply-To: <48CE7E85.7080908@Sun.COM> References: <1221491221.29542.11.camel@moss-spartans.epoch.ncsc.mil> <48CE7E85.7080908@Sun.COM> Message-ID: <48CE846C.9010404@sun.com> On 09/15/08 08:25, Darren J Moffat wrote: > Stephen Smalley wrote: >> The procphasprocperm() interface in os/cred.c is used for checking >> access for a variety of inter-process operations, including but not >> limited to signal sending. It unfortunately does not specify any >> information about the particular operation. > > You gave three options but are there positives and negatives with each > of the solutions ? > >> 2) Extend the interface to pass information about the particular >> operation and optionally supplemental data, and use this information to >> determine which FMAC permission to check, defining different permissions >> for different operations. > > This seems like the best long term solution for FMAC and everything > else, given no other information on how to choose between the three. > > +1 for option #2 From John.Zolnowsky at Sun.Com Mon Sep 15 09:13:34 2008 From: John.Zolnowsky at Sun.Com (John Zolnowsky x69422/408-404-5064) Date: Mon, 15 Sep 2008 09:13:34 -0700 (PDT) Subject: [fmac-discuss] prochasprocperm Message-ID: <200809151613.m8FGDYa11978@domus.sfbay.sun.com> > Date: Mon, 15 Sep 2008 11:07:01 -0400 > From: Stephen Smalley > > The prochasprocperm() interface in os/cred.c is used for checking > access for a variety of inter-process operations, including but not > limited to signal sending. It unfortunately does not specify any > information about the particular operation. Does this issue extend to the somewhat deprecated hasprocperm()? I noticed contract_process_cankill() calls both hasprocperm() and prochasprocperm(). > We have several options for handling this in FMAC: > 1) Define a single permission in the process class for this interface > and always check that permission in this function between the two > process security contexts/ids. > > 2) Extend the interface to pass information about the particular > operation and optionally supplemental data, and use this information to > determine which FMAC permission to check, defining different permissions > for different operations. I'd suggest a variant on this. Define new interfaces relating to the particular context, something like prochasprocpermsignal(...) prochasprocpermsched(...) prochasprocpermcred(...) This would allow better type checking (at the language level) on the supplemental data. Of course, this becomes messy if the same issue applies to haspprocperm(). -JZ > 3) Define and implement discrete FMAC permission checks in the callers > rather than in prochasprocperm(). > > Suggestions? > > -- > Stephen Smalley > National Security Agency > > _______________________________________________ > fmac-discuss mailing list > fmac-discuss at opensolaris.org > http://mail.opensolaris.org/mailman/listinfo/fmac-discuss > From sds at tycho.nsa.gov Mon Sep 15 10:01:15 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 15 Sep 2008 13:01:15 -0400 Subject: [fmac-discuss] prochasprocperm In-Reply-To: <48CE7E85.7080908@Sun.COM> References: <1221491221.29542.11.camel@moss-spartans.epoch.ncsc.mil> <48CE7E85.7080908@Sun.COM> Message-ID: <1221498075.29542.57.camel@moss-spartans.epoch.ncsc.mil> On Mon, 2008-09-15 at 16:25 +0100, Darren J Moffat wrote: > Stephen Smalley wrote: > > The procphasprocperm() interface in os/cred.c is used for checking > > access for a variety of inter-process operations, including but not > > limited to signal sending. It unfortunately does not specify any > > information about the particular operation. > > You gave three options but are there positives and negatives with each > of the solutions ? To clarify, I expect we would actually insert the FMAC check into the hasprocperm() function that is also called by prochasprocperm() if we went with approach #1 or #2, as that is where the existing zone and uid checks are performed. #1 (check in hasprocperm(), no interface change): Positives: - Ensures that FMAC mediation occurs whenever *hasprocperm() is called. - Provides a very simple, abstract security policy for all operations using *hasprocperm(). - No interface change to *hasprocperm(). Negatives: - Cannot distinguish among the individual operations, thereby limiting flexibility and granularity of access control. #2 (check in *hasprocperm() with extended interface): Positives: - Ensures that FMAC mediation occurs whenever *hasprocperm() is called. - Can distinguish among individual operations. Negatives: - More complex security policy than #1. - Requires passing down all relevant state to *hasprocperm(). - Requires an interface change to *hasprocperm(). #3 (check in individual operations, no change to *hasprocperm()): Positives: - Can distinguish among individual operations. - No need to pass down state to *hasprocperm(). - No interface change to *hasprocperm(). Negatives: - More complex security policy than #1, same as #2. - Requires instrumenting all operations that call hasprocperm() with new FMAC hooks. - Maintenance concern: Ensuring that all future operations that are mediated by hasprocperm() are also mediated by FMAC hooks. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Mon Sep 15 10:02:20 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 15 Sep 2008 13:02:20 -0400 Subject: [fmac-discuss] prochasprocperm In-Reply-To: <200809151613.m8FGDYa11978@domus.sfbay.sun.com> References: <200809151613.m8FGDYa11978@domus.sfbay.sun.com> Message-ID: <1221498140.29542.60.camel@moss-spartans.epoch.ncsc.mil> On Mon, 2008-09-15 at 09:13 -0700, John Zolnowsky x69422/408-404-5064 wrote: > > Date: Mon, 15 Sep 2008 11:07:01 -0400 > > From: Stephen Smalley > > > > The prochasprocperm() interface in os/cred.c is used for checking > > access for a variety of inter-process operations, including but not > > limited to signal sending. It unfortunately does not specify any > > information about the particular operation. > > Does this issue extend to the somewhat deprecated hasprocperm()? > I noticed contract_process_cankill() calls both hasprocperm() > and prochasprocperm(). > > > We have several options for handling this in FMAC: > > 1) Define a single permission in the process class for this interface > > and always check that permission in this function between the two > > process security contexts/ids. > > > > 2) Extend the interface to pass information about the particular > > operation and optionally supplemental data, and use this information to > > determine which FMAC permission to check, defining different permissions > > for different operations. > > I'd suggest a variant on this. Define new interfaces relating to > the particular context, something like > prochasprocpermsignal(...) > prochasprocpermsched(...) > prochasprocpermcred(...) > > This would allow better type checking (at the language level) on the > supplemental data. > > Of course, this becomes messy if the same issue applies to haspprocperm(). I'm afraid the same issue does apply to hasprocperm() given that prochasprocperm() calls hasprocperm() to perform the actual credential checks, and given that we would want any legacy callers of hasprocperm() to also be mediated by FMAC. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Mon Sep 15 11:02:10 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Mon, 15 Sep 2008 14:02:10 -0400 Subject: [fmac-discuss] [PATCH] Set linker security flag on security context transitions Message-ID: <1221501730.29542.100.camel@moss-spartans.epoch.ncsc.mil> When the calling domain is less trusted than the new domain, we want to set the linker security flag so that ld.so will not trust the caller. This is subject to policy via a process:execsetid permission check; if allowed, then the linker security flag is not set. We set the EXECSETID_UGIDS flag because that is what is checked by elfexec(). There appear to be no side effects from setting this flag. If desired, we could introduce our own flag value here, as with setting of PRIV_SETUGID flag by the base context transition support. If someone could explain the rationale for why PRIV_SETID is not the same as EXECSETID_SETID and why PRIV_SETUGID is not the same as EXECSETID_UGIDS in meaning, I would be appreciative. I find it vaguely maddening that setting PRIV_SETUGID in privflags causes EXECSETID_SETID to be set in setidfl and an actual identity change resulting from PRIV_SETID results in setting of EXECSETID_UGIDS, reversing the sense of the flag names. Perhaps this is just historical and deserves a code cleanup? Example of running "LD_PRELOAD=evil.o passwd" as root from a user_t shell: dmesg output: avc: denied { execsetid } for scontext=system_u:system_r:user_t:unclassified tcontext=system_u:system_r:passwd_t:unclassified tclass=process pid=100768 comm=sh Command output: ld.so.1: passwd: warning: ./evil.o: open failed: illegal insecure pathname Of course, if we allow this permission in policy, kernel mediation of the PROT_EXEC mapping will still prevent execution of unauthorized shared objects: dmesg output: avc: denied { execute } for scontext=system_u:system_r:passwd_t:unclassified tcontext=system_u:object_r:file_t:unclassified tclass=file pid=100768 comm=passwd path=/export/home/sds/evil.o Command output: ld.so.1: passwd: fatal: ./evil.o: Permission denied Killed diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -333,7 +333,7 @@ int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, - security_id_t *prev_secidp, security_id_t *secidp) + boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) { security_id_t prev_secid, secid; int error; @@ -355,6 +355,7 @@ FILE__EXECUTE_NO_TRANS); if (error) return (error); + *execsetid = B_FALSE; *setsecid = B_FALSE; return (0); } @@ -368,6 +369,14 @@ FILE__ENTRYPOINT); if (error) return (error); + + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, + PROCESS__EXECSETID); + if (error) + *execsetid = B_TRUE; + else + *execsetid = B_FALSE; + *setsecid = B_TRUE; *prev_secidp = prev_secid; *secidp = secid; @@ -420,6 +429,8 @@ int fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode) { + _NOTE(ARGUNUSED(mode)); /* todo: distinguish read vs. write? */ + if (!fmac_enabled) return (0); return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -524,7 +524,7 @@ ssize_t resid; uid_t uid, gid; security_id_t prev_secid, secid; - boolean_t setsecid = B_FALSE; + boolean_t setsecid = B_FALSE, fmac_execsetid = B_FALSE; struct vattr vattr; char magbuf[MAGIC_BYTES]; int setid; @@ -568,7 +568,8 @@ if (level == 0) { privflags = execsetid(vp, &vattr, &uid, &gid); - error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); + error = fmac_exec(CRED(), vp, &setsecid, &fmac_execsetid, + &prev_secid, &secid); if (error) goto bad; @@ -672,6 +673,9 @@ setidfl |= EXECSETID_SETID; if (setid & PRIV_INCREASE) setidfl |= EXECSETID_PRIVS; + + if (fmac_execsetid) + setidfl |= EXECSETID_UGIDS; error = (*eswp->exec_func)(vp, uap, args, idatap, level, execsz, setidfl, exec_file, cred, brand_action); diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -92,7 +92,7 @@ security_id_t *); void fmac_vnode_post_create(vnode_t *, security_id_t); int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, - security_id_t *prev_secidp, security_id_t *secidp); + boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); int fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode); #endif /* _KERNEL */ -- Stephen Smalley National Security Agency From john.weeks at sun.com Tue Sep 16 10:30:34 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 16 Sep 2008 10:30:34 -0700 Subject: [fmac-discuss] [PATCH] Set linker security flag on security context transitions In-Reply-To: <1221501730.29542.100.camel@moss-spartans.epoch.ncsc.mil> References: <1221501730.29542.100.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48CFED3A.4050004@sun.com> Acked-by: John Weeks On 09/15/08 11:02, Stephen Smalley wrote: > When the calling domain is less trusted than the new domain, we want to > set the linker security flag so that ld.so will not trust the caller. > This is subject to policy via a process:execsetid permission check; if > allowed, then the linker security flag is not set. > > We set the EXECSETID_UGIDS flag because that is what is checked by > elfexec(). There appear to be no side effects from setting this flag. > If desired, we could introduce our own flag value here, as with setting > of PRIV_SETUGID flag by the base context transition support. > > If someone could explain the rationale for why PRIV_SETID is not the > same as EXECSETID_SETID and why PRIV_SETUGID is not the same as > EXECSETID_UGIDS in meaning, I would be appreciative. I find it vaguely > maddening that setting PRIV_SETUGID in privflags causes EXECSETID_SETID > to be set in setidfl and an actual identity change resulting from > PRIV_SETID results in setting of EXECSETID_UGIDS, reversing the sense of > the flag names. Perhaps this is just historical and deserves a code > cleanup? > > Example of running "LD_PRELOAD=evil.o passwd" as root from a user_t > shell: > dmesg output: > avc: denied { execsetid } for > scontext=system_u:system_r:user_t:unclassified > tcontext=system_u:system_r:passwd_t:unclassified tclass=process > pid=100768 comm=sh > > Command output: > ld.so.1: passwd: warning: ./evil.o: open failed: illegal insecure > pathname > > Of course, if we allow this permission in policy, kernel mediation of > the PROT_EXEC mapping will still prevent execution of unauthorized > shared objects: > > dmesg output: > avc: denied { execute } for > scontext=system_u:system_r:passwd_t:unclassified > tcontext=system_u:object_r:file_t:unclassified tclass=file pid=100768 > comm=passwd path=/export/home/sds/evil.o > > Command output: > ld.so.1: passwd: fatal: ./evil.o: Permission denied > Killed > > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -333,7 +333,7 @@ > > int > fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > - security_id_t *prev_secidp, security_id_t *secidp) > + boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) > { > security_id_t prev_secid, secid; > int error; > @@ -355,6 +355,7 @@ > FILE__EXECUTE_NO_TRANS); > if (error) > return (error); > + *execsetid = B_FALSE; > *setsecid = B_FALSE; > return (0); > } > @@ -368,6 +369,14 @@ > FILE__ENTRYPOINT); > if (error) > return (error); > + > + error = avc_has_perm(prev_secid, secid, SECCLASS_PROCESS, > + PROCESS__EXECSETID); > + if (error) > + *execsetid = B_TRUE; > + else > + *execsetid = B_FALSE; > + > *setsecid = B_TRUE; > *prev_secidp = prev_secid; > *secidp = secid; > @@ -420,6 +429,8 @@ > int > fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode) > { > + _NOTE(ARGUNUSED(mode)); /* todo: distinguish read vs. write? */ > + > if (!fmac_enabled) > return (0); > return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), > diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c > --- a/usr/src/uts/common/os/exec.c > +++ b/usr/src/uts/common/os/exec.c > @@ -524,7 +524,7 @@ > ssize_t resid; > uid_t uid, gid; > security_id_t prev_secid, secid; > - boolean_t setsecid = B_FALSE; > + boolean_t setsecid = B_FALSE, fmac_execsetid = B_FALSE; > struct vattr vattr; > char magbuf[MAGIC_BYTES]; > int setid; > @@ -568,7 +568,8 @@ > if (level == 0) { > privflags = execsetid(vp, &vattr, &uid, &gid); > > - error = fmac_exec(CRED(), vp, &setsecid, &prev_secid, &secid); > + error = fmac_exec(CRED(), vp, &setsecid, &fmac_execsetid, > + &prev_secid, &secid); > if (error) > goto bad; > > @@ -672,6 +673,9 @@ > setidfl |= EXECSETID_SETID; > if (setid & PRIV_INCREASE) > setidfl |= EXECSETID_PRIVS; > + > + if (fmac_execsetid) > + setidfl |= EXECSETID_UGIDS; > > error = (*eswp->exec_func)(vp, uap, args, idatap, level, execsz, > setidfl, exec_file, cred, brand_action); > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -92,7 +92,7 @@ > security_id_t *); > void fmac_vnode_post_create(vnode_t *, security_id_t); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > - security_id_t *prev_secidp, security_id_t *secidp); > + boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); > int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > int fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode); > #endif /* _KERNEL */ > > From sds at tycho.nsa.gov Tue Sep 16 12:10:27 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Tue, 16 Sep 2008 15:10:27 -0400 Subject: [fmac-discuss] [PATCH] A few policy changes Message-ID: <1221592227.5404.140.camel@moss-spartans.epoch.ncsc.mil> A few policy changes to help with getting a system functioning in enforcing mode and to support ongoing work by John on pam unix_cred changes to set user session security contexts. diff --git a/usr/src/cmd/fmac/policy/domains/admin/sysadm.te b/usr/src/cmd/fmac/policy/domains/admin/sysadm.te --- a/usr/src/cmd/fmac/policy/domains/admin/sysadm.te +++ b/usr/src/cmd/fmac/policy/domains/admin/sysadm.te @@ -183,12 +183,12 @@ # # sysadm_t is the system administrator domain. # -type sysadm_t, domain, privlog, privowner, admin, userdomain; +type sysadm_t, domain, privlog, privowner, privmem, admin, userdomain; admin_domain(sysadm) # Inherit and use descriptors from remote_login_t. allow sysadm_t remote_login_t:fd inherit_fd_perms; - - +# Make sysadm unconfined for now. +unconfined_domain(sysadm_t) diff --git a/usr/src/cmd/fmac/policy/domains/system/initrc.te b/usr/src/cmd/fmac/policy/domains/system/initrc.te --- a/usr/src/cmd/fmac/policy/domains/system/initrc.te +++ b/usr/src/cmd/fmac/policy/domains/system/initrc.te @@ -31,7 +31,7 @@ # initrc_t is the domain of the init rc scripts. # initrc_exec_t is the type of the init program. # -type initrc_t, domain, privlog, privowner; +type initrc_t, domain, privlog, privuser, privrole, privowner, privmem, admin; type initrc_exec_t, file_type, sysadmfile, exec_type; type initrc_tmp_t, file_type, sysadmfile, tmpfile; @@ -162,3 +162,6 @@ # Reset tty labels. allow initrc_t tty_device_t:chr_file relabelto; + +# Make initrc_t unconfined for now. +unconfined_domain(initrc_t) diff --git a/usr/src/cmd/fmac/policy/domains/system/sshd.te b/usr/src/cmd/fmac/policy/domains/system/sshd.te --- a/usr/src/cmd/fmac/policy/domains/system/sshd.te +++ b/usr/src/cmd/fmac/policy/domains/system/sshd.te @@ -71,6 +71,9 @@ # Run shells in user_t by default domain_auto_trans(sshd_t, shell_exec_t, user_t) +# Allow sysadm_t shells on explicit request +domain_trans(sshd_t, shell_exec_t, sysadm_t) + # Read /etc/shadow allow sshd_t shadow_t:file r_file_perms; @@ -83,3 +86,7 @@ # Tell it how to relabel them type_change user_t sshd_devpts_t:chr_file user_devpts_t; + +# Check the validity of security contexts. +# Used by pam unix_cred. +allow sshd_t security_t:security check_context; diff --git a/usr/src/cmd/fmac/policy/file_contexts b/usr/src/cmd/fmac/policy/file_contexts --- a/usr/src/cmd/fmac/policy/file_contexts +++ b/usr/src/cmd/fmac/policy/file_contexts @@ -136,12 +136,11 @@ /lib/svc/bin/svc.startd system_u:object_r:initrc_exec_t /lib/svc/bin/svc.configd system_u:object_r:initrc_exec_t /lib/ld.*\.so.* system_u:object_r:ld_so_t -/lib/lib.*\.so.* system_u:object_r:shlib_t # # /sbin # -/sbin(/.*)? system_u:object_r:sbin_t +/sbin(/.*)? system_u:object_r:bin_t /sbin/sh system_u:object_r:shell_exec_t /sbin/ifconfig system_u:object_r:ifconfig_exec_t /sbin/init system_u:object_r:init_exec_t @@ -189,8 +188,6 @@ # /usr/lib(/.*)? system_u:object_r:lib_t /usr/lib/ssh/sshd system_u:object_r:sshd_exec_t -/usr/lib/saf/ttymon system_u:object_r:getty_exec_t -/usr/lib/lib.*\.so.* system_u:object_r:shlib_t /usr/lib/inet/inetd system_u:object_r:inetd_exec_t /usr/lib/inet/in\..*d system_u:object_r:inetd_child_exec_t /usr/lib/sendmail system_u:object_r:sendmail_exec_t @@ -198,7 +195,7 @@ # # /usr/sbin # -/usr/sbin(/.*)? system_u:object_r:sbin_t +/usr/sbin(/.*)? system_u:object_r:bin_t /usr/sbin/fsck system_u:object_r:fsadm_exec_t /usr/sbin/mkfs system_u:object_r:fsadm_exec_t /usr/sbin/fdisk system_u:object_r:fsadm_exec_t @@ -211,7 +208,7 @@ /usr/sbin/in.ftpd system_u:object_r:ftpd_exec_t /usr/sbin/rpcbind system_u:object_r:portmap_exec_t /usr/sbin/rpc\..* system_u:object_r:rpcd_exec_t -/usr/sbin/makemap system_u:object_r:sbin_t +/usr/sbin/makemap system_u:object_r:bin_t # # /usr/sadm @@ -224,9 +221,8 @@ # /usr/X11 # /usr/X11/bin(/.*)? system_u:object_r:bin_t -/usr/X11/bin/Xorg system_u:object_r:xserver_exec_t +/usr/X11/bin/amd64/Xorg system_u:object_r:xserver_exec_t /usr/X11/lib(/.*)? system_u:object_r:lib_t -/usr/X11/lib/lib.*\.so.* system_u:object_r:shlib_t /usr/X11/share/man(/.*)? system_u:object_r:man_t # @@ -256,3 +252,6 @@ # /var/log # /var/log(/.*)? system_u:object_r:var_log_t + +# Wrapper for architecture-specific executables. +/usr/lib/isaexec system_u:object_r:bin_t diff --git a/usr/src/cmd/fmac/policy/macros.te b/usr/src/cmd/fmac/policy/macros.te --- a/usr/src/cmd/fmac/policy/macros.te +++ b/usr/src/cmd/fmac/policy/macros.te @@ -250,7 +250,7 @@ define(`uses_shlib',` allow $1 ld_so_t:file rx_file_perms; allow $1 ld_so_t:file execute_no_trans; -allow $1 shlib_t:file rx_file_perms; +allow $1 { shlib_t lib_t }:file rx_file_perms; ') ################################# @@ -460,4 +460,8 @@ allow $1_t $2_devpts_t:chr_file rw_file_perms; ') - +define(`unconfined_domain', ` +allow $1 domain:process *; +allow $1 file_type:dir_file_class_set *; +allow $1 security_t:security *; +') diff --git a/usr/src/cmd/fmac/policy/rbac b/usr/src/cmd/fmac/policy/rbac --- a/usr/src/cmd/fmac/policy/rbac +++ b/usr/src/cmd/fmac/policy/rbac @@ -84,9 +84,7 @@ fsadm_t ifconfig_t logrotate_t - sysadm_t # single-user mode user_mail_t # mail sent by crond - user_t }; # diff --git a/usr/src/cmd/fmac/policy/types/file.te b/usr/src/cmd/fmac/policy/types/file.te --- a/usr/src/cmd/fmac/policy/types/file.te +++ b/usr/src/cmd/fmac/policy/types/file.te @@ -112,13 +112,7 @@ # # lib_t is the type of files in the system lib directories. # -type lib_t, file_type, sysadmfile; - -# -# shlib_t is the type of shared objects in the system lib -# directories. -# -type shlib_t, file_type, sysadmfile; +type lib_t alias shlib_t, file_type, sysadmfile; # # ld_so_t is the type of the system dynamic loaders. @@ -128,7 +122,7 @@ # # bin_t is the type of files in the system bin directories. # -type bin_t, file_type, sysadmfile; +type bin_t alias sbin_t, file_type, sysadmfile; # # ls_exec_t is the type of the ls program. @@ -139,11 +133,6 @@ # chkpwd_exec_t is the type of the pwdb_chkpwd program. # type chkpwd_exec_t, file_type, exec_type, sysadmfile; - -# -# sbin_t is the type of files in the system sbin directories. -# -type sbin_t, file_type, sysadmfile; # # usr_t is the type for /usr. diff --git a/usr/src/cmd/fmac/policy/users b/usr/src/cmd/fmac/policy/users --- a/usr/src/cmd/fmac/policy/users +++ b/usr/src/cmd/fmac/policy/users @@ -47,6 +47,12 @@ # user system_u roles system_r; +# +# user_u is the fallback FMAC user identity for users who +# have no specific FMAC user identity in the policy. It +# is limited to the unprivileged user_r role. +user user_u roles { user_r }; + # # The following users correspond to Unix identities. # These identities are typically assigned as the user attribute @@ -55,6 +61,3 @@ user root roles { user_r sysadm_r }; -user jadmin roles { user_r sysadm_r }; - -user jdoe roles { user_r }; -- Stephen Smalley National Security Agency From john.weeks at sun.com Tue Sep 16 12:53:11 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 16 Sep 2008 12:53:11 -0700 Subject: [fmac-discuss] [PATCH] A few policy changes In-Reply-To: <1221592227.5404.140.camel@moss-spartans.epoch.ncsc.mil> References: <1221592227.5404.140.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D00EA7.9060208@sun.com> Acked-by: John Weeks On 09/16/08 12:10, Stephen Smalley wrote: > A few policy changes to help with getting a system functioning in > enforcing mode and to support ongoing work by John on pam unix_cred > changes to set user session security contexts. > > diff --git a/usr/src/cmd/fmac/policy/domains/admin/sysadm.te b/usr/src/cmd/fmac/policy/domains/admin/sysadm.te > --- a/usr/src/cmd/fmac/policy/domains/admin/sysadm.te > +++ b/usr/src/cmd/fmac/policy/domains/admin/sysadm.te > @@ -183,12 +183,12 @@ > # > # sysadm_t is the system administrator domain. > # > -type sysadm_t, domain, privlog, privowner, admin, userdomain; > +type sysadm_t, domain, privlog, privowner, privmem, admin, userdomain; > > admin_domain(sysadm) > > # Inherit and use descriptors from remote_login_t. > allow sysadm_t remote_login_t:fd inherit_fd_perms; > > - > - > +# Make sysadm unconfined for now. > +unconfined_domain(sysadm_t) > diff --git a/usr/src/cmd/fmac/policy/domains/system/initrc.te b/usr/src/cmd/fmac/policy/domains/system/initrc.te > --- a/usr/src/cmd/fmac/policy/domains/system/initrc.te > +++ b/usr/src/cmd/fmac/policy/domains/system/initrc.te > @@ -31,7 +31,7 @@ > # initrc_t is the domain of the init rc scripts. > # initrc_exec_t is the type of the init program. > # > -type initrc_t, domain, privlog, privowner; > +type initrc_t, domain, privlog, privuser, privrole, privowner, privmem, admin; > type initrc_exec_t, file_type, sysadmfile, exec_type; > > type initrc_tmp_t, file_type, sysadmfile, tmpfile; > @@ -162,3 +162,6 @@ > > # Reset tty labels. > allow initrc_t tty_device_t:chr_file relabelto; > + > +# Make initrc_t unconfined for now. > +unconfined_domain(initrc_t) > diff --git a/usr/src/cmd/fmac/policy/domains/system/sshd.te b/usr/src/cmd/fmac/policy/domains/system/sshd.te > --- a/usr/src/cmd/fmac/policy/domains/system/sshd.te > +++ b/usr/src/cmd/fmac/policy/domains/system/sshd.te > @@ -71,6 +71,9 @@ > # Run shells in user_t by default > domain_auto_trans(sshd_t, shell_exec_t, user_t) > > +# Allow sysadm_t shells on explicit request > +domain_trans(sshd_t, shell_exec_t, sysadm_t) > + > # Read /etc/shadow > allow sshd_t shadow_t:file r_file_perms; > > @@ -83,3 +86,7 @@ > > # Tell it how to relabel them > type_change user_t sshd_devpts_t:chr_file user_devpts_t; > + > +# Check the validity of security contexts. > +# Used by pam unix_cred. > +allow sshd_t security_t:security check_context; > diff --git a/usr/src/cmd/fmac/policy/file_contexts b/usr/src/cmd/fmac/policy/file_contexts > --- a/usr/src/cmd/fmac/policy/file_contexts > +++ b/usr/src/cmd/fmac/policy/file_contexts > @@ -136,12 +136,11 @@ > /lib/svc/bin/svc.startd system_u:object_r:initrc_exec_t > /lib/svc/bin/svc.configd system_u:object_r:initrc_exec_t > /lib/ld.*\.so.* system_u:object_r:ld_so_t > -/lib/lib.*\.so.* system_u:object_r:shlib_t > > # > # /sbin > # > -/sbin(/.*)? system_u:object_r:sbin_t > +/sbin(/.*)? system_u:object_r:bin_t > /sbin/sh system_u:object_r:shell_exec_t > /sbin/ifconfig system_u:object_r:ifconfig_exec_t > /sbin/init system_u:object_r:init_exec_t > @@ -189,8 +188,6 @@ > # > /usr/lib(/.*)? system_u:object_r:lib_t > /usr/lib/ssh/sshd system_u:object_r:sshd_exec_t > -/usr/lib/saf/ttymon system_u:object_r:getty_exec_t > -/usr/lib/lib.*\.so.* system_u:object_r:shlib_t > /usr/lib/inet/inetd system_u:object_r:inetd_exec_t > /usr/lib/inet/in\..*d system_u:object_r:inetd_child_exec_t > /usr/lib/sendmail system_u:object_r:sendmail_exec_t > @@ -198,7 +195,7 @@ > # > # /usr/sbin > # > -/usr/sbin(/.*)? system_u:object_r:sbin_t > +/usr/sbin(/.*)? system_u:object_r:bin_t > /usr/sbin/fsck system_u:object_r:fsadm_exec_t > /usr/sbin/mkfs system_u:object_r:fsadm_exec_t > /usr/sbin/fdisk system_u:object_r:fsadm_exec_t > @@ -211,7 +208,7 @@ > /usr/sbin/in.ftpd system_u:object_r:ftpd_exec_t > /usr/sbin/rpcbind system_u:object_r:portmap_exec_t > /usr/sbin/rpc\..* system_u:object_r:rpcd_exec_t > -/usr/sbin/makemap system_u:object_r:sbin_t > +/usr/sbin/makemap system_u:object_r:bin_t > > # > # /usr/sadm > @@ -224,9 +221,8 @@ > # /usr/X11 > # > /usr/X11/bin(/.*)? system_u:object_r:bin_t > -/usr/X11/bin/Xorg system_u:object_r:xserver_exec_t > +/usr/X11/bin/amd64/Xorg system_u:object_r:xserver_exec_t > /usr/X11/lib(/.*)? system_u:object_r:lib_t > -/usr/X11/lib/lib.*\.so.* system_u:object_r:shlib_t > /usr/X11/share/man(/.*)? system_u:object_r:man_t > > # > @@ -256,3 +252,6 @@ > # /var/log > # > /var/log(/.*)? system_u:object_r:var_log_t > + > +# Wrapper for architecture-specific executables. > +/usr/lib/isaexec system_u:object_r:bin_t > diff --git a/usr/src/cmd/fmac/policy/macros.te b/usr/src/cmd/fmac/policy/macros.te > --- a/usr/src/cmd/fmac/policy/macros.te > +++ b/usr/src/cmd/fmac/policy/macros.te > @@ -250,7 +250,7 @@ > define(`uses_shlib',` > allow $1 ld_so_t:file rx_file_perms; > allow $1 ld_so_t:file execute_no_trans; > -allow $1 shlib_t:file rx_file_perms; > +allow $1 { shlib_t lib_t }:file rx_file_perms; > ') > > ################################# > @@ -460,4 +460,8 @@ > allow $1_t $2_devpts_t:chr_file rw_file_perms; > ') > > - > +define(`unconfined_domain', ` > +allow $1 domain:process *; > +allow $1 file_type:dir_file_class_set *; > +allow $1 security_t:security *; > +') > diff --git a/usr/src/cmd/fmac/policy/rbac b/usr/src/cmd/fmac/policy/rbac > --- a/usr/src/cmd/fmac/policy/rbac > +++ b/usr/src/cmd/fmac/policy/rbac > @@ -84,9 +84,7 @@ > fsadm_t > ifconfig_t > logrotate_t > - sysadm_t # single-user mode > user_mail_t # mail sent by crond > - user_t > }; > > # > diff --git a/usr/src/cmd/fmac/policy/types/file.te b/usr/src/cmd/fmac/policy/types/file.te > --- a/usr/src/cmd/fmac/policy/types/file.te > +++ b/usr/src/cmd/fmac/policy/types/file.te > @@ -112,13 +112,7 @@ > # > # lib_t is the type of files in the system lib directories. > # > -type lib_t, file_type, sysadmfile; > - > -# > -# shlib_t is the type of shared objects in the system lib > -# directories. > -# > -type shlib_t, file_type, sysadmfile; > +type lib_t alias shlib_t, file_type, sysadmfile; > > # > # ld_so_t is the type of the system dynamic loaders. > @@ -128,7 +122,7 @@ > # > # bin_t is the type of files in the system bin directories. > # > -type bin_t, file_type, sysadmfile; > +type bin_t alias sbin_t, file_type, sysadmfile; > > # > # ls_exec_t is the type of the ls program. > @@ -139,11 +133,6 @@ > # chkpwd_exec_t is the type of the pwdb_chkpwd program. > # > type chkpwd_exec_t, file_type, exec_type, sysadmfile; > - > -# > -# sbin_t is the type of files in the system sbin directories. > -# > -type sbin_t, file_type, sysadmfile; > > # > # usr_t is the type for /usr. > diff --git a/usr/src/cmd/fmac/policy/users b/usr/src/cmd/fmac/policy/users > --- a/usr/src/cmd/fmac/policy/users > +++ b/usr/src/cmd/fmac/policy/users > @@ -47,6 +47,12 @@ > # > user system_u roles system_r; > > +# > +# user_u is the fallback FMAC user identity for users who > +# have no specific FMAC user identity in the policy. It > +# is limited to the unprivileged user_r role. > +user user_u roles { user_r }; > + > # > # The following users correspond to Unix identities. > # These identities are typically assigned as the user attribute > @@ -55,6 +61,3 @@ > > user root roles { user_r sysadm_r }; > > -user jadmin roles { user_r sysadm_r }; > - > -user jdoe roles { user_r }; > > From john.weeks at sun.com Tue Sep 16 22:56:06 2008 From: john.weeks at sun.com (John Weeks) Date: Tue, 16 Sep 2008 22:56:06 -0700 Subject: [fmac-discuss] [PATCH] fmacsys_getprevcon calling wrong cred function Message-ID: <48D09BF6.1030809@sun.com> # HG changeset patch # User John Weeks # Date 1221623966 25200 # Node ID 1a4322f3a46d9950e4ba7927b30d646af355c37d # Parent ff1aaba25d5716b2c44b4ec71a7d7b1812010b6a fmacsys_getprevcon calling wrong cred function diff --git a/usr/src/uts/common/syscall/fmacsys.c b/usr/src/uts/common/syscall/fmacsys.c --- a/usr/src/uts/common/syscall/fmacsys.c +++ b/usr/src/uts/common/syscall/fmacsys.c @@ -332,7 +332,7 @@ int err = 0; /* If previous context not set, return null string */ - if (crgetexecsecid(CRED()) == SECSID_NULL) { + if (crgetprevsecid(CRED()) == SECSID_NULL) { if (subyte(scontext, 0) < 0) return (set_errno(EFAULT)); else From sds at tycho.nsa.gov Wed Sep 17 04:49:44 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 17 Sep 2008 07:49:44 -0400 Subject: [fmac-discuss] [PATCH] fmacsys_getprevcon calling wrong cred function In-Reply-To: <48D09BF6.1030809@sun.com> References: <48D09BF6.1030809@sun.com> Message-ID: <1221652184.14126.7.camel@moss-spartans.epoch.ncsc.mil> On Tue, 2008-09-16 at 22:56 -0700, John Weeks wrote: > # HG changeset patch > # User John Weeks > # Date 1221623966 25200 > # Node ID 1a4322f3a46d9950e4ba7927b30d646af355c37d > # Parent ff1aaba25d5716b2c44b4ec71a7d7b1812010b6a > fmacsys_getprevcon calling wrong cred function > > diff --git a/usr/src/uts/common/syscall/fmacsys.c b/usr/src/uts/common/syscall/fmacsys.c > --- a/usr/src/uts/common/syscall/fmacsys.c > +++ b/usr/src/uts/common/syscall/fmacsys.c > @@ -332,7 +332,7 @@ > int err = 0; > > /* If previous context not set, return null string */ > - if (crgetexecsecid(CRED()) == SECSID_NULL) { > + if (crgetprevsecid(CRED()) == SECSID_NULL) { > if (subyte(scontext, 0) < 0) > return (set_errno(EFAULT)); > else Acked-by: Stephen Smalley Two slightly tangential observations however: - I think we would benefit from #include'ing cred_impl.h in fmacsys.c and fmac.c and directly referencing the secid fields so that we don't incur extraneous function call overhead whenever we access the cred secids in the core FMAC code. Any objection? - We don't yet have a fscreate secid supported in FMAC, so applications cannot yet directly create files in a given security context (they can only relabel after the fact). Given such a fscreate secid and a setfscreatecon() system call, it would be a simple modification to fmac_vnode_create() to use that secid if set, just as the domain transition logic uses the execsecid if set. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Sep 17 05:23:52 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 17 Sep 2008 08:23:52 -0400 Subject: [fmac-discuss] Mediating link, unlink, rename, ... Message-ID: <1221654232.14126.31.camel@moss-spartans.epoch.ncsc.mil> Hi, I had originally thought that by instrumenting fop_access() with a FMAC hook, we would automatically pick up basic write access checks on directories for operations such as link, unlink, and rename and thus have at least coarse-grained checking until I could implement the finer-grained checks in the individual operations - this is the behavior we get in Linux from instrumenting the core permission() function there. However, I see that in Solaris, those operations are entirely implemented by the underlying filesystem methods and they do not call back into VOP_ACCESS() for the directory permission checks, instead using their own internal functions for such access checking, so we don't get any FMAC checking on them yet. In looking at fop_link() as an example, it appears that we could insert a FMAC hook call prior to invoking the underlying ->vop_link method that would apply appropriate FMAC permission checks on the directory vnode (add_name permission) and on the source file vnode (link permission). However, in looking at the underlying zfs_link() code, I notice that on entry it calls VOP_REALVP() on the source vnode, so we likely would need to do the same in the FMAC hook to ensure we are operating on the same vnode. Any problems with doing this twice? The reason why we want to insert the FMAC hooks into the generic vfs layer (e.g. fop_link) rather than the underlying filesystem functions (e.g. zfs_link) is that MAC labeling and access control needs to be applied to all filesystems. Even filesystems that won't natively support MAC labeling will get a default label assigned to their files. While we could insert FMAC hooks into all of the underlying filesystem functions, that seems rather onerous and fragile compared to doing it once in the vfs. However, the division of labor between the vfs and the filesystem-specific code is rather different in Solaris than in Linux. Any objections or concerns with this approach? -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Wed Sep 17 08:20:10 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Wed, 17 Sep 2008 09:20:10 -0600 Subject: [fmac-discuss] Mediating link, unlink, rename, ... In-Reply-To: <1221654232.14126.31.camel@moss-spartans.epoch.ncsc.mil> References: <1221654232.14126.31.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D1202A.5020502@Sun.COM> Stephen Smalley wrote: > Hi, > > I had originally thought that by instrumenting fop_access() with a FMAC > hook, we would automatically pick up basic write access checks on > directories for operations such as link, unlink, and rename and thus > have at least coarse-grained checking until I could implement the > finer-grained checks in the individual operations - this is the behavior > we get in Linux from instrumenting the core permission() function there. > However, I see that in Solaris, those operations are entirely > implemented by the underlying filesystem methods and they do not call > back into VOP_ACCESS() for the directory permission checks, instead > using their own internal functions for such access checking, so we don't > get any FMAC checking on them yet. > > In looking at fop_link() as an example, it appears that we could insert > a FMAC hook call prior to invoking the underlying ->vop_link method that > would apply appropriate FMAC permission checks on the directory vnode > (add_name permission) and on the source file vnode (link permission). > However, in looking at the underlying zfs_link() code, I notice that on > entry it calls VOP_REALVP() on the source vnode, so we likely would need > to do the same in the FMAC hook to ensure we are operating on the same > vnode. Any problems with doing this twice? > > The reason why we want to insert the FMAC hooks into the generic vfs > layer (e.g. fop_link) rather than the underlying filesystem functions > (e.g. zfs_link) is that MAC labeling and access control needs to be > applied to all filesystems. Even filesystems that won't natively > support MAC labeling will get a default label assigned to their files. > While we could insert FMAC hooks into all of the underlying filesystem > functions, that seems rather onerous and fragile compared to doing it > once in the vfs. However, the division of labor between the vfs and the > filesystem-specific code is rather different in Solaris than in Linux. > > Any objections or concerns with this approach? > I would prefer to only do the checks once. The checks are probably done in the individual file systems today because we didn't have the "fop" layer until Solaris 10. The fop layer was added as part of the File Event Montitoring "fem" changes. Now that we have the "fop" layer it seems like a lot of the checks could be hoisted out of the file systems and into the "fop" layer. I do see one potential problem with pulling the access checks out of the file system and into the fop layer, though. With ZFS it determines whether a file or directory can be created based on the ACE_ADD_FILE or ACE_ADD_SUBDIRECTORY ACL permission. We would also have a similar situation with deleting and renaming files where special "delete" permissions may come into play. The VOP_ACCESS() interface was extended last year to allow for NFSv4 ACL masks to be checked for, but this is only supported in ZFS. The NFS server can easily check for this support via vfs_has_feature(), but I'm not sure how the NFS client could request an access check based on NFSv4 ACL permission masks. -Mark From sds at tycho.nsa.gov Wed Sep 17 10:04:02 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 17 Sep 2008 13:04:02 -0400 Subject: [fmac-discuss] [PATCH] Mediate create and link Message-ID: <1221671042.14126.74.camel@moss-spartans.epoch.ncsc.mil> Apply directory and file permission checks on create and link operations. This extends the existing fmac_vnode_create() hook to apply dir:add_name and file:create permission checks and adds a new fmac_vnode_link() hook to apply dir:add_name and file:link permission checks. Other changes include: - pass the link name to audit for inclusion in avc messages, - fix memory leak of security context in fmac_vnode_create(), - pass the vnode to audit on the fmac_exec() checks so that path= info is included in avc messages. The issue of unifying this logic with the corresponding filesystem access checking is deferred to a future patch. Sample avc output with this patch applied: avc: denied { add_name } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100779 comm=ln path=/etc name=foo avc: denied { link } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100779 comm=ln path=/etc/shadow name=foo diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c --- a/usr/src/uts/common/fmac/avc.c +++ b/usr/src/uts/common/fmac/avc.c @@ -567,6 +567,8 @@ vp = a->u.fs.vp; if (vp && vp->v_path) avc_audit_append(" path=%s", vp->v_path); + if (a->u.fs.name) + avc_audit_append(" name=%s", a->u.fs.name); break; } } diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -262,8 +262,7 @@ uint32_t scontext_len; xoptattr_t *xoap; int error; - - _NOTE(ARGUNUSED(name)); /* future use in audit message */ + avc_audit_data_t ad; if (!fmac_enabled) return (0); @@ -284,6 +283,24 @@ cr_secid = crgetsecid(cr); + error = security_transition_sid(cr_secid, dvp->v_secid, sclass, + &secid); + if (error) + return (error); + + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = dvp; + ad.u.fs.name = name; + + error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, + DIR__ADD_NAME, &ad); + if (error) + return (error); + + error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); + if (error) + return (error); + /* * Wrap the vattr with an xvattr so we can pass the * secctx to the fs code. @@ -293,24 +310,17 @@ xvap->xva_vattr.va_mask |= AT_XVATTR; /* reset after memcpy */ XVA_SET_REQ(xvap, XAT_SECCTX); - error = security_transition_sid(cr_secid, dvp->v_secid, sclass, - &secid); - if (error) - return (error); - error = security_sid_to_context(secid, &scontext, &scontext_len); if (error) return (error); if (scontext_len > sizeof (xoap->xoa_secctx)) - return (EINVAL); + goto inval; xoap = xva_getxoptattr(xvap); if (!xoap) - return (EINVAL); + goto inval; (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx)); - - *secidp = secid; /* * Switch the vap pointer to the newly populated xvattr. @@ -318,7 +328,12 @@ * the underlying fs code. The original vattr is not mutated. */ *vapp = &xvap->xva_vattr; + *secidp = secid; + security_context_free(scontext); return (0); +inval: + security_context_free(scontext); + return (EINVAL); } void @@ -332,11 +347,47 @@ } int +fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, + caller_context_t *ct) +{ + security_id_t cr_secid; + security_class_t sclass; + int error; + vnode_t *realvp; + avc_audit_data_t ad; + + if (!fmac_enabled) + return (0); + + sclass = fmac_vtype_to_sclass(svp->v_type); + if (!sclass) + return (0); + + if (VOP_REALVP(svp, &realvp, ct) == 0) + svp = realvp; + + cr_secid = crgetsecid(cr); + + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = tdvp; + ad.u.fs.name = name; + error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR, + DIR__ADD_NAME, &ad); + if (error) + return (error); + + ad.u.fs.vp = svp; + return (avc_has_perm_audit(cr_secid, svp->v_secid, sclass, + FILE__LINK, &ad)); +} + +int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) { security_id_t prev_secid, secid; int error; + avc_audit_data_t ad; if (!fmac_enabled) return (0); @@ -351,8 +402,10 @@ } if (prev_secid == secid) { - error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, - FILE__EXECUTE_NO_TRANS); + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = vp; + error = avc_has_perm_audit(prev_secid, vp->v_secid, + SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); if (error) return (error); *execsetid = B_FALSE; @@ -365,8 +418,10 @@ if (error) return (error); - error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, - FILE__ENTRYPOINT); + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = vp; + error = avc_has_perm_audit(secid, vp->v_secid, SECCLASS_FILE, + FILE__ENTRYPOINT, &ad); if (error) return (error); diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -3445,6 +3445,10 @@ VOPXID_MAP_CR(tdvp, cr); + err = fmac_vnode_link(tdvp, svp, tnm, cr, ct); + if (err) + return (err); + err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags); VOPSTATS_UPDATE(tdvp, link); return (err); diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h --- a/usr/src/uts/common/sys/fmac/avc.h +++ b/usr/src/uts/common/sys/fmac/avc.h @@ -83,6 +83,7 @@ union { struct { struct vnode *vp; + char *name; } fs; } u; diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -91,6 +91,8 @@ int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, security_id_t *); void fmac_vnode_post_create(vnode_t *, security_id_t); +int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, + caller_context_t *ct); int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Wed Sep 17 10:05:09 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 17 Sep 2008 13:05:09 -0400 Subject: [fmac-discuss] Mediating link, unlink, rename, ... In-Reply-To: <48D1202A.5020502@Sun.COM> References: <1221654232.14126.31.camel@moss-spartans.epoch.ncsc.mil> <48D1202A.5020502@Sun.COM> Message-ID: <1221671109.14126.77.camel@moss-spartans.epoch.ncsc.mil> On Wed, 2008-09-17 at 09:20 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > Hi, > > > > I had originally thought that by instrumenting fop_access() with a FMAC > > hook, we would automatically pick up basic write access checks on > > directories for operations such as link, unlink, and rename and thus > > have at least coarse-grained checking until I could implement the > > finer-grained checks in the individual operations - this is the behavior > > we get in Linux from instrumenting the core permission() function there. > > However, I see that in Solaris, those operations are entirely > > implemented by the underlying filesystem methods and they do not call > > back into VOP_ACCESS() for the directory permission checks, instead > > using their own internal functions for such access checking, so we don't > > get any FMAC checking on them yet. > > > > In looking at fop_link() as an example, it appears that we could insert > > a FMAC hook call prior to invoking the underlying ->vop_link method that > > would apply appropriate FMAC permission checks on the directory vnode > > (add_name permission) and on the source file vnode (link permission). > > However, in looking at the underlying zfs_link() code, I notice that on > > entry it calls VOP_REALVP() on the source vnode, so we likely would need > > to do the same in the FMAC hook to ensure we are operating on the same > > vnode. Any problems with doing this twice? > > > > The reason why we want to insert the FMAC hooks into the generic vfs > > layer (e.g. fop_link) rather than the underlying filesystem functions > > (e.g. zfs_link) is that MAC labeling and access control needs to be > > applied to all filesystems. Even filesystems that won't natively > > support MAC labeling will get a default label assigned to their files. > > While we could insert FMAC hooks into all of the underlying filesystem > > functions, that seems rather onerous and fragile compared to doing it > > once in the vfs. However, the division of labor between the vfs and the > > filesystem-specific code is rather different in Solaris than in Linux. > > > > Any objections or concerns with this approach? > > > > I would prefer to only do the checks once. > > The checks are probably done in the individual file systems today > because we didn't have the "fop" layer until Solaris 10. The fop layer > was added as part of the File Event Montitoring "fem" changes. > > Now that we have the "fop" layer it seems like a lot of the checks could > be hoisted out of the file systems and into the "fop" layer. > > I do see one potential problem with pulling the access checks out of the > file system and into the fop layer, though. With ZFS it determines > whether a file or directory can be created based on the ACE_ADD_FILE or > ACE_ADD_SUBDIRECTORY ACL permission. We would also have a similar > situation with deleting and renaming files where special "delete" > permissions may come into play. The VOP_ACCESS() interface was extended > last year to allow for NFSv4 ACL masks to be checked for, but this is > only supported in ZFS. The NFS server can easily check for this support > via vfs_has_feature(), but I'm not sure how the NFS client could request > an access check based on NFSv4 ACL permission masks. Ok, I've posted a patch introducing a FMAC hook into fop_link() for now; we'll have to investigate later how to unify this with the existing access checks in the filesystem code. -- Stephen Smalley National Security Agency From john.weeks at sun.com Wed Sep 17 12:59:45 2008 From: john.weeks at sun.com (John Weeks) Date: Wed, 17 Sep 2008 12:59:45 -0700 Subject: [fmac-discuss] [PATCH] Mediate create and link In-Reply-To: <1221671042.14126.74.camel@moss-spartans.epoch.ncsc.mil> References: <1221671042.14126.74.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D161B1.7060304@sun.com> Acked-by: John Weeks On 09/17/08 10:04, Stephen Smalley wrote: > Apply directory and file permission checks on create and link > operations. This extends the existing fmac_vnode_create() hook to apply > dir:add_name and file:create permission checks and adds a new > fmac_vnode_link() hook to apply dir:add_name and file:link permission > checks. Other changes include: > - pass the link name to audit for inclusion in avc messages, > - fix memory leak of security context in fmac_vnode_create(), > - pass the vnode to audit on the fmac_exec() checks so that path= info > is included in avc messages. > > The issue of unifying this logic with the corresponding filesystem > access checking is deferred to a future patch. > > Sample avc output with this patch applied: > > avc: denied { add_name } for > scontext=user_u:user_r:user_t:unclassified > tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100779 > comm=ln path=/etc name=foo > > avc: denied { link } for scontext=user_u:user_r:user_t:unclassified > tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100779 > comm=ln path=/etc/shadow name=foo > > diff --git a/usr/src/uts/common/fmac/avc.c b/usr/src/uts/common/fmac/avc.c > --- a/usr/src/uts/common/fmac/avc.c > +++ b/usr/src/uts/common/fmac/avc.c > @@ -567,6 +567,8 @@ > vp = a->u.fs.vp; > if (vp && vp->v_path) > avc_audit_append(" path=%s", vp->v_path); > + if (a->u.fs.name) > + avc_audit_append(" name=%s", a->u.fs.name); > break; > } > } > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -262,8 +262,7 @@ > uint32_t scontext_len; > xoptattr_t *xoap; > int error; > - > - _NOTE(ARGUNUSED(name)); /* future use in audit message */ > + avc_audit_data_t ad; > > if (!fmac_enabled) > return (0); > @@ -284,6 +283,24 @@ > > cr_secid = crgetsecid(cr); > > + error = security_transition_sid(cr_secid, dvp->v_secid, sclass, > + &secid); > + if (error) > + return (error); > + > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = dvp; > + ad.u.fs.name = name; > + > + error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, > + DIR__ADD_NAME, &ad); > + if (error) > + return (error); > + > + error = avc_has_perm_audit(cr_secid, secid, sclass, FILE__CREATE, &ad); > + if (error) > + return (error); > + > /* > * Wrap the vattr with an xvattr so we can pass the > * secctx to the fs code. > @@ -293,24 +310,17 @@ > xvap->xva_vattr.va_mask |= AT_XVATTR; /* reset after memcpy */ > XVA_SET_REQ(xvap, XAT_SECCTX); > > - error = security_transition_sid(cr_secid, dvp->v_secid, sclass, > - &secid); > - if (error) > - return (error); > - > error = security_sid_to_context(secid, &scontext, &scontext_len); > if (error) > return (error); > > if (scontext_len > sizeof (xoap->xoa_secctx)) > - return (EINVAL); > + goto inval; > > xoap = xva_getxoptattr(xvap); > if (!xoap) > - return (EINVAL); > + goto inval; > (void) strncpy(xoap->xoa_secctx, scontext, sizeof (xoap->xoa_secctx)); > - > - *secidp = secid; > > /* > * Switch the vap pointer to the newly populated xvattr. > @@ -318,7 +328,12 @@ > * the underlying fs code. The original vattr is not mutated. > */ > *vapp = &xvap->xva_vattr; > + *secidp = secid; > + security_context_free(scontext); > return (0); > +inval: > + security_context_free(scontext); > + return (EINVAL); > } > > void > @@ -332,11 +347,47 @@ > } > > int > +fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, > + caller_context_t *ct) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + int error; > + vnode_t *realvp; > + avc_audit_data_t ad; > + > + if (!fmac_enabled) > + return (0); > + > + sclass = fmac_vtype_to_sclass(svp->v_type); > + if (!sclass) > + return (0); > + > + if (VOP_REALVP(svp, &realvp, ct) == 0) > + svp = realvp; > + > + cr_secid = crgetsecid(cr); > + > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = tdvp; > + ad.u.fs.name = name; > + error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR, > + DIR__ADD_NAME, &ad); > + if (error) > + return (error); > + > + ad.u.fs.vp = svp; > + return (avc_has_perm_audit(cr_secid, svp->v_secid, sclass, > + FILE__LINK, &ad)); > +} > + > +int > fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) > { > security_id_t prev_secid, secid; > int error; > + avc_audit_data_t ad; > > if (!fmac_enabled) > return (0); > @@ -351,8 +402,10 @@ > } > > if (prev_secid == secid) { > - error = avc_has_perm(prev_secid, vp->v_secid, SECCLASS_FILE, > - FILE__EXECUTE_NO_TRANS); > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = vp; > + error = avc_has_perm_audit(prev_secid, vp->v_secid, > + SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); > if (error) > return (error); > *execsetid = B_FALSE; > @@ -365,8 +418,10 @@ > if (error) > return (error); > > - error = avc_has_perm(secid, vp->v_secid, SECCLASS_FILE, > - FILE__ENTRYPOINT); > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = vp; > + error = avc_has_perm_audit(secid, vp->v_secid, SECCLASS_FILE, > + FILE__ENTRYPOINT, &ad); > if (error) > return (error); > > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -3445,6 +3445,10 @@ > > VOPXID_MAP_CR(tdvp, cr); > > + err = fmac_vnode_link(tdvp, svp, tnm, cr, ct); > + if (err) > + return (err); > + > err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags); > VOPSTATS_UPDATE(tdvp, link); > return (err); > diff --git a/usr/src/uts/common/sys/fmac/avc.h b/usr/src/uts/common/sys/fmac/avc.h > --- a/usr/src/uts/common/sys/fmac/avc.h > +++ b/usr/src/uts/common/sys/fmac/avc.h > @@ -83,6 +83,7 @@ > union { > struct { > struct vnode *vp; > + char *name; > } fs; > } u; > > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -91,6 +91,8 @@ > int fmac_vnode_create(vnode_t *, char *, xvattr_t *, vattr_t **, cred_t *, > security_id_t *); > void fmac_vnode_post_create(vnode_t *, security_id_t); > +int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, > + caller_context_t *ct); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); > int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > > > > From sds at tycho.nsa.gov Wed Sep 17 13:59:37 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Wed, 17 Sep 2008 16:59:37 -0400 Subject: [fmac-discuss] [PATCH] Mediate unlink and rmdir Message-ID: <1221685177.21652.6.camel@moss-spartans.epoch.ncsc.mil> Apply directory and file permission checks on unlink and rmdir operations. Since the target vnode is not available in the fop_ functions, we hook the zfs_zaccess_delete() function. This limits the checking to zfs only at present. We may revisit this later in reconsidering the division of labor between the vfs and the filesystem vnode operations. diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -382,6 +382,39 @@ } int +fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr) +{ + security_id_t cr_secid; + security_class_t sclass; + access_vector_t av; + int error; + avc_audit_data_t ad; + + if (!fmac_enabled) + return (0); + + sclass = fmac_vtype_to_sclass(vp->v_type); + if (!sclass) + return (0); + + cr_secid = crgetsecid(cr); + + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = dvp; + error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, + DIR__REMOVE_NAME, &ad); + if (error) + return (error); + + ad.u.fs.vp = vp; + if (sclass == SECCLASS_DIR) + av = DIR__RMDIR; + else + av = FILE__UNLINK; + return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); +} + +int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) { diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "fs/fs_subr.h" #include @@ -2514,6 +2515,10 @@ boolean_t dzpcheck_privs = B_TRUE; boolean_t zpcheck_privs = B_TRUE; + zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr); + if (zp_error) + return (zp_error); + /* * We want specific DELETE permissions to * take precedence over WRITE/EXECUTE. We don't diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -93,6 +93,7 @@ void fmac_vnode_post_create(vnode_t *, security_id_t); int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, caller_context_t *ct); +int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr); int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Wed Sep 17 15:13:22 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Wed, 17 Sep 2008 16:13:22 -0600 Subject: [fmac-discuss] [PATCH] Mediate unlink and rmdir In-Reply-To: <1221685177.21652.6.camel@moss-spartans.epoch.ncsc.mil> References: <1221685177.21652.6.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D18102.7080500@Sun.COM> Stephen Smalley wrote: > Apply directory and file permission checks on unlink and rmdir > operations. Since the target vnode is not available in the fop_ > functions, we hook the zfs_zaccess_delete() function. This limits the > checking to zfs only at present. We may revisit this later in > reconsidering the division of labor between the vfs and the filesystem > vnode operations. > Look ok > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -382,6 +382,39 @@ > } > > int > +fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + access_vector_t av; > + int error; > + avc_audit_data_t ad; > + > + if (!fmac_enabled) > + return (0); > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (0); > + > + cr_secid = crgetsecid(cr); > + > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = dvp; > + error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, > + DIR__REMOVE_NAME, &ad); > + if (error) > + return (error); > + > + ad.u.fs.vp = vp; > + if (sclass == SECCLASS_DIR) > + av = DIR__RMDIR; > + else > + av = FILE__UNLINK; > + return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); > +} > + > +int > fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) > { > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > @@ -50,6 +50,7 @@ > #include > #include > #include > +#include > #include "fs/fs_subr.h" > #include > > @@ -2514,6 +2515,10 @@ > boolean_t dzpcheck_privs = B_TRUE; > boolean_t zpcheck_privs = B_TRUE; > > + zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr); > + if (zp_error) > + return (zp_error); > + > /* > * We want specific DELETE permissions to > * take precedence over WRITE/EXECUTE. We don't > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -93,6 +93,7 @@ > void fmac_vnode_post_create(vnode_t *, security_id_t); > int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, > caller_context_t *ct); > +int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); > int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > > > From john.weeks at sun.com Wed Sep 17 21:10:58 2008 From: john.weeks at sun.com (John Weeks) Date: Wed, 17 Sep 2008 21:10:58 -0700 Subject: [fmac-discuss] [PATCH] Mediate unlink and rmdir In-Reply-To: <1221685177.21652.6.camel@moss-spartans.epoch.ncsc.mil> References: <1221685177.21652.6.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D1D4D2.5050908@sun.com> Acked-by: John Weeks On 09/17/08 13:59, Stephen Smalley wrote: > Apply directory and file permission checks on unlink and rmdir > operations. Since the target vnode is not available in the fop_ > functions, we hook the zfs_zaccess_delete() function. This limits the > checking to zfs only at present. We may revisit this later in > reconsidering the division of labor between the vfs and the filesystem > vnode operations. > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -382,6 +382,39 @@ > } > > int > +fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + access_vector_t av; > + int error; > + avc_audit_data_t ad; > + > + if (!fmac_enabled) > + return (0); > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (0); > + > + cr_secid = crgetsecid(cr); > + > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = dvp; > + error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, > + DIR__REMOVE_NAME, &ad); > + if (error) > + return (error); > + > + ad.u.fs.vp = vp; > + if (sclass == SECCLASS_DIR) > + av = DIR__RMDIR; > + else > + av = FILE__UNLINK; > + return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); > +} > + > +int > fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) > { > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > @@ -50,6 +50,7 @@ > #include > #include > #include > +#include > #include "fs/fs_subr.h" > #include > > @@ -2514,6 +2515,10 @@ > boolean_t dzpcheck_privs = B_TRUE; > boolean_t zpcheck_privs = B_TRUE; > > + zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr); > + if (zp_error) > + return (zp_error); > + > /* > * We want specific DELETE permissions to > * take precedence over WRITE/EXECUTE. We don't > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -93,6 +93,7 @@ > void fmac_vnode_post_create(vnode_t *, security_id_t); > int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, > caller_context_t *ct); > +int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); > int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > > > From sds at tycho.nsa.gov Thu Sep 18 06:54:46 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 18 Sep 2008 09:54:46 -0400 Subject: [fmac-discuss] [PATCH] Mediate rename Message-ID: <1221746086.24048.40.camel@moss-spartans.epoch.ncsc.mil> Apply directory and file permission checks on rename operations. To allow a distinction between rename and unlink checking on the source vnode, the fmac_vnode_remove() hook in zfs_zaccess_delete() introduced by the prior patch is moved to zfs_remove() and zfs_rmdir(), and a separate fmac_vnode_rename() hook is added to zfs_rename(). As with the remove/rmdir hooks, we have to hook zfs presently for rename since the source and target vnodes are only available there. Sample AVC output on a mv /etc/shadow- /etc/shadow: avc: denied { remove_name } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100813 comm=mv path=/etc avc: denied { rename } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100813 comm=mv path=/etc/shadow- avc: denied { add_name } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100813 comm=mv path=/etc avc: denied { unlink } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100813 comm=mv path=/etc/shadow diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -382,7 +382,7 @@ } int -fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr) +fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr) { security_id_t cr_secid; security_class_t sclass; @@ -401,6 +401,7 @@ AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.vp = dvp; + ad.u.fs.name = name; error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, DIR__REMOVE_NAME, &ad); if (error) @@ -412,6 +413,65 @@ else av = FILE__UNLINK; return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); +} + +int +fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp, + cred_t *cr) +{ + security_id_t cr_secid; + security_class_t sclass, tclass; + access_vector_t av; + int error; + avc_audit_data_t ad; + + if (!fmac_enabled) + return (0); + + sclass = fmac_vtype_to_sclass(svp->v_type); + if (!sclass) + return (0); + + cr_secid = crgetsecid(cr); + + AVC_AUDIT_DATA_INIT(&ad, FS); + + ad.u.fs.vp = sdvp; + error = avc_has_perm_audit(cr_secid, sdvp->v_secid, SECCLASS_DIR, + DIR__REMOVE_NAME, &ad); + if (error) + return (error); + + ad.u.fs.vp = svp; + error = avc_has_perm_audit(cr_secid, svp->v_secid, sclass, + FILE__RENAME, &ad); + if (error) + return (error); + + ad.u.fs.vp = tdvp; + error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR, + DIR__ADD_NAME, &ad); + if (error) + return (error); + + if (tvp) { + tclass = fmac_vtype_to_sclass(tvp->v_type); + if (!tclass) + return (0); + + if (tclass == SECCLASS_DIR) + av = DIR__RMDIR; + else + av = FILE__UNLINK; + + ad.u.fs.vp = tvp; + error = avc_has_perm_audit(cr_secid, tvp->v_secid, tclass, av, + &ad); + if (error) + return (error); + } + + return (0); } int diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -50,7 +50,6 @@ #include #include #include -#include #include "fs/fs_subr.h" #include @@ -2515,10 +2514,6 @@ boolean_t dzpcheck_privs = B_TRUE; boolean_t zpcheck_privs = B_TRUE; - zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr); - if (zp_error) - return (zp_error); - /* * We want specific DELETE permissions to * take precedence over WRITE/EXECUTE. We don't diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c @@ -74,6 +74,7 @@ #include #include #include +#include /* * Programming rules. @@ -1446,6 +1447,10 @@ goto out; } + error = fmac_vnode_remove(dvp, vp, name, cr); + if (error) + goto out; + vnevent_remove(vp, dvp, name, ct); if (realnmp) @@ -1801,6 +1806,10 @@ error = EINVAL; goto out; } + + error = fmac_vnode_remove(dvp, vp, name, cr); + if (error) + goto out; vnevent_rmdir(vp, dvp, name, ct); @@ -3084,6 +3093,11 @@ if (error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)) goto out; + error = fmac_vnode_rename(sdvp, ZTOV(szp), tdvp, + tzp ? ZTOV(tzp) : NULL, cr); + if (error) + goto out; + if (ZTOV(szp)->v_type == VDIR) { /* * Check to make sure rename is valid. diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -93,7 +93,9 @@ void fmac_vnode_post_create(vnode_t *, security_id_t); int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, caller_context_t *ct); -int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr); +int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr); +int fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp, + cred_t *cr); int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); -- Stephen Smalley National Security Agency From Mark.Shellenbaum at Sun.COM Thu Sep 18 07:15:22 2008 From: Mark.Shellenbaum at Sun.COM (Mark Shellenbaum) Date: Thu, 18 Sep 2008 08:15:22 -0600 Subject: [fmac-discuss] [PATCH] Mediate rename In-Reply-To: <1221746086.24048.40.camel@moss-spartans.epoch.ncsc.mil> References: <1221746086.24048.40.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D2627A.4010306@Sun.COM> Stephen Smalley wrote: > Apply directory and file permission checks on rename operations. To > allow a distinction between rename and unlink checking on the source > vnode, the fmac_vnode_remove() hook in zfs_zaccess_delete() introduced > by the prior patch is moved to zfs_remove() and zfs_rmdir(), and a > separate fmac_vnode_rename() hook is added to zfs_rename(). As with the > remove/rmdir hooks, we have to hook zfs presently for rename since the > source and target vnodes are only available there. > > int > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > @@ -50,7 +50,6 @@ > #include > #include > #include > -#include > #include "fs/fs_subr.h" > #include > > @@ -2515,10 +2514,6 @@ > boolean_t dzpcheck_privs = B_TRUE; > boolean_t zpcheck_privs = B_TRUE; > > - zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr); > - if (zp_error) > - return (zp_error); > - > /* > * We want specific DELETE permissions to > * take precedence over WRITE/EXECUTE. We don't > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -74,6 +74,7 @@ > #include > #include > #include > +#include > > /* > * Programming rules. > @@ -1446,6 +1447,10 @@ > goto out; > } > > + error = fmac_vnode_remove(dvp, vp, name, cr); > + if (error) > + goto out; > + > vnevent_remove(vp, dvp, name, ct); > > if (realnmp) > @@ -1801,6 +1806,10 @@ > error = EINVAL; > goto out; > } > + > + error = fmac_vnode_remove(dvp, vp, name, cr); > + if (error) > + goto out; > > vnevent_rmdir(vp, dvp, name, ct); > > @@ -3084,6 +3093,11 @@ > if (error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)) > goto out; > > + error = fmac_vnode_rename(sdvp, ZTOV(szp), tdvp, > + tzp ? ZTOV(tzp) : NULL, cr); > + if (error) > + goto out; > + I thought you wanted to do the fmac checks before the file system did its own access checks? Just to make sure I'm following you. You removed the fmac check from zfs_zaccess_delete() because that function could be invoked from either an unlink or a rename operation and you want to treat a remove from a rename operation differently than an unlink operation. -Mark From sds at tycho.nsa.gov Thu Sep 18 07:27:44 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 18 Sep 2008 10:27:44 -0400 Subject: [fmac-discuss] [PATCH] Mediate rename In-Reply-To: <48D2627A.4010306@Sun.COM> References: <1221746086.24048.40.camel@moss-spartans.epoch.ncsc.mil> <48D2627A.4010306@Sun.COM> Message-ID: <1221748064.24048.50.camel@moss-spartans.epoch.ncsc.mil> On Thu, 2008-09-18 at 08:15 -0600, Mark Shellenbaum wrote: > Stephen Smalley wrote: > > Apply directory and file permission checks on rename operations. To > > allow a distinction between rename and unlink checking on the source > > vnode, the fmac_vnode_remove() hook in zfs_zaccess_delete() introduced > > by the prior patch is moved to zfs_remove() and zfs_rmdir(), and a > > separate fmac_vnode_rename() hook is added to zfs_rename(). As with the > > remove/rmdir hooks, we have to hook zfs presently for rename since the > > source and target vnodes are only available there. > > > > > int > > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > > @@ -50,7 +50,6 @@ > > #include > > #include > > #include > > -#include > > #include "fs/fs_subr.h" > > #include > > > > @@ -2515,10 +2514,6 @@ > > boolean_t dzpcheck_privs = B_TRUE; > > boolean_t zpcheck_privs = B_TRUE; > > > > - zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr); > > - if (zp_error) > > - return (zp_error); > > - > > /* > > * We want specific DELETE permissions to > > * take precedence over WRITE/EXECUTE. We don't > > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > > @@ -74,6 +74,7 @@ > > #include > > #include > > #include > > +#include > > > > /* > > * Programming rules. > > @@ -1446,6 +1447,10 @@ > > goto out; > > } > > > > + error = fmac_vnode_remove(dvp, vp, name, cr); > > + if (error) > > + goto out; > > + > > vnevent_remove(vp, dvp, name, ct); > > > > if (realnmp) > > @@ -1801,6 +1806,10 @@ > > error = EINVAL; > > goto out; > > } > > + > > + error = fmac_vnode_remove(dvp, vp, name, cr); > > + if (error) > > + goto out; > > > > vnevent_rmdir(vp, dvp, name, ct); > > > > @@ -3084,6 +3093,11 @@ > > if (error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)) > > goto out; > > > > + error = fmac_vnode_rename(sdvp, ZTOV(szp), tdvp, > > + tzp ? ZTOV(tzp) : NULL, cr); > > + if (error) > > + goto out; > > + > > I thought you wanted to do the fmac checks before the file system did > its own access checks? I'd actually prefer DAC before MAC when possible (as in fop_access(), where fmac_vnode_access() is called after ->vop_access()), but it isn't a deal breaker either way. It is mostly to reduce noise in the avc messages from harmless application/library probing that wouldn't have been allowed anyway. > Just to make sure I'm following you. You removed the fmac check from > zfs_zaccess_delete() because that function could be invoked from either > an unlink or a rename operation and you want to treat a remove from a > rename operation differently than an unlink operation. Right; in the rename case, we check: - Does the subject have remove_name permission to the source directory? - Does the subject have rename permission to the source file? - Does the subject have add_name permission to the target directory? - Does the subject have unlink permission to the target file if one exists? In the remove/rmdir case, we check: - Does the subject have remove_name permission to the directory? - Does the subject have unlink/rmdir permission to the file? Leaving the hook in zfs_zaccess_delete() was triggering an unlink check on the source file upon a rename. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Thu Sep 18 07:46:07 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 18 Sep 2008 10:46:07 -0400 Subject: [fmac-discuss] [PATCH] Mediate setting of attributes Message-ID: <1221749167.24048.60.camel@moss-spartans.epoch.ncsc.mil> Apply file:setattr permission checks on setattr and setsecattr operations. We may wish to further distinguish these operations with different permissions in the future. Sample AVC output: avc: denied { setattr } for scontext=system_u:system_r:crond_t:unclassified tcontext=system_u:object_r:var_t:unclassified tclass=file pid=100324 comm=cron path=/var/cron/log diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -475,6 +475,28 @@ } int +fmac_vnode_setattr(vnode_t *vp, cred_t *cr) +{ + security_id_t cr_secid; + security_class_t sclass; + avc_audit_data_t ad; + + if (!fmac_enabled) + return (0); + + sclass = fmac_vtype_to_sclass(vp->v_type); + if (!sclass) + return (0); + + cr_secid = crgetsecid(cr); + + AVC_AUDIT_DATA_INIT(&ad, FS); + ad.u.fs.vp = vp; + return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, + FILE__SETATTR, &ad)); +} + +int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) { diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -3274,6 +3274,11 @@ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) { return (EINVAL); } + + err = fmac_vnode_setattr(vp, cr); + if (err) + return (err); + err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct); VOPSTATS_UPDATE(vp, setattr); return (err); @@ -4069,6 +4074,11 @@ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) { return (EINVAL); } + + err = fmac_vnode_setattr(vp, cr); + if (err) + return (err); + err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct); VOPSTATS_UPDATE(vp, setsecattr); return (err); diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -96,6 +96,7 @@ int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr); int fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp, cred_t *cr); +int fmac_vnode_setattr(vnode_t *, cred_t *); int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); -- Stephen Smalley National Security Agency From john.weeks at sun.com Thu Sep 18 08:42:37 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 18 Sep 2008 08:42:37 -0700 Subject: [fmac-discuss] [PATCH] Mediate rename In-Reply-To: <1221746086.24048.40.camel@moss-spartans.epoch.ncsc.mil> References: <1221746086.24048.40.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D276ED.3030308@sun.com> Acked-by: John Weeks On 09/18/08 06:54, Stephen Smalley wrote: > Apply directory and file permission checks on rename operations. To > allow a distinction between rename and unlink checking on the source > vnode, the fmac_vnode_remove() hook in zfs_zaccess_delete() introduced > by the prior patch is moved to zfs_remove() and zfs_rmdir(), and a > separate fmac_vnode_rename() hook is added to zfs_rename(). As with the > remove/rmdir hooks, we have to hook zfs presently for rename since the > source and target vnodes are only available there. > > Sample AVC output on a mv /etc/shadow- /etc/shadow: > avc: denied { remove_name } for > scontext=user_u:user_r:user_t:unclassified > tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100813 > comm=mv path=/etc > > avc: denied { rename } for scontext=user_u:user_r:user_t:unclassified > tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100813 > comm=mv path=/etc/shadow- > > avc: denied { add_name } for > scontext=user_u:user_r:user_t:unclassified > tcontext=system_u:object_r:etc_t:unclassified tclass=dir pid=100813 > comm=mv path=/etc > > avc: denied { unlink } for scontext=user_u:user_r:user_t:unclassified > tcontext=system_u:object_r:shadow_t:unclassified tclass=file pid=100813 > comm=mv path=/etc/shadow > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -382,7 +382,7 @@ > } > > int > -fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr) > +fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr) > { > security_id_t cr_secid; > security_class_t sclass; > @@ -401,6 +401,7 @@ > > AVC_AUDIT_DATA_INIT(&ad, FS); > ad.u.fs.vp = dvp; > + ad.u.fs.name = name; > error = avc_has_perm_audit(cr_secid, dvp->v_secid, SECCLASS_DIR, > DIR__REMOVE_NAME, &ad); > if (error) > @@ -412,6 +413,65 @@ > else > av = FILE__UNLINK; > return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, av, &ad)); > +} > + > +int > +fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp, > + cred_t *cr) > +{ > + security_id_t cr_secid; > + security_class_t sclass, tclass; > + access_vector_t av; > + int error; > + avc_audit_data_t ad; > + > + if (!fmac_enabled) > + return (0); > + > + sclass = fmac_vtype_to_sclass(svp->v_type); > + if (!sclass) > + return (0); > + > + cr_secid = crgetsecid(cr); > + > + AVC_AUDIT_DATA_INIT(&ad, FS); > + > + ad.u.fs.vp = sdvp; > + error = avc_has_perm_audit(cr_secid, sdvp->v_secid, SECCLASS_DIR, > + DIR__REMOVE_NAME, &ad); > + if (error) > + return (error); > + > + ad.u.fs.vp = svp; > + error = avc_has_perm_audit(cr_secid, svp->v_secid, sclass, > + FILE__RENAME, &ad); > + if (error) > + return (error); > + > + ad.u.fs.vp = tdvp; > + error = avc_has_perm_audit(cr_secid, tdvp->v_secid, SECCLASS_DIR, > + DIR__ADD_NAME, &ad); > + if (error) > + return (error); > + > + if (tvp) { > + tclass = fmac_vtype_to_sclass(tvp->v_type); > + if (!tclass) > + return (0); > + > + if (tclass == SECCLASS_DIR) > + av = DIR__RMDIR; > + else > + av = FILE__UNLINK; > + > + ad.u.fs.vp = tvp; > + error = avc_has_perm_audit(cr_secid, tvp->v_secid, tclass, av, > + &ad); > + if (error) > + return (error); > + } > + > + return (0); > } > > int > diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c > --- a/usr/src/uts/common/fs/zfs/zfs_acl.c > +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c > @@ -50,7 +50,6 @@ > #include > #include > #include > -#include > #include "fs/fs_subr.h" > #include > > @@ -2515,10 +2514,6 @@ > boolean_t dzpcheck_privs = B_TRUE; > boolean_t zpcheck_privs = B_TRUE; > > - zp_error = fmac_vnode_remove(ZTOV(dzp), ZTOV(zp), cr); > - if (zp_error) > - return (zp_error); > - > /* > * We want specific DELETE permissions to > * take precedence over WRITE/EXECUTE. We don't > diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c > --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c > +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c > @@ -74,6 +74,7 @@ > #include > #include > #include > +#include > > /* > * Programming rules. > @@ -1446,6 +1447,10 @@ > goto out; > } > > + error = fmac_vnode_remove(dvp, vp, name, cr); > + if (error) > + goto out; > + > vnevent_remove(vp, dvp, name, ct); > > if (realnmp) > @@ -1801,6 +1806,10 @@ > error = EINVAL; > goto out; > } > + > + error = fmac_vnode_remove(dvp, vp, name, cr); > + if (error) > + goto out; > > vnevent_rmdir(vp, dvp, name, ct); > > @@ -3084,6 +3093,11 @@ > if (error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)) > goto out; > > + error = fmac_vnode_rename(sdvp, ZTOV(szp), tdvp, > + tzp ? ZTOV(tzp) : NULL, cr); > + if (error) > + goto out; > + > if (ZTOV(szp)->v_type == VDIR) { > /* > * Check to make sure rename is valid. > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -93,7 +93,9 @@ > void fmac_vnode_post_create(vnode_t *, security_id_t); > int fmac_vnode_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, > caller_context_t *ct); > -int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, cred_t *cr); > +int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr); > +int fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp, > + cred_t *cr); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); > int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > From john.weeks at sun.com Thu Sep 18 08:44:56 2008 From: john.weeks at sun.com (John Weeks) Date: Thu, 18 Sep 2008 08:44:56 -0700 Subject: [fmac-discuss] [PATCH] Mediate setting of attributes In-Reply-To: <1221749167.24048.60.camel@moss-spartans.epoch.ncsc.mil> References: <1221749167.24048.60.camel@moss-spartans.epoch.ncsc.mil> Message-ID: <48D27778.6040003@sun.com> Acked-by: John Weeks On 09/18/08 07:46, Stephen Smalley wrote: > Apply file:setattr permission checks on setattr and setsecattr > operations. We may wish to further distinguish these operations with > different permissions in the future. > > Sample AVC output: > avc: denied { setattr } for > scontext=system_u:system_r:crond_t:unclassified > tcontext=system_u:object_r:var_t:unclassified tclass=file pid=100324 > comm=cron path=/var/cron/log > > > diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c > --- a/usr/src/uts/common/fmac/fmac.c > +++ b/usr/src/uts/common/fmac/fmac.c > @@ -475,6 +475,28 @@ > } > > int > +fmac_vnode_setattr(vnode_t *vp, cred_t *cr) > +{ > + security_id_t cr_secid; > + security_class_t sclass; > + avc_audit_data_t ad; > + > + if (!fmac_enabled) > + return (0); > + > + sclass = fmac_vtype_to_sclass(vp->v_type); > + if (!sclass) > + return (0); > + > + cr_secid = crgetsecid(cr); > + > + AVC_AUDIT_DATA_INIT(&ad, FS); > + ad.u.fs.vp = vp; > + return (avc_has_perm_audit(cr_secid, vp->v_secid, sclass, > + FILE__SETATTR, &ad)); > +} > + > +int > fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp) > { > diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c > --- a/usr/src/uts/common/fs/vnode.c > +++ b/usr/src/uts/common/fs/vnode.c > @@ -3274,6 +3274,11 @@ > vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) { > return (EINVAL); > } > + > + err = fmac_vnode_setattr(vp, cr); > + if (err) > + return (err); > + > err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct); > VOPSTATS_UPDATE(vp, setattr); > return (err); > @@ -4069,6 +4074,11 @@ > vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) { > return (EINVAL); > } > + > + err = fmac_vnode_setattr(vp, cr); > + if (err) > + return (err); > + > err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct); > VOPSTATS_UPDATE(vp, setsecattr); > return (err); > diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h > --- a/usr/src/uts/common/sys/fmac/fmac.h > +++ b/usr/src/uts/common/sys/fmac/fmac.h > @@ -96,6 +96,7 @@ > int fmac_vnode_remove(vnode_t *dvp, vnode_t *vp, char *name, cred_t *cr); > int fmac_vnode_rename(vnode_t *sdvp, vnode_t *svp, vnode_t *tdvp, vnode_t *tvp, > cred_t *cr); > +int fmac_vnode_setattr(vnode_t *, cred_t *); > int fmac_exec(cred_t *cr, vnode_t *vp, boolean_t *setsecid, > boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); > int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); > From sds at tycho.nsa.gov Thu Sep 18 12:33:56 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Thu, 18 Sep 2008 15:33:56 -0400 Subject: [fmac-discuss] [PATCH] Mediate some process operations Message-ID: <1221766436.24048.128.camel@moss-spartans.epoch.ncsc.mil> Mediate process operations that presently call *hasprocperm() by extending the existing interfaces to pass an access vector and inserting a fmac_hasprocperm() hook into hasprocperm(). Sample AVC output from kill `cat /var/run/sshd.pid`: avc: denied { signal } for scontext=user_u:user_r:user_t:unclassified tcontext=system_u:system_r:sshd_t:unclassified tclass=process pid=100763 comm=bash If we wanted to augment the avc message with the target pid, we might extend the hasprocperm() interface to optionally convey the target pid if available; then prochasprocperm() could pass that information from the proc_t. diff --git a/usr/src/common/fmac/policy/flask/access_vectors b/usr/src/common/fmac/policy/flask/access_vectors --- a/usr/src/common/fmac/policy/flask/access_vectors +++ b/usr/src/common/fmac/policy/flask/access_vectors @@ -245,6 +245,7 @@ { fork transition + info sigchld sigkill sigstop @@ -252,6 +253,8 @@ ptrace getsched setsched + getcore + setcore getsession getpgid setpgid diff --git a/usr/src/uts/common/brand/lx/syscall/lx_kill.c b/usr/src/uts/common/brand/lx/syscall/lx_kill.c --- a/usr/src/uts/common/brand/lx/syscall/lx_kill.c +++ b/usr/src/uts/common/brand/lx/syscall/lx_kill.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -126,7 +128,7 @@ * to send the signal to the target pid */ if (((sig == SIGCONT) && (pp->p_sessp != curproc->p_sessp)) || - (!prochasprocperm(pp, curproc, CRED()))) { + (!prochasprocperm(pp, curproc, CRED(), fmac_sigtoav(sig)))) { mutex_exit(&pp->p_lock); rv = set_errno(EPERM); goto free_and_exit; diff --git a/usr/src/uts/common/contract/process.c b/usr/src/uts/common/contract/process.c --- a/usr/src/uts/common/contract/process.c +++ b/usr/src/uts/common/contract/process.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -488,9 +489,10 @@ int cankill; mutex_enter(&tp->p_crlock); - cankill = hasprocperm(tp->p_cred, ctp->conp_cred); + cankill = hasprocperm(tp->p_cred, ctp->conp_cred, PROCESS__SIGKILL); mutex_exit(&tp->p_crlock); - if (cankill || (sp && prochasprocperm(tp, sp, CRED()))) + if (cankill || (sp && prochasprocperm(tp, sp, CRED(), + PROCESS__SIGKILL))) return (1); return (0); diff --git a/usr/src/uts/common/disp/class.c b/usr/src/uts/common/disp/class.c --- a/usr/src/uts/common/disp/class.c +++ b/usr/src/uts/common/disp/class.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -259,7 +260,8 @@ /* * Check basic permissions. */ - if (!prochasprocperm(targpp, reqpp, reqpcredp)) { + if (!prochasprocperm(targpp, reqpp, reqpcredp, + PROCESS__SETSCHED)) { crfree(reqpcredp); return (EPERM); } diff --git a/usr/src/uts/common/disp/priocntl.c b/usr/src/uts/common/disp/priocntl.c --- a/usr/src/uts/common/disp/priocntl.c +++ b/usr/src/uts/common/disp/priocntl.c @@ -52,6 +52,7 @@ #include #include #include +#include #include /* @@ -973,7 +974,7 @@ * Check permissions before changing the nice value. */ if (pcnice->pc_op == PC_SETNICE) { - if (!prochasprocperm(pp, curproc, CRED())) { + if (!prochasprocperm(pp, curproc, CRED(), PROCESS__SETSCHED)) { mutex_exit(&pp->p_lock); return (EPERM); } @@ -1143,7 +1144,7 @@ * Check permissions before changing the prio value. */ if (pcprio->pc_op == PC_SETPRIO) { - if (!prochasprocperm(pp, curproc, CRED())) { + if (!prochasprocperm(pp, curproc, CRED(), PROCESS__SETSCHED)) { mutex_exit(&pp->p_lock); return (EPERM); } diff --git a/usr/src/uts/common/fmac/fmac.c b/usr/src/uts/common/fmac/fmac.c --- a/usr/src/uts/common/fmac/fmac.c +++ b/usr/src/uts/common/fmac/fmac.c @@ -606,3 +606,31 @@ return (avc_has_perm(crgetsecid((cred_t *)scr), crgetsecid(tcr), SECCLASS_PROCESS, PROCESS__PTRACE)); } + +access_vector_t +fmac_sigtoav(int sig) +{ + switch (sig) { + case SIGCHLD: + return (PROCESS__SIGCHLD); + case SIGKILL: + return (PROCESS__SIGKILL); + case SIGSTOP: + return (PROCESS__SIGSTOP); + } + return (PROCESS__SIGNAL); +} + +int +fmac_hasprocperm(const cred_t *tcrp, const cred_t *scrp, access_vector_t perms) +{ + security_id_t tsecid; + security_id_t ssecid; + + if (!fmac_enabled) + return (0); + + tsecid = crgetsecid((cred_t *)tcrp); + ssecid = crgetsecid((cred_t *)scrp); + return (avc_has_perm(ssecid, tsecid, SECCLASS_PROCESS, perms)); +} diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c --- a/usr/src/uts/common/os/cpu.c +++ b/usr/src/uts/common/os/cpu.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -2503,7 +2504,8 @@ * Binding will get EPERM if the thread is of system class * or hasprocperm() fails. */ - if (tp->t_cid == 0 || !hasprocperm(tp->t_cred, CRED())) { + if (tp->t_cid == 0 || !hasprocperm(tp->t_cred, CRED(), + PROCESS__SETSCHED)) { *error = EPERM; thread_unlock(tp); return (0); diff --git a/usr/src/uts/common/os/cred.c b/usr/src/uts/common/os/cred.c --- a/usr/src/uts/common/os/cred.c +++ b/usr/src/uts/common/os/cred.c @@ -65,6 +65,7 @@ #include #include #include +#include /* Ephemeral IDs Zones specific data */ @@ -553,13 +554,15 @@ * (4) otherwise, the check fails */ int -hasprocperm(const cred_t *tcrp, const cred_t *scrp) +hasprocperm(const cred_t *tcrp, const cred_t *scrp, access_vector_t perms) { if (scrp == tcrp) return (1); if (scrp->cr_zone != tcrp->cr_zone && (scrp->cr_zone != global_zone || secpolicy_proc_zone(scrp) != 0)) + return (0); + if (fmac_hasprocperm(tcrp, scrp, perms)) return (0); if (scrp->cr_uid == tcrp->cr_ruid || scrp->cr_ruid == tcrp->cr_ruid || @@ -578,7 +581,8 @@ * be held. */ int -prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp) +prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp, + access_vector_t perms) { int rets; cred_t *tcrp; @@ -594,7 +598,7 @@ mutex_enter(&tp->p_crlock); crhold(tcrp = tp->p_cred); mutex_exit(&tp->p_crlock); - rets = hasprocperm(tcrp, scrp); + rets = hasprocperm(tcrp, scrp, perms); crfree(tcrp); return (rets); diff --git a/usr/src/uts/common/os/klpd.c b/usr/src/uts/common/os/klpd.c --- a/usr/src/uts/common/os/klpd.c +++ b/usr/src/uts/common/os/klpd.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -548,7 +549,8 @@ cred_t *pcr; mutex_enter(&pidlock); p = prfind(pid); - if (p == NULL || !prochasprocperm(p, curproc, CRED())) { + if (p == NULL || !prochasprocperm(p, curproc, CRED(), + PROCESS__PTRACE)) { mutex_exit(&pidlock); klpd_rele(kpd); return (set_errno(p == NULL ? ESRCH : EPERM)); diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -1833,7 +1834,8 @@ secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) { if (tp == sp || - !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { + !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && + prochasprocperm(tp, sp, cr, PROCESS__INFO)) { return (0); } else { return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); diff --git a/usr/src/uts/common/os/pool_pset.c b/usr/src/uts/common/os/pool_pset.c --- a/usr/src/uts/common/os/pool_pset.c +++ b/usr/src/uts/common/os/pool_pset.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -645,7 +646,7 @@ /* * Check our basic permissions to control this process. */ - if (!prochasprocperm(p, curproc, pcred)) { + if (!prochasprocperm(p, curproc, pcred, PROCESS__SETSCHED)) { mutex_exit(&p->p_lock); weakbinding_start(); mutex_exit(&cpu_lock); diff --git a/usr/src/uts/common/os/sig.c b/usr/src/uts/common/os/sig.c --- a/usr/src/uts/common/os/sig.c +++ b/usr/src/uts/common/os/sig.c @@ -59,6 +59,8 @@ #include #include #include +#include +#include #include #include @@ -1839,7 +1841,7 @@ if (pv->checkperm == 0 || (pv->sig == SIGCONT && p->p_sessp == myprocp->p_sessp) || - prochasprocperm(p, myprocp, cr)) { + prochasprocperm(p, myprocp, cr, fmac_sigtoav(pv->sig))) { pv->perm++; if (pv->sig) { /* Make sure we should be setting si_pid and friends */ diff --git a/usr/src/uts/common/sys/cred.h b/usr/src/uts/common/sys/cred.h --- a/usr/src/uts/common/sys/cred.h +++ b/usr/src/uts/common/sys/cred.h @@ -82,8 +82,9 @@ extern void crset(struct proc *, cred_t *); extern int groupmember(gid_t, const cred_t *); extern int supgroupmember(gid_t, const cred_t *); -extern int hasprocperm(const cred_t *, const cred_t *); -extern int prochasprocperm(struct proc *, struct proc *, const cred_t *); +extern int hasprocperm(const cred_t *, const cred_t *, access_vector_t perms); +extern int prochasprocperm(struct proc *, struct proc *, const cred_t *, + access_vector_t perms); extern int crcmp(const cred_t *, const cred_t *); extern cred_t *zone_kcred(void); diff --git a/usr/src/uts/common/sys/fmac/fmac.h b/usr/src/uts/common/sys/fmac/fmac.h --- a/usr/src/uts/common/sys/fmac/fmac.h +++ b/usr/src/uts/common/sys/fmac/fmac.h @@ -101,6 +101,9 @@ boolean_t *execsetid, security_id_t *prev_secidp, security_id_t *secidp); int fmac_vnode_access(vnode_t *, int, int, cred_t *, boolean_t); int fmac_priv_proc_cred_perm(const cred_t *scr, cred_t *tcr, int mode); +access_vector_t fmac_sigtoav(int sig); +int fmac_hasprocperm(const cred_t *tcrp, const cred_t *scrp, + access_vector_t perms); #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/syscall/corectl.c b/usr/src/uts/common/syscall/corectl.c --- a/usr/src/uts/common/syscall/corectl.c +++ b/usr/src/uts/common/syscall/corectl.c @@ -35,6 +35,7 @@ #include #include #include +#include #include /* @@ -285,7 +286,8 @@ mutex_enter(&p->p_lock); mutex_exit(&pidlock); mutex_enter(&p->p_crlock); - if (!hasprocperm(p->p_cred, CRED())) + if (!hasprocperm(p->p_cred, CRED(), + PROCESS__GETCORE)) error = EPERM; else if (p->p_corefile != NULL) rp = corectl_path_value(p->p_corefile); @@ -396,7 +398,7 @@ mutex_enter(&p->p_lock); mutex_exit(&pidlock); mutex_enter(&p->p_crlock); - if (!hasprocperm(p->p_cred, CRED())) + if (!hasprocperm(p->p_cred, CRED(), PROCESS__GETCORE)) error = EPERM; else if (p->p_content == NULL) content = CC_CONTENT_NONE; @@ -434,7 +436,8 @@ mutex_enter(&p->p_crlock); - if (!(p->p_flag & SSYS) && hasprocperm(p->p_cred, CRED())) { + if (!(p->p_flag & SSYS) && hasprocperm(p->p_cred, CRED(), + PROCESS__SETCORE)) { mutex_exit(&p->p_crlock); counterp->cc_count++; if (counterp->cc_path != NULL) { diff --git a/usr/src/uts/common/syscall/lgrpsys.c b/usr/src/uts/common/syscall/lgrpsys.c --- a/usr/src/uts/common/syscall/lgrpsys.c +++ b/usr/src/uts/common/syscall/lgrpsys.c @@ -38,6 +38,7 @@ #include #include #include +#include #include /* for prom_printf() */ #include @@ -343,7 +344,8 @@ * Check to see whether caller has permission to set * affinity for LWP */ - if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) { + if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED(), + PROCESS__SETSCHED)) { thread_unlock(t); return (set_errno(EPERM)); } @@ -585,7 +587,8 @@ * Check to see whether caller has permission to set affinity for * thread */ - if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) { + if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED(), + PROCESS__SETSCHED)) { thread_unlock(t); return (set_errno(EPERM)); } @@ -956,7 +959,8 @@ * Check to see whether caller has permission to set affinity for * thread */ - if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) { + if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED(), + PROCESS__SETSCHED)) { thread_unlock(t); return (set_errno(EPERM)); } diff --git a/usr/src/uts/common/syscall/pset.c b/usr/src/uts/common/syscall/pset.c --- a/usr/src/uts/common/syscall/pset.c +++ b/usr/src/uts/common/syscall/pset.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -273,7 +274,7 @@ * Must have the same UID as the target process or * have PRIV_PROC_OWNER privilege. */ - if (!hasprocperm(tp->t_cred, CRED())) + if (!hasprocperm(tp->t_cred, CRED(), PROCESS__SETSCHED)) return (EPERM); /* * Unbinding of an unbound thread should always succeed. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 19 08:03:22 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 19 Sep 2008 11:03:22 -0400 Subject: [fmac-discuss] [PATCH] Policy changes Message-ID: <1221836602.25857.36.camel@moss-spartans.epoch.ncsc.mil> Various policy cleanups and changes to enable booting and logging into the system in enforcing mode (e.g. using -p enforcing on the kernel command line). In order to actually use, apply the patch, update your policy and file_contexts, relabel your filesystems, and then reboot. Note also that there is a dependency on the pam unix_cred changes for setting the user session security context. diff --git a/usr/src/cmd/fmac/policy/Makefile b/usr/src/cmd/fmac/policy/Makefile --- a/usr/src/cmd/fmac/policy/Makefile +++ b/usr/src/cmd/fmac/policy/Makefile @@ -120,13 +120,15 @@ types/procfs.te \ types/security.te +ALL_TE = macros.te attrib.te $(TYPES) domains/every.te $(SYSTEM_DOMAINS) $(PROGRAM_DOMAINS) $(USER_DOMAINS) $(ADMIN_DOMAINS) assert.te + FLASK_FILES = $(COMMONBASE)/fmac/policy/flask/security_classes \ $(COMMONBASE)/fmac/policy/flask/initial_sids \ $(COMMONBASE)/fmac/policy/flask/access_vectors USERS_FILE = users$(MLS_SUFFIX) -POLICY_FILES = initial_sid_contexts$(MLS_SUFFIX) \ +CONTEXT_FILES = initial_sid_contexts$(MLS_SUFFIX) \ fs_use$(MLS_SUFFIX) \ net_contexts$(MLS_SUFFIX) @@ -138,24 +140,19 @@ POLICYFILES += $(MLS_FILE) -POLICYFILES += all.te rbac +POLICYFILES += $(ALL_TE) rbac POLICYFILES += $(USERS_FILE) POLICYFILES += constraints -POLICYFILES += $(POLICY_FILES) - -CLOBBERFILES += all.te all_types.te all_domains.te system_domains.te \ - program_domains.te user_domains.te admin_domains.te \ - file_contexts.mls fs_use.mls initial_sid_contexts.mls \ - net_contexts.mls fs_contexts.mls users.mls +POLICYFILES += $(CONTEXT_FILES) .KEEP_STATE: -all: policy +all: ss_policy -policy: policy.conf +ss_policy: policy.conf $(CHECKPOLICY) -o $@ policy.conf $(CHECKPOLICY) -b $@ @@ -177,9 +174,8 @@ users.mls: users $(SED) 's/;/ ranges u;/' $^ > $@ -install: policy file_contexts +install: ss_policy file_contexts install -s -m 744 -d $(ROOT)/etc/security/fmac - cp policy ss_policy install -s -m 644 -f $(ROOT)/etc/security/fmac ss_policy install -s -m 644 -f $(ROOT)/etc/security/fmac file_contexts @@ -190,28 +186,7 @@ $(SETFILES) -v file_contexts `mount -p | awk '/zfs/{print $$3}'` $(TOUCH) relabel -all.te: macros.te attrib.te all_types.te all_domains.te assert.te - $(CAT) $^ > $@ - -all_types.te: $(TYPES) - $(CAT) $^ > $@ - -all_domains.te: domains/every.te system_domains.te program_domains.te user_domains.te admin_domains.te - $(CAT) $^ > $@ - -system_domains.te: $(SYSTEM_DOMAINS) - $(CAT) $^ > $@ - -program_domains.te: $(PROGRAM_DOMAINS) - $(CAT) $^ > $@ - -user_domains.te: $(USER_DOMAINS) - $(CAT) $^ > $@ - -admin_domains.te: $(ADMIN_DOMAINS) - $(CAT) $^ > $@ - clean: - $(RM) -f policy ss_policy policy.conf + $(RM) -f ss_policy policy.conf include ../../Makefile.targ diff --git a/usr/src/cmd/fmac/policy/assert.te b/usr/src/cmd/fmac/policy/assert.te --- a/usr/src/cmd/fmac/policy/assert.te +++ b/usr/src/cmd/fmac/policy/assert.te @@ -87,11 +87,6 @@ neverallow ~{ admin fsadm_t } fixed_disk_device_t:devfile_class_set { read write append }; # -# Verify that only the X server and klogd have access to memory devices. -# -neverallow ~privmem memory_device_t:devfile_class_set { read write append }; - -# # Verify that only the administrator domain and # cardmgr can create, rename or unlink device special files. # @@ -132,8 +127,8 @@ neverallow $1_t ~{ $1_exec_t ld_so_t }:file execute_no_trans;'', `assert_execute($1) assert_execute(shift($@))')') -assert_execute(getty, klogd, atd, inetd, tcpd, rlogind, - ypbind, portmap, syslogd, rpcd, gpm, xfs, fsadm) +assert_execute(getty, klogd, atd, tcpd, rlogind, + ypbind, portmap, rpcd, gpm, xfs, fsadm) neverallow { local_login_t remote_login_t } ~login_exec_t:file entrypoint; neverallow { local_login_t remote_login_t } ~ld_so_t:file execute_no_trans; diff --git a/usr/src/cmd/fmac/policy/domains/every.te b/usr/src/cmd/fmac/policy/domains/every.te --- a/usr/src/cmd/fmac/policy/domains/every.te +++ b/usr/src/cmd/fmac/policy/domains/every.te @@ -43,8 +43,13 @@ uses_shlib(domain) # Read/search default file type. -allow domain file_t:dir r_dir_perms; -allow domain file_t:file r_file_perms; +allow domain default_t:dir r_dir_perms; +allow domain default_t:file r_file_perms; + +# Create/access files that do not yet support labeling. +# This shows up for e.g. tmpfs mounts on /tmp, /var/run, ... +allow domain file_t:dir create_dir_perms; +allow domain file_t:file create_file_perms; # Get attributes of file systems. allow domain fs_type:filesystem getattr; diff --git a/usr/src/cmd/fmac/policy/domains/program/passwd.te b/usr/src/cmd/fmac/policy/domains/program/passwd.te --- a/usr/src/cmd/fmac/policy/domains/program/passwd.te +++ b/usr/src/cmd/fmac/policy/domains/program/passwd.te @@ -51,3 +51,7 @@ # Update /etc/shadow. allow passwd_t shadow_t:file create_file_perms; file_type_auto_trans(passwd_t, etc_t, shadow_t) + +# Update lastlog. +allow passwd_t var_log_t:dir rw_dir_perms; +allow passwd_t var_log_t:file create_file_perms; diff --git a/usr/src/cmd/fmac/policy/domains/program/su.te b/usr/src/cmd/fmac/policy/domains/program/su.te --- a/usr/src/cmd/fmac/policy/domains/program/su.te +++ b/usr/src/cmd/fmac/policy/domains/program/su.te @@ -45,6 +45,13 @@ # Revert to the user domain when a shell is executed. domain_auto_trans($1_su_t, shell_exec_t, $1_t) + +# No need to set linker security flag on the su -> user shell transition. +allow $1_su_t $1_t:process execsetid; + +# Create/update /var/adm/sulog. +allow $1_su_t var_log_t:dir rw_dir_perms; +allow $1_su_t var_log_t:file create_file_perms; # Execute xauth. can_exec($1_su_t, bin_t) diff --git a/usr/src/cmd/fmac/policy/domains/program/utempter.te b/usr/src/cmd/fmac/policy/domains/program/utempter.te --- a/usr/src/cmd/fmac/policy/domains/program/utempter.te +++ b/usr/src/cmd/fmac/policy/domains/program/utempter.te @@ -35,11 +35,9 @@ type utempter_t, domain; type utempter_exec_t, file_type, sysadmfile, exec_type; -# Use capabilities. -allow utempter_t utempter_t:capability { setgid }; - -# Update /var/run/utmp and /var/log/wtmp. -allow utempter_t initrc_var_run_t:file rw_file_perms; +# Update /var/adm/utmp and /var/adm/wtmp. +allow utempter_t var_log_t:dir rw_dir_perms; +allow utempter_t var_log_t:file create_file_perms; allow utempter_t wtmp_t:file rw_file_perms; # Allow ioctl and getattr /dev/ptmx. diff --git a/usr/src/cmd/fmac/policy/domains/system/crond.te b/usr/src/cmd/fmac/policy/domains/system/crond.te --- a/usr/src/cmd/fmac/policy/domains/system/crond.te +++ b/usr/src/cmd/fmac/policy/domains/system/crond.te @@ -30,7 +30,7 @@ # the crond_domain macro. # -type crond_t, domain, privuser, privrole, privlog; +type crond_t, domain, privuser, privrole, privlog, privowner, privmem, admin; type crond_exec_t, file_type, sysadmfile, exec_type; type cron_context_t, file_type, sysadmfile; @@ -41,6 +41,9 @@ file_type_auto_trans(crond_t, var_run_t, crond_var_run_t) type cron_log_t, file_type, sysadmfile; file_type_auto_trans(crond_t, var_log_t, cron_log_t) + +# Make crond unconfined for now. +unconfined_domain(crond_t) # Use capabilities. allow crond_t crond_t:capability { setgid setuid net_bind_service }; diff --git a/usr/src/cmd/fmac/policy/domains/system/inetd.te b/usr/src/cmd/fmac/policy/domains/system/inetd.te --- a/usr/src/cmd/fmac/policy/domains/system/inetd.te +++ b/usr/src/cmd/fmac/policy/domains/system/inetd.te @@ -48,6 +48,10 @@ # Use capabilities. allow inetd_t inetd_t:capability { setgid net_bind_service }; +# Runs ksh during startup. +# Possibly this should transition into a different domain. +can_exec(inetd_t, shell_exec_t) + # Use the network. can_network(inetd_t) diff --git a/usr/src/cmd/fmac/policy/domains/system/init.te b/usr/src/cmd/fmac/policy/domains/system/init.te --- a/usr/src/cmd/fmac/policy/domains/system/init.te +++ b/usr/src/cmd/fmac/policy/domains/system/init.te @@ -35,7 +35,7 @@ # to communicate with init. # sulogin_exec_t is the type of sulogin. # -type init_t, domain, privlog; +type init_t, domain, privuser, privrole, privowner, privmem, admin; type init_exec_t, file_type, sysadmfile, exec_type; type initctl_t, file_type, sysadmfile; type sulogin_exec_t, file_type, sysadmfile; @@ -76,3 +76,6 @@ # Read and write ttys. allow init_t tty_device_t:chr_file rw_file_perms; + +# Make init_t unconfined for now. +unconfined_domain(init_t) diff --git a/usr/src/cmd/fmac/policy/domains/system/kernel.te b/usr/src/cmd/fmac/policy/domains/system/kernel.te --- a/usr/src/cmd/fmac/policy/domains/system/kernel.te +++ b/usr/src/cmd/fmac/policy/domains/system/kernel.te @@ -34,18 +34,12 @@ # threads started by it. It is also the target type # when checking permissions in the system class. # -type kernel_t, domain; - -# Use capabilities. -allow kernel_t self:capability setuid; +type kernel_t, domain, privuser, privrole, privowner, privmem, admin; # Run init in the init_t domain. domain_auto_trans(kernel_t, init_exec_t, init_t) -# Mount and unmount file systems. -allow kernel_t fs_type:filesystem mount_fs_perms; +# Make kernel_t unconfined. +unconfined_domain(kernel_t) -# Search the persistent label mapping. -allow kernel_t file_labels_t:dir search; - diff --git a/usr/src/cmd/fmac/policy/domains/system/sshd.te b/usr/src/cmd/fmac/policy/domains/system/sshd.te --- a/usr/src/cmd/fmac/policy/domains/system/sshd.te +++ b/usr/src/cmd/fmac/policy/domains/system/sshd.te @@ -46,9 +46,6 @@ # Can create pty's can_create_pty(sshd) -# Fetch shell attributes -allow sshd_t shell_exec_t:file { getattr }; - # Use capabilities. allow sshd_t self:capability { chown fowner fsetid sys_tty_config dac_override net_bind_service }; @@ -59,20 +56,28 @@ # Access key files allow sshd_t sshd_key_t:file rw_file_perms; -# Append to /var/log/lastlog -allow sshd_t var_log_t:file append; +# kerberos library always tries to open /etc/krb5/krb5.conf with write access. +dontaudit sshd_t etc_t:file write; -# Append to utmp -allow sshd_t initrc_var_run_t:file append; +# Create/update /var/adm/lastlog and utmpx. +allow sshd_t var_log_t:dir rw_dir_perms; +allow sshd_t var_log_t:file create_file_perms; # Append to wtmp allow sshd_t wtmp_t:file append; -# Run shells in user_t by default -domain_auto_trans(sshd_t, shell_exec_t, user_t) +# Runs /sbin/sh. +can_exec(sshd_t, shell_exec_t) -# Allow sysadm_t shells on explicit request +# Runs /usr/bin/locale. +can_exec(sshd_t, bin_t) + +# Transition to user domains upon shell invocation. +domain_trans(sshd_t, shell_exec_t, user_t) domain_trans(sshd_t, shell_exec_t, sysadm_t) + +# No need for linker security flag setting on sshd -> user shell transition. +allow sshd_t { user_t sysadm_t }:process execsetid; # Read /etc/shadow allow sshd_t shadow_t:file r_file_perms; diff --git a/usr/src/cmd/fmac/policy/domains/system/syslogd.te b/usr/src/cmd/fmac/policy/domains/system/syslogd.te --- a/usr/src/cmd/fmac/policy/domains/system/syslogd.te +++ b/usr/src/cmd/fmac/policy/domains/system/syslogd.te @@ -49,7 +49,8 @@ allow syslogd_t init_t:fd inherit_fd_perms; # Modify log files. -allow syslogd_t var_log_t:file rw_file_perms; +allow syslogd_t var_log_t:dir rw_dir_perms; +allow syslogd_t var_log_t:file create_file_perms; # Create and bind to /dev/log. file_type_auto_trans(syslogd_t, device_t, devlog_t) @@ -60,3 +61,7 @@ allow privlog devlog_t:sock_file rw_file_perms; can_unix_send(privlog,syslogd_t) can_unix_connect(privlog,syslogd_t) + +# Runs m4 during startup. +can_exec(syslogd_t, bin_t) + diff --git a/usr/src/cmd/fmac/policy/domains/user/user.te b/usr/src/cmd/fmac/policy/domains/user/user.te --- a/usr/src/cmd/fmac/policy/domains/user/user.te +++ b/usr/src/cmd/fmac/policy/domains/user/user.te @@ -189,19 +189,6 @@ auditdeny $1_t domain:dir ~r_dir_perms; auditdeny $1_t domain:notdevfile_class_set ~r_file_perms; -# Some shells ask for w access to utmp, but will operate -# correctly without it. Do not audit write denials to utmp. -auditdeny $1_t initrc_var_run_t:file ~write; - -# -# connect_secure and sendmsg_secure calls with a -# peer or destination socket SID can be enforced -# when using the loopback interface. Enforcement -# for real network interfaces will be possible when -# a packet labeling mechanism is integrated. -# -allow $1_t node_lo_t:node enforce_dest; - ') @@ -213,4 +200,10 @@ # type user_t, domain, userdomain; +# Entered via /usr/dt/config/Xsession.jds for graphical login. +allow user_t bin_t:file entrypoint; + +# /var/tmp/orbit-... access until it gets labeled properly +allow user_t tmp_t:file r_file_perms; + user_domain(user) diff --git a/usr/src/cmd/fmac/policy/file_contexts b/usr/src/cmd/fmac/policy/file_contexts --- a/usr/src/cmd/fmac/policy/file_contexts +++ b/usr/src/cmd/fmac/policy/file_contexts @@ -62,7 +62,7 @@ # # The security context for all files not otherwise specified. # -/.* system_u:object_r:file_t +/.* system_u:object_r:default_t # # The root directory. @@ -78,6 +78,7 @@ # Other user home directories. # /home(/.*)? system_u:object_r:user_home_t +/export/home(/.*)? system_u:object_r:user_home_t # # /boot @@ -191,6 +192,7 @@ /usr/lib/inet/inetd system_u:object_r:inetd_exec_t /usr/lib/inet/in\..*d system_u:object_r:inetd_child_exec_t /usr/lib/sendmail system_u:object_r:sendmail_exec_t +/usr/lib/utmp_update system_u:object_r:utempter_exec_t # # /usr/sbin @@ -218,6 +220,28 @@ /usr/sadm/lib(/.*)? system_u:object_r:lib_t # +# /usr/sfw +# +/usr/sfw/bin(/.*)? system_u:object_r:bin_t +/usr/sfw/libexec(/.*)? system_u:object_r:bin_t +/usr/sfw/lib(/.*)? system_u:object_r:lib_t + +# +# /usr/dt +# +/usr/dt/bin(/.*)? system_u:object_r:bin_t +/usr/dt/config(/.*)? system_u:object_r:bin_t +/usr/dt/lib(/.*)? system_u:object_r:lib_t + +/usr/openwin/bin(/.*)? system_u:object_r:bin_t +/usr/openwin/lib(/.*)? system_u:object_r:lib_t +/usr/openwin/sfw(/.*)? system_u:object_r:lib_t +/usr/openwin/server(/.*)? system_u:object_r:lib_t + +/usr/snadm/bin(/.*)? system_u:object_r:bin_t +/usr/snadm/lib(/.*)? system_u:object_r:lib_t + +# # /usr/X11 # /usr/X11/bin(/.*)? system_u:object_r:bin_t @@ -232,6 +256,9 @@ /var/yp(/.*)? system_u:object_r:var_yp_t /var/lib(/.*)? system_u:object_r:var_lib_t /var/tmp(/.*)? system_u:object_r:tmp_t +/var/dt/tmp(/.*)? system_u:object_r:tmp_t +/var/dt/appconfig/appmanager(/.*)? system_u:object_r:tmp_t +/var/cron(/.*)? system_u:object_r:cron_log_t # # /var/run @@ -247,11 +274,14 @@ /var/spool/lp(/.*)? system_u:object_r:lpd_spool_t /var/mail(/.*)? system_u:object_r:mail_spool_t /var/spool/mqueue(/.*)? system_u:object_r:mqueue_spool_t +/var/spool/clientmqueue(/.*)? system_u:object_r:mqueue_spool_t # # /var/log # /var/log(/.*)? system_u:object_r:var_log_t +/var/adm(/.*)? system_u:object_r:var_log_t +/var/adm/wtmpx system_u:object_r:wtmp_t # Wrapper for architecture-specific executables. /usr/lib/isaexec system_u:object_r:bin_t diff --git a/usr/src/cmd/fmac/policy/macros.te b/usr/src/cmd/fmac/policy/macros.te --- a/usr/src/cmd/fmac/policy/macros.te +++ b/usr/src/cmd/fmac/policy/macros.te @@ -113,18 +113,18 @@ # # Permissions for reading and writing directories and their attributes. # -define(`rw_dir_perms', `{ read getattr lock setattr search add_name remove_name }') +define(`rw_dir_perms', `{ read write getattr lock setattr search add_name remove_name }') # # Permissions for reading and adding names to directories. # -define(`ra_dir_perms', `{ read getattr lock setattr search add_name }') +define(`ra_dir_perms', `{ read write getattr lock setattr search add_name }') # # Permissions for creating and using directories. # -define(`create_dir_perms', `{ create read getattr setattr link unlink rename search add_name remove_name reparent rmdir }') +define(`create_dir_perms', `{ create read write getattr setattr link unlink rename search add_name remove_name reparent rmdir }') # # Permissions to inherit and use file descriptions. @@ -227,6 +227,11 @@ # Allow the new domain to be entered by the program. # allow $3 $2:file entrypoint; + +# +# Silence execsetid avc messages. +# +dontaudit $1 $3:process execsetid; ') ################################# @@ -463,5 +468,6 @@ define(`unconfined_domain', ` allow $1 domain:process *; allow $1 file_type:dir_file_class_set *; +allow $1 unlabeled_t:dir_file_class_set *; allow $1 security_t:security *; ') diff --git a/usr/src/cmd/fmac/policy/types/file.te b/usr/src/cmd/fmac/policy/types/file.te --- a/usr/src/cmd/fmac/policy/types/file.te +++ b/usr/src/cmd/fmac/policy/types/file.te @@ -56,6 +56,11 @@ # or fs_contexts.mls file. # type file_t, file_type, root_dir_type, sysadmfile; + +# +# Default type for unspecified files in file_contexts. +# +type default_t, file_type, root_dir_type, sysadmfile; # # root_t is the type for the root directory. -- Stephen Smalley National Security Agency From sds at tycho.nsa.gov Fri Sep 19 08:19:48 2008 From: sds at tycho.nsa.gov (Stephen Smalley) Date: Fri, 19 Sep 2008 11:19:48 -0400 Subject: [fmac-discuss] Running FMAC Message-ID: <1221837588.25857.57.camel@moss-spartans.epoch.ncsc.mil> We likely should add basic instructions to the project pages about how to get FMAC up and running and how to exercise it when we make the next release. In essence, it boils down to: - build and install it (boilerplate) - noting that you need ZFS root, - boot it once in permissive mode (the default), - label all ZFS filesystems, (setfiles /etc/security/fmac/file_contexts / /export/home ...) - boot it again, optionally in enforcing mode via -p enforcing, - login, - check your context via pcon and make sure it is user_u:user_r:user_t, - make