Merge branch 'master' into next
James Morris [Mon, 22 Sep 2008 00:41:56 +0000 (17:41 -0700)]
Conflicts:

MAINTAINERS

Thanks for breaking my tree :-)

Signed-off-by: James Morris <jmorris@namei.org>

35 files changed:
Documentation/DocBook/kernel-api.tmpl
Documentation/SELinux.txt [new file with mode: 0644]
MAINTAINERS
drivers/char/tpm/Kconfig
include/linux/security.h
scripts/Makefile
scripts/selinux/Makefile [new file with mode: 0644]
scripts/selinux/README [new file with mode: 0644]
scripts/selinux/install_policy.sh [new file with mode: 0644]
scripts/selinux/mdp/.gitignore [new file with mode: 0644]
scripts/selinux/mdp/Makefile [new file with mode: 0644]
scripts/selinux/mdp/dbus_contexts [new file with mode: 0644]
scripts/selinux/mdp/mdp.c [new file with mode: 0644]
security/Kconfig
security/Makefile
security/inode.c
security/security.c
security/selinux/Kconfig
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h
security/selinux/include/security.h
security/selinux/ss/avtab.c
security/selinux/ss/conditional.c
security/selinux/ss/conditional.h
security/selinux/ss/ebitmap.c
security/selinux/ss/hashtab.c
security/selinux/ss/mls.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/selinux/ss/sidtab.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smackfs.c

index b7b1482..cd0e6d5 100644 (file)
@@ -283,6 +283,7 @@ X!Earch/x86/kernel/mca_32.c
   <chapter id="security">
      <title>Security Framework</title>
 !Isecurity/security.c
+!Esecurity/inode.c
   </chapter>
 
   <chapter id="audit">
diff --git a/Documentation/SELinux.txt b/Documentation/SELinux.txt
new file mode 100644 (file)
index 0000000..07eae00
--- /dev/null
@@ -0,0 +1,27 @@
+If you want to use SELinux, chances are you will want
+to use the distro-provided policies, or install the
+latest reference policy release from
+       http://oss.tresys.com/projects/refpolicy
+
+However, if you want to install a dummy policy for
+testing, you can do using 'mdp' provided under
+scripts/selinux.  Note that this requires the selinux
+userspace to be installed - in particular you will
+need checkpolicy to compile a kernel, and setfiles and
+fixfiles to label the filesystem.
+
+       1. Compile the kernel with selinux enabled.
+       2. Type 'make' to compile mdp.
+       3. Make sure that you are not running with
+          SELinux enabled and a real policy.  If
+          you are, reboot with selinux disabled
+          before continuing.
+       4. Run install_policy.sh:
+               cd scripts/selinux
+               sh install_policy.sh
+
+Step 4 will create a new dummy policy valid for your
+kernel, with a single selinux user, role, and type.
+It will compile the policy, will set your SELINUXTYPE to
+dummy in /etc/selinux/config, install the compiled policy
+as 'dummy', and relabel your filesystem.
index cad81a2..926485c 100644 (file)
@@ -3650,8 +3650,9 @@ M:        jmorris@namei.org
 P:     Eric Paris
 M:     eparis@parisplace.org
 L:     linux-kernel@vger.kernel.org (kernel issues)
-L:     selinux@tycho.nsa.gov (subscribers-only, general discussion)
-W:     http://www.nsa.gov/selinux
+L:     selinux@tycho.nsa.gov (subscribers-only, general discussion)
+W:     http://selinuxproject.org
+T:     git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
 S:     Supported
 
 SENSABLE PHANTOM
index 3738cfa..f5fc64f 100644 (file)
@@ -6,6 +6,7 @@ menuconfig TCG_TPM
        tristate "TPM Hardware Support"
        depends on HAS_IOMEM
        depends on EXPERIMENTAL
+       select SECURITYFS
        ---help---
          If you have a TPM security chip in your system, which
          implements the Trusted Computing Group's specification,
index 80c4d00..f5c4a51 100644 (file)
@@ -1560,11 +1560,6 @@ struct security_operations {
 extern int security_init(void);
 extern int security_module_enable(struct security_operations *ops);
 extern int register_security(struct security_operations *ops);
-extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
-                                            struct dentry *parent, void *data,
-                                            const struct file_operations *fops);
-extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent);
-extern void securityfs_remove(struct dentry *dentry);
 
 /* Security operations */
 int security_ptrace_may_access(struct task_struct *child, unsigned int mode);
@@ -2424,25 +2419,6 @@ static inline int security_netlink_recv(struct sk_buff *skb, int cap)
        return cap_netlink_recv(skb, cap);
 }
 
-static inline struct dentry *securityfs_create_dir(const char *name,
-                                       struct dentry *parent)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline struct dentry *securityfs_create_file(const char *name,
-                                               mode_t mode,
-                                               struct dentry *parent,
-                                               void *data,
-                                               const struct file_operations *fops)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline void securityfs_remove(struct dentry *dentry)
-{
-}
-
 static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
        return -EOPNOTSUPP;
@@ -2806,5 +2782,35 @@ static inline void security_audit_rule_free(void *lsmrule)
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_AUDIT */
 
+#ifdef CONFIG_SECURITYFS
+
+extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
+                                            struct dentry *parent, void *data,
+                                            const struct file_operations *fops);
+extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent);
+extern void securityfs_remove(struct dentry *dentry);
+
+#else /* CONFIG_SECURITYFS */
+
+static inline struct dentry *securityfs_create_dir(const char *name,
+                                                  struct dentry *parent)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *securityfs_create_file(const char *name,
+                                                   mode_t mode,
+                                                   struct dentry *parent,
+                                                   void *data,
+                                                   const struct file_operations *fops)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline void securityfs_remove(struct dentry *dentry)
+{}
+
+#endif
+
 #endif /* ! __LINUX_SECURITY_H */
 
index 1c73c5a..aafdf06 100644 (file)
@@ -20,6 +20,7 @@ hostprogs-y += unifdef
 
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
+subdir-$(CONFIG_SECURITY_SELINUX) += selinux
 
 # Let clean descend into subdirs
-subdir-        += basic kconfig package
+subdir-        += basic kconfig package selinux
diff --git a/scripts/selinux/Makefile b/scripts/selinux/Makefile
new file mode 100644 (file)
index 0000000..ca4b1ec
--- /dev/null
@@ -0,0 +1,2 @@
+subdir-y := mdp
+subdir-        += mdp
diff --git a/scripts/selinux/README b/scripts/selinux/README
new file mode 100644 (file)
index 0000000..a936315
--- /dev/null
@@ -0,0 +1,2 @@
+Please see Documentation/SELinux.txt for information on
+installing a dummy SELinux policy.
diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
new file mode 100644 (file)
index 0000000..7b9ccf6
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+if [ `id -u` -ne 0 ]; then
+       echo "$0: must be root to install the selinux policy"
+       exit 1
+fi
+SF=`which setfiles`
+if [ $? -eq 1 ]; then
+       if [ -f /sbin/setfiles ]; then
+               SF="/usr/setfiles"
+       else
+               echo "no selinux tools installed: setfiles"
+               exit 1
+       fi
+fi
+
+cd mdp
+
+CP=`which checkpolicy`
+VERS=`$CP -V | awk '{print $1}'`
+
+./mdp policy.conf file_contexts
+$CP -o policy.$VERS policy.conf
+
+mkdir -p /etc/selinux/dummy/policy
+mkdir -p /etc/selinux/dummy/contexts/files
+
+cp file_contexts /etc/selinux/dummy/contexts/files
+cp dbus_contexts /etc/selinux/dummy/contexts
+cp policy.$VERS /etc/selinux/dummy/policy
+FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts
+
+if [ ! -d /etc/selinux ]; then
+       mkdir -p /etc/selinux
+fi
+if [ ! -f /etc/selinux/config ]; then
+       cat > /etc/selinux/config << EOF
+SELINUX=enforcing
+SELINUXTYPE=dummy
+EOF
+else
+       TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}`
+       if [ "eq$TYPE" != "eqdummy" ]; then
+               selinuxenabled
+               if [ $? -eq 0 ]; then
+                       echo "SELinux already enabled with a non-dummy policy."
+                       echo "Exiting.  Please install policy by hand if that"
+                       echo "is what you REALLY want."
+                       exit 1
+               fi
+               mv /etc/selinux/config /etc/selinux/config.mdpbak
+               grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config
+               echo "SELINUXTYPE=dummy" >> /etc/selinux/config
+       fi
+fi
+
+cd /etc/selinux/dummy/contexts/files
+$SF file_contexts /
+
+mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}`
+$SF file_contexts $mounts
+
+
+dodev=`cat /proc/$$/mounts | grep "/dev "`
+if [ "eq$dodev" != "eq" ]; then
+       mount --move /dev /mnt
+       $SF file_contexts /dev
+       mount --move /mnt /dev
+fi
+
diff --git a/scripts/selinux/mdp/.gitignore b/scripts/selinux/mdp/.gitignore
new file mode 100644 (file)
index 0000000..654546d
--- /dev/null
@@ -0,0 +1,2 @@
+# Generated file
+mdp
diff --git a/scripts/selinux/mdp/Makefile b/scripts/selinux/mdp/Makefile
new file mode 100644 (file)
index 0000000..eb365b3
--- /dev/null
@@ -0,0 +1,5 @@
+hostprogs-y    := mdp
+HOST_EXTRACFLAGS += -Isecurity/selinux/include
+
+always         := $(hostprogs-y)
+clean-files    := $(hostprogs-y) policy.* file_contexts
diff --git a/scripts/selinux/mdp/dbus_contexts b/scripts/selinux/mdp/dbus_contexts
new file mode 100644 (file)
index 0000000..116e684
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <selinux>
+  </selinux>
+</busconfig>
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
new file mode 100644 (file)
index 0000000..ca757d4
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ *
+ * mdp - make dummy policy
+ *
+ * When pointed at a kernel tree, builds a dummy policy for that kernel
+ * with exactly one type with full rights to itself.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Authors: Serge E. Hallyn <serue@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "flask.h"
+
+void usage(char *name)
+{
+       printf("usage: %s [-m] policy_file context_file\n", name);
+       exit(1);
+}
+
+void find_common_name(char *cname, char *dest, int len)
+{
+       char *start, *end;
+
+       start = strchr(cname, '_')+1;
+       end = strchr(start, '_');
+       if (!start || !end || start-cname > len || end-start > len) {
+               printf("Error with commons defines\n");
+               exit(1);
+       }
+       strncpy(dest, start, end-start);
+       dest[end-start] = '\0';
+}
+
+#define S_(x) x,
+static char *classlist[] = {
+#include "class_to_string.h"
+       NULL
+};
+#undef S_
+
+#include "initial_sid_to_string.h"
+
+#define TB_(x) char *x[] = {
+#define TE_(x) NULL };
+#define S_(x) x,
+#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+
+struct common {
+       char *cname;
+       char **perms;
+};
+struct common common[] = {
+#define TB_(x) { #x, x },
+#define S_(x)
+#define TE_(x)
+#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+};
+
+#define S_(x, y, z) {x, #y},
+struct av_inherit {
+       int class;
+       char *common;
+};
+struct av_inherit av_inherit[] = {
+#include "av_inherit.h"
+};
+#undef S_
+
+#include "av_permissions.h"
+#define S_(x, y, z) {x, y, z},
+struct av_perms {
+       int class;
+       int perm_i;
+       char *perm_s;
+};
+struct av_perms av_perms[] = {
+#include "av_perm_to_string.h"
+};
+#undef S_
+
+int main(int argc, char *argv[])
+{
+       int i, j, mls = 0;
+       char **arg, *polout, *ctxout;
+       int classlist_len, initial_sid_to_string_len;
+       FILE *fout;
+
+       if (argc < 3)
+               usage(argv[0]);
+       arg = argv+1;
+       if (argc==4 && strcmp(argv[1], "-m") == 0) {
+               mls = 1;
+               arg++;
+       }
+       polout = *arg++;
+       ctxout = *arg;
+
+       fout = fopen(polout, "w");
+       if (!fout) {
+               printf("Could not open %s for writing\n", polout);
+               usage(argv[0]);
+       }
+
+       classlist_len = sizeof(classlist) / sizeof(char *);
+       /* print out the classes */
+       for (i=1; i < classlist_len; i++) {
+               if(classlist[i])
+                       fprintf(fout, "class %s\n", classlist[i]);
+               else
+                       fprintf(fout, "class user%d\n", i);
+       }
+       fprintf(fout, "\n");
+
+       initial_sid_to_string_len = sizeof(initial_sid_to_string) / sizeof (char *);
+       /* print out the sids */
+       for (i=1; i < initial_sid_to_string_len; i++)
+               fprintf(fout, "sid %s\n", initial_sid_to_string[i]);
+       fprintf(fout, "\n");
+
+       /* print out the commons */
+       for (i=0; i< sizeof(common)/sizeof(struct common); i++) {
+               char cname[101];
+               find_common_name(common[i].cname, cname, 100);
+               cname[100] = '\0';
+               fprintf(fout, "common %s\n{\n", cname);
+               for (j=0; common[i].perms[j]; j++)
+                       fprintf(fout, "\t%s\n", common[i].perms[j]);
+               fprintf(fout, "}\n\n");
+       }
+       fprintf(fout, "\n");
+
+       /* print out the class permissions */
+       for (i=1; i < classlist_len; i++) {
+               if (classlist[i]) {
+                       int firstperm = -1, numperms = 0;
+
+                       fprintf(fout, "class %s\n", classlist[i]);
+                       /* does it inherit from a common? */
+                       for (j=0; j < sizeof(av_inherit)/sizeof(struct av_inherit); j++)
+                               if (av_inherit[j].class == i)
+                                       fprintf(fout, "inherits %s\n", av_inherit[j].common);
+
+                       for (j=0; j < sizeof(av_perms)/sizeof(struct av_perms); j++) {
+                               if (av_perms[j].class == i) {
+                                       if (firstperm == -1)
+                                               firstperm = j;
+                                       numperms++;
+                               }
+                       }
+                       if (!numperms) {
+                               fprintf(fout, "\n");
+                               continue;
+                       }
+
+                       fprintf(fout, "{\n");
+                       /* print out the av_perms */
+                       for (j=0; j < numperms; j++) {
+                               fprintf(fout, "\t%s\n", av_perms[firstperm+j].perm_s);
+                       }
+                       fprintf(fout, "}\n\n");
+               }
+       }
+       fprintf(fout, "\n");
+
+       /* NOW PRINT OUT MLS STUFF */
+       if (mls) {
+               printf("MLS not yet implemented\n");
+               exit(1);
+       }
+
+       /* types, roles, and allows */
+       fprintf(fout, "type base_t;\n");
+       fprintf(fout, "role base_r types { base_t };\n");
+       for (i=1; i < classlist_len; i++) {
+               if (classlist[i])
+                       fprintf(fout, "allow base_t base_t:%s *;\n", classlist[i]);
+               else
+                       fprintf(fout, "allow base_t base_t:user%d *;\n", i);
+       }
+       fprintf(fout, "user user_u roles { base_r };\n");
+       fprintf(fout, "\n");
+
+       /* default sids */
+       for (i=1; i < initial_sid_to_string_len; i++)
+               fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
+       fprintf(fout, "\n");
+
+
+       fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
+       fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
+       fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
+       fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
+       fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
+
+       fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
+       fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
+
+       fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
+       fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
+       fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
+
+       fprintf(fout, "genfscon proc / user_u:base_r:base_t\n");
+
+       fclose(fout);
+
+       fout = fopen(ctxout, "w");
+       if (!fout) {
+               printf("Wrote policy, but cannot open %s for writing\n", ctxout);
+               usage(argv[0]);
+       }
+       fprintf(fout, "/ user_u:base_r:base_t\n");
+       fprintf(fout, "/.* user_u:base_r:base_t\n");
+       fclose(fout);
+
+       return 0;
+}
index 5592939..d9f47ce 100644 (file)
@@ -51,6 +51,14 @@ config SECURITY
 
          If you are unsure how to answer this question, answer N.
 
+config SECURITYFS
+       bool "Enable the securityfs filesystem"
+       help
+         This will build the securityfs filesystem.  It is currently used by
+         the TPM bios character driver.  It is not used by SELinux or SMACK.
+
+         If you are unsure how to answer this question, answer N.
+
 config SECURITY_NETWORK
        bool "Socket and Networking Security Hooks"
        depends on SECURITY
index f654260..c05c127 100644 (file)
@@ -10,7 +10,8 @@ subdir-$(CONFIG_SECURITY_SMACK)               += smack
 obj-y          += commoncap.o
 
 # Object file lists
-obj-$(CONFIG_SECURITY)                 += security.o capability.o inode.o
+obj-$(CONFIG_SECURITY)                 += security.o capability.o
+obj-$(CONFIG_SECURITYFS)               += inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
index acc6cf0..ca4958e 100644 (file)
@@ -190,7 +190,7 @@ static int create_by_name(const char *name, mode_t mode,
  * @name: a pointer to a string containing the name of the file to create.
  * @mode: the permission that the file should have
  * @parent: a pointer to the parent dentry for this file.  This should be a
- *          directory dentry if set.  If this paramater is NULL, then the
+ *          directory dentry if set.  If this parameter is %NULL, then the
  *          file will be created in the root of the securityfs filesystem.
  * @data: a pointer to something that the caller will want to get to later
  *        on.  The inode.i_private pointer will point to this value on
@@ -199,18 +199,18 @@ static int create_by_name(const char *name, mode_t mode,
  *        this file.
  *
  * This is the basic "create a file" function for securityfs.  It allows for a
- * wide range of flexibility in createing a file, or a directory (if you
+ * wide range of flexibility in creating a file, or a directory (if you
  * want to create a directory, the securityfs_create_dir() function is
- * recommended to be used instead.)
+ * recommended to be used instead).
  *
- * This function will return a pointer to a dentry if it succeeds.  This
+ * This function returns a pointer to a dentry if it succeeds.  This
  * pointer must be passed to the securityfs_remove() function when the file is
  * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, NULL will be returned.
+ * you are responsible here).  If an error occurs, %NULL is returned.
  *
- * If securityfs is not enabled in the kernel, the value -ENODEV will be
+ * If securityfs is not enabled in the kernel, the value %-ENODEV is
  * returned.  It is not wise to check for this value, but rather, check for
- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
 struct dentry *securityfs_create_file(const char *name, mode_t mode,
@@ -252,19 +252,19 @@ EXPORT_SYMBOL_GPL(securityfs_create_file);
  * @name: a pointer to a string containing the name of the directory to
  *        create.
  * @parent: a pointer to the parent dentry for this file.  This should be a
- *          directory dentry if set.  If this paramater is NULL, then the
+ *          directory dentry if set.  If this parameter is %NULL, then the
  *          directory will be created in the root of the securityfs filesystem.
  *
- * This function creates a directory in securityfs with the given name.
+ * This function creates a directory in securityfs with the given @name.
  *
- * This function will return a pointer to a dentry if it succeeds.  This
+ * This function returns a pointer to a dentry if it succeeds.  This
  * pointer must be passed to the securityfs_remove() function when the file is
  * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, NULL will be returned.
+ * you are responsible here).  If an error occurs, %NULL will be returned.
  *
- * If securityfs is not enabled in the kernel, the value -ENODEV will be
+ * If securityfs is not enabled in the kernel, the value %-ENODEV is
  * returned.  It is not wise to check for this value, but rather, check for
- * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
 struct dentry *securityfs_create_dir(const char *name, struct dentry *parent)
@@ -278,16 +278,15 @@ EXPORT_SYMBOL_GPL(securityfs_create_dir);
 /**
  * securityfs_remove - removes a file or directory from the securityfs filesystem
  *
- * @dentry: a pointer to a the dentry of the file or directory to be
- *          removed.
+ * @dentry: a pointer to a the dentry of the file or directory to be removed.
  *
  * This function removes a file or directory in securityfs that was previously
  * created with a call to another securityfs function (like
  * securityfs_create_file() or variants thereof.)
  *
  * This function is required to be called in order for the file to be
- * removed, no automatic cleanup of files will happen when a module is
- * removed, you are responsible here.
+ * removed. No automatic cleanup of files will happen when a module is
+ * removed; you are responsible here.
  */
 void securityfs_remove(struct dentry *dentry)
 {
index 3a4b4f5..255b085 100644 (file)
@@ -82,8 +82,8 @@ __setup("security=", choose_lsm);
  *
  * Return true if:
  *     -The passed LSM is the one chosen by user at boot time,
- *     -or user didsn't specify a specific LSM and we're the first to ask
- *      for registeration permissoin,
+ *     -or user didn't specify a specific LSM and we're the first to ask
+ *      for registration permission,
  *     -or the passed LSM is currently loaded.
  * Otherwise, return false.
  */
@@ -101,13 +101,13 @@ int __init security_module_enable(struct security_operations *ops)
  * register_security - registers a security framework with the kernel
  * @ops: a pointer to the struct security_options that is to be registered
  *
- * This function is to allow a security module to register itself with the
+ * This function allows a security module to register itself with the
  * kernel security subsystem.  Some rudimentary checking is done on the @ops
  * value passed to this function. You'll need to check first if your LSM
  * is allowed to register its @ops by calling security_module_enable(@ops).
  *
  * If there is already a security module registered with the kernel,
- * an error will be returned.  Otherwise 0 is returned on success.
+ * an error will be returned.  Otherwise %0 is returned on success.
  */
 int register_security(struct security_operations *ops)
 {
index a436d1c..26301dd 100644 (file)
@@ -6,9 +6,6 @@ config SECURITY_SELINUX
        help
          This selects NSA Security-Enhanced Linux (SELinux).
          You will also need a policy configuration and a labeled filesystem.
-         You can obtain the policy compiler (checkpolicy), the utility for
-         labeling filesystems (setfiles), and an example policy configuration
-         from <http://www.nsa.gov/selinux/>.
          If you are unsure how to answer this question, answer N.
 
 config SECURITY_SELINUX_BOOTPARAM
index 114b4b4..cb30c7e 100644 (file)
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
        const char **common_pts = NULL;
        u32 common_base = 0;
index 03fc6a8..89f446d 100644 (file)
@@ -957,7 +957,8 @@ out_err:
        return rc;
 }
 
-void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts)
+static void selinux_write_opts(struct seq_file *m,
+                              struct security_mnt_opts *opts)
 {
        int i;
        char *prefix;
@@ -3548,38 +3549,44 @@ out:
 #endif /* IPV6 */
 
 static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
-                            char **addrp, int src, u8 *proto)
+                            char **_addrp, int src, u8 *proto)
 {
-       int ret = 0;
+       char *addrp;
+       int ret;
 
        switch (ad->u.net.family) {
        case PF_INET:
                ret = selinux_parse_skb_ipv4(skb, ad, proto);
-               if (ret || !addrp)
-                       break;
-               *addrp = (char *)(src ? &ad->u.net.v4info.saddr :
-                                       &ad->u.net.v4info.daddr);
-               break;
+               if (ret)
+                       goto parse_error;
+               addrp = (char *)(src ? &ad->u.net.v4info.saddr :
+                                      &ad->u.net.v4info.daddr);
+               goto okay;
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case PF_INET6:
                ret = selinux_parse_skb_ipv6(skb, ad, proto);
-               if (ret || !addrp)
-                       break;
-               *addrp = (char *)(src ? &ad->u.net.v6info.saddr :
-                                       &ad->u.net.v6info.daddr);
-               break;
+               if (ret)
+                       goto parse_error;
+               addrp = (char *)(src ? &ad->u.net.v6info.saddr :
+                                      &ad->u.net.v6info.daddr);
+               goto okay;
 #endif /* IPV6 */
        default:
-               break;
+               addrp = NULL;
+               goto okay;
        }
 
-       if (unlikely(ret))
-               printk(KERN_WARNING
-                      "SELinux: failure in selinux_parse_skb(),"
-                      " unable to parse packet\n");
-
+parse_error:
+       printk(KERN_WARNING
+              "SELinux: failure in selinux_parse_skb(),"
+              " unable to parse packet\n");
        return ret;
+
+okay:
+       if (_addrp)
+               *_addrp = addrp;
+       return 0;
 }
 
 /**
@@ -5219,8 +5226,12 @@ static int selinux_setprocattr(struct task_struct *p,
 
                if (sid == 0)
                        return -EINVAL;
-
-               /* Only allow single threaded processes to change context */
+               /*
+                * SELinux allows to change context in the following case only.
+                *  - Single threaded processes.
+                *  - Multi threaded processes intend to change its context into
+                *    more restricted domain (defined by TYPEBOUNDS statement).
+                */
                if (atomic_read(&p->mm->mm_users) != 1) {
                        struct task_struct *g, *t;
                        struct mm_struct *mm = p->mm;
@@ -5228,11 +5239,16 @@ static int selinux_setprocattr(struct task_struct *p,
                        do_each_thread(g, t) {
                                if (t->mm == mm && t != p) {
                                        read_unlock(&tasklist_lock);
-                                       return -EPERM;
+                                       error = security_bounded_transition(tsec->sid, sid);
+                                       if (!error)
+                                               goto boundary_ok;
+
+                                       return error;
                                }
                        } while_each_thread(g, t);
                        read_unlock(&tasklist_lock);
                }
+boundary_ok:
 
                /* Check permissions for the transition. */
                error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
index 7b9769f..d12ff1a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
                     u32 events, u32 ssid, u32 tsid,
                     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
index 7c54300..7244737 100644 (file)
 #define POLICYDB_VERSION_RANGETRANS    21
 #define POLICYDB_VERSION_POLCAP                22
 #define POLICYDB_VERSION_PERMISSIVE    23
+#define POLICYDB_VERSION_BOUNDARY      24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
 #define POLICYDB_VERSION_MAX   CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
 #else
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT    0x01
@@ -62,6 +63,16 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY     0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE   0x0002
+
+/* limitation of boundary depth  */
+#define POLICYDB_BOUNDS_MAXDEPTH       4
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
                                 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
index a1be97f..1215b8e 100644 (file)
@@ -98,7 +98,7 @@ struct avtab_node *
 avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
 {
        int hvalue;
-       struct avtab_node *prev, *cur, *newnode;
+       struct avtab_node *prev, *cur;
        u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 
        if (!h || !h->htable)
@@ -122,9 +122,7 @@ avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datu
                    key->target_class < cur->key.target_class)
                        break;
        }
-       newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
-
-       return newnode;
+       return avtab_insert_node(h, hvalue, prev, cur, key, datum);
 }
 
 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
@@ -231,7 +229,7 @@ void avtab_destroy(struct avtab *h)
 
        for (i = 0; i < h->nslot; i++) {
                cur = h->htable[i];
-               while (cur != NULL) {
+               while (cur) {
                        temp = cur;
                        cur = cur->next;
                        kmem_cache_free(avtab_node_cachep, temp);
index fb4efe4..4a4e35c 100644 (file)
@@ -29,7 +29,7 @@ static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
        int s[COND_EXPR_MAXDEPTH];
        int sp = -1;
 
-       for (cur = expr; cur != NULL; cur = cur->next) {
+       for (cur = expr; cur; cur = cur->next) {
                switch (cur->expr_type) {
                case COND_BOOL:
                        if (sp == (COND_EXPR_MAXDEPTH - 1))
@@ -97,14 +97,14 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node)
                if (new_state == -1)
                        printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n");
                /* turn the rules on or off */
-               for (cur = node->true_list; cur != NULL; cur = cur->next) {
+               for (cur = node->true_list; cur; cur = cur->next) {
                        if (new_state <= 0)
                                cur->node->key.specified &= ~AVTAB_ENABLED;
                        else
                                cur->node->key.specified |= AVTAB_ENABLED;
                }
 
-               for (cur = node->false_list; cur != NULL; cur = cur->next) {
+               for (cur = node->false_list; cur; cur = cur->next) {
                        /* -1 or 1 */
                        if (new_state)
                                cur->node->key.specified &= ~AVTAB_ENABLED;
@@ -128,7 +128,7 @@ int cond_policydb_init(struct policydb *p)
 static void cond_av_list_destroy(struct cond_av_list *list)
 {
        struct cond_av_list *cur, *next;
-       for (cur = list; cur != NULL; cur = next) {
+       for (cur = list; cur; cur = next) {
                next = cur->next;
                /* the avtab_ptr_t node is destroy by the avtab */
                kfree(cur);
@@ -139,7 +139,7 @@ static void cond_node_destroy(struct cond_node *node)
 {
        struct cond_expr *cur_expr, *next_expr;
 
-       for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) {
+       for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
                next_expr = cur_expr->next;
                kfree(cur_expr);
        }
@@ -155,7 +155,7 @@ static void cond_list_destroy(struct cond_node *list)
        if (list == NULL)
                return;
 
-       for (cur = list; cur != NULL; cur = next) {
+       for (cur = list; cur; cur = next) {
                next = cur->next;
                cond_node_destroy(cur);
        }
@@ -239,7 +239,7 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto err;
-       key[len] = 0;
+       key[len] = '\0';
        if (hashtab_insert(h, key, booldatum))
                goto err;
 
@@ -291,7 +291,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
                                        goto err;
                                }
                                found = 0;
-                               for (cur = other; cur != NULL; cur = cur->next) {
+                               for (cur = other; cur; cur = cur->next) {
                                        if (cur->node == node_ptr) {
                                                found = 1;
                                                break;
@@ -485,7 +485,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi
        if (!ctab || !key || !avd)
                return;
 
-       for (node = avtab_search_node(ctab, key); node != NULL;
+       for (node = avtab_search_node(ctab, key); node;
                                node = avtab_search_node_next(node, key->specified)) {
                if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
                    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
index 65b9f83..53ddb01 100644 (file)
@@ -28,7 +28,7 @@ struct cond_expr {
 #define COND_XOR       5 /* bool ^ bool */
 #define COND_EQ                6 /* bool == bool */
 #define COND_NEQ       7 /* bool != bool */
-#define COND_LAST      8
+#define COND_LAST      COND_NEQ
        __u32 expr_type;
        __u32 bool;
        struct cond_expr *next;
index ddc2754..68c7348 100644 (file)
@@ -109,7 +109,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
        *catmap = c_iter;
        c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
 
-       while (e_iter != NULL) {
+       while (e_iter) {
                for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
                        unsigned int delta, e_startbit, c_endbit;
 
@@ -197,7 +197,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
                        }
                }
                c_iter = c_iter->next;
-       } while (c_iter != NULL);
+       } while (c_iter);
        if (e_iter != NULL)
                ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
        else
index 2e7788e..933e735 100644 (file)
@@ -81,7 +81,7 @@ void *hashtab_search(struct hashtab *h, const void *key)
 
        hvalue = h->hash_value(h, key);
        cur = h->htable[hvalue];
-       while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
+       while (cur && h->keycmp(h, key, cur->key) > 0)
                cur = cur->next;
 
        if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
@@ -100,7 +100,7 @@ void hashtab_destroy(struct hashtab *h)
 
        for (i = 0; i < h->size; i++) {
                cur = h->htable[i];
-               while (cur != NULL) {
+               while (cur) {
                        temp = cur;
                        cur = cur->next;
                        kfree(temp);
@@ -127,7 +127,7 @@ int hashtab_map(struct hashtab *h,
 
        for (i = 0; i < h->size; i++) {
                cur = h->htable[i];
-               while (cur != NULL) {
+               while (cur) {
                        ret = apply(cur->key, cur->datum, args);
                        if (ret)
                                return ret;
index 77d745d..b5407f1 100644 (file)
@@ -283,8 +283,8 @@ int mls_context_to_sid(struct policydb *pol,
                p++;
 
        delim = *p;
-       if (delim != 0)
-               *p++ = 0;
+       if (delim != '\0')
+               *p++ = '\0';
 
        for (l = 0; l < 2; l++) {
                levdatum = hashtab_search(pol->p_levels.table, scontextp);
@@ -302,14 +302,14 @@ int mls_context_to_sid(struct policydb *pol,
                                while (*p && *p != ',' && *p != '-')
                                        p++;
                                delim = *p;
-                               if (delim != 0)
-                                       *p++ = 0;
+                               if (delim != '\0')
+                                       *p++ = '\0';
 
                                /* Separate into range if exists */
                                rngptr = strchr(scontextp, '.');
                                if (rngptr != NULL) {
                                        /* Remove '.' */
-                                       *rngptr++ = 0;
+                                       *rngptr++ = '\0';
                                }
 
                                catdatum = hashtab_search(pol->p_cats.table,
@@ -357,8 +357,8 @@ int mls_context_to_sid(struct policydb *pol,
                                p++;
 
                        delim = *p;
-                       if (delim != 0)
-                               *p++ = 0;
+                       if (delim != '\0')
+                               *p++ = '\0';
                } else
                        break;
        }
index 2391761..72e4a54 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/audit.h>
 #include "security.h"
 
 #include "policydb.h"
@@ -116,7 +117,12 @@ static struct policydb_compat_info policydb_compat[] = {
                .version        = POLICYDB_VERSION_PERMISSIVE,
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
-       }
+       },
+       {
+               .version        = POLICYDB_VERSION_BOUNDARY,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
+       },
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -254,7 +260,9 @@ static int role_index(void *key, void *datum, void *datap)
 
        role = datum;
        p = datap;
-       if (!role->value || role->value > p->p_roles.nprim)
+       if (!role->value
+           || role->value > p->p_roles.nprim
+           || role->bounds > p->p_roles.nprim)
                return -EINVAL;
        p->p_role_val_to_name[role->value - 1] = key;
        p->role_val_to_struct[role->value - 1] = role;
@@ -270,9 +278,12 @@ static int type_index(void *key, void *datum, void *datap)
        p = datap;
 
        if (typdatum->primary) {
-               if (!typdatum->value || typdatum->value > p->p_types.nprim)
+               if (!typdatum->value
+                   || typdatum->value > p->p_types.nprim
+                   || typdatum->bounds > p->p_types.nprim)
                        return -EINVAL;
                p->p_type_val_to_name[typdatum->value - 1] = key;
+               p->type_val_to_struct[typdatum->value - 1] = typdatum;
        }
 
        return 0;
@@ -285,7 +296,9 @@ static int user_index(void *key, void *datum, void *datap)
 
        usrdatum = datum;
        p = datap;
-       if (!usrdatum->value || usrdatum->value > p->p_users.nprim)
+       if (!usrdatum->value
+           || usrdatum->value > p->p_users.nprim
+           || usrdatum->bounds > p->p_users.nprim)
                return -EINVAL;
        p->p_user_val_to_name[usrdatum->value - 1] = key;
        p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
@@ -438,6 +451,14 @@ static int policydb_index_others(struct policydb *p)
                goto out;
        }
 
+       p->type_val_to_struct =
+               kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
+                       GFP_KERNEL);
+       if (!p->type_val_to_struct) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
        if (cond_init_bool_indexes(p)) {
                rc = -ENOMEM;
                goto out;
@@ -625,6 +646,7 @@ void policydb_destroy(struct policydb *p)
        kfree(p->class_val_to_struct);
        kfree(p->role_val_to_struct);
        kfree(p->user_val_to_struct);
+       kfree(p->type_val_to_struct);
 
        avtab_destroy(&p->te_avtab);
 
@@ -932,7 +954,7 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        rc = hashtab_insert(h, key, perdatum);
        if (rc)
@@ -979,7 +1001,7 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        for (i = 0; i < nel; i++) {
                rc = perm_read(p, comdatum->permissions.table, fp);
@@ -1117,7 +1139,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        if (len2) {
                cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL);
@@ -1128,7 +1150,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
                rc = next_entry(cladatum->comkey, fp, len2);
                if (rc < 0)
                        goto bad;
-               cladatum->comkey[len2] = 0;
+               cladatum->comkey[len2] = '\0';
 
                cladatum->comdatum = hashtab_search(p->p_commons.table,
                                                    cladatum->comkey);
@@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 {
        char *key = NULL;
        struct role_datum *role;
-       int rc;
-       __le32 buf[2];
+       int rc, to_read = 2;
+       __le32 buf[3];
        u32 len;
 
        role = kzalloc(sizeof(*role), GFP_KERNEL);
@@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
                goto out;
        }
 
-       rc = next_entry(buf, fp, sizeof buf);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               to_read = 3;
+
+       rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
        if (rc < 0)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        role->value = le32_to_cpu(buf[1]);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               role->bounds = le32_to_cpu(buf[2]);
 
        key = kmalloc(len + 1, GFP_KERNEL);
        if (!key) {
@@ -1201,7 +1228,7 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        rc = ebitmap_read(&role->dominates, fp);
        if (rc)
@@ -1236,8 +1263,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
 {
        char *key = NULL;
        struct type_datum *typdatum;
-       int rc;
-       __le32 buf[3];
+       int rc, to_read = 3;
+       __le32 buf[4];
        u32 len;
 
        typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
@@ -1246,13 +1273,27 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
                return rc;
        }
 
-       rc = next_entry(buf, fp, sizeof buf);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               to_read = 4;
+
+       rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
        if (rc < 0)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        typdatum->value = le32_to_cpu(buf[1]);
-       typdatum->primary = le32_to_cpu(buf[2]);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+               u32 prop = le32_to_cpu(buf[2]);
+
+               if (prop & TYPEDATUM_PROPERTY_PRIMARY)
+                       typdatum->primary = 1;
+               if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
+                       typdatum->attribute = 1;
+
+               typdatum->bounds = le32_to_cpu(buf[3]);
+       } else {
+               typdatum->primary = le32_to_cpu(buf[2]);
+       }
 
        key = kmalloc(len + 1, GFP_KERNEL);
        if (!key) {
@@ -1262,7 +1303,7 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        rc = hashtab_insert(h, key, typdatum);
        if (rc)
@@ -1309,8 +1350,8 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
 {
        char *key = NULL;
        struct user_datum *usrdatum;
-       int rc;
-       __le32 buf[2];
+       int rc, to_read = 2;
+       __le32 buf[3];
        u32 len;
 
        usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
@@ -1319,12 +1360,17 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
                goto out;
        }
 
-       rc = next_entry(buf, fp, sizeof buf);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               to_read = 3;
+
+       rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
        if (rc < 0)
                goto bad;
 
        len = le32_to_cpu(buf[0]);
        usrdatum->value = le32_to_cpu(buf[1]);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               usrdatum->bounds = le32_to_cpu(buf[2]);
 
        key = kmalloc(len + 1, GFP_KERNEL);
        if (!key) {
@@ -1334,7 +1380,7 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        rc = ebitmap_read(&usrdatum->roles, fp);
        if (rc)
@@ -1388,7 +1434,7 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC);
        if (!levdatum->level) {
@@ -1440,7 +1486,7 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
        rc = next_entry(key, fp, len);
        if (rc < 0)
                goto bad;
-       key[len] = 0;
+       key[len] = '\0';
 
        rc = hashtab_insert(h, key, catdatum);
        if (rc)
@@ -1465,6 +1511,133 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
        cat_read,
 };
 
+static int user_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+       struct user_datum *upper, *user;
+       struct policydb *p = datap;
+       int depth = 0;
+
+       upper = user = datum;
+       while (upper->bounds) {
+               struct ebitmap_node *node;
+               unsigned long bit;
+
+               if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+                       printk(KERN_ERR "SELinux: user %s: "
+                              "too deep or looped boundary",
+                              (char *) key);
+                       return -EINVAL;
+               }
+
+               upper = p->user_val_to_struct[upper->bounds - 1];
+               ebitmap_for_each_positive_bit(&user->roles, node, bit) {
+                       if (ebitmap_get_bit(&upper->roles, bit))
+                               continue;
+
+                       printk(KERN_ERR
+                              "SELinux: boundary violated policy: "
+                              "user=%s role=%s bounds=%s\n",
+                              p->p_user_val_to_name[user->value - 1],
+                              p->p_role_val_to_name[bit],
+                              p->p_user_val_to_name[upper->value - 1]);
+
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int role_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+       struct role_datum *upper, *role;
+       struct policydb *p = datap;
+       int depth = 0;
+
+       upper = role = datum;
+       while (upper->bounds) {
+               struct ebitmap_node *node;
+               unsigned long bit;
+
+               if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+                       printk(KERN_ERR "SELinux: role %s: "
+                              "too deep or looped bounds\n",
+                              (char *) key);
+                       return -EINVAL;
+               }
+
+               upper = p->role_val_to_struct[upper->bounds - 1];
+               ebitmap_for_each_positive_bit(&role->types, node, bit) {
+                       if (ebitmap_get_bit(&upper->types, bit))
+                               continue;
+
+                       printk(KERN_ERR
+                              "SELinux: boundary violated policy: "
+                              "role=%s type=%s bounds=%s\n",
+                              p->p_role_val_to_name[role->value - 1],
+                              p->p_type_val_to_name[bit],
+                              p->p_role_val_to_name[upper->value - 1]);
+
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int type_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+       struct type_datum *upper, *type;
+       struct policydb *p = datap;
+       int depth = 0;
+
+       upper = type = datum;
+       while (upper->bounds) {
+               if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+                       printk(KERN_ERR "SELinux: type %s: "
+                              "too deep or looped boundary\n",
+                              (char *) key);
+                       return -EINVAL;
+               }
+
+               upper = p->type_val_to_struct[upper->bounds - 1];
+               if (upper->attribute) {
+                       printk(KERN_ERR "SELinux: type %s: "
+                              "bounded by attribute %s",
+                              (char *) key,
+                              p->p_type_val_to_name[upper->value - 1]);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int policydb_bounds_sanity_check(struct policydb *p)
+{
+       int rc;
+
+       if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
+               return 0;
+
+       rc = hashtab_map(p->p_users.table,
+                        user_bounds_sanity_check, p);
+       if (rc)
+               return rc;
+
+       rc = hashtab_map(p->p_roles.table,
+                        role_bounds_sanity_check, p);
+       if (rc)
+               return rc;
+
+       rc = hashtab_map(p->p_types.table,
+                        type_bounds_sanity_check, p);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
 extern int ss_initialized;
 
 /*
@@ -1523,7 +1696,7 @@ int policydb_read(struct policydb *p, void *fp)
                kfree(policydb_str);
                goto bad;
        }
-       policydb_str[len] = 0;
+       policydb_str[len] = '\0';
        if (strcmp(policydb_str, POLICYDB_STRING)) {
                printk(KERN_ERR "SELinux:  policydb string %s does not match "
                       "my string %s\n", policydb_str, POLICYDB_STRING);
@@ -1961,6 +2134,10 @@ int policydb_read(struct policydb *p, void *fp)
                                goto bad;
        }
 
+       rc = policydb_bounds_sanity_check(p);
+       if (rc)
+               goto bad;
+
        rc = 0;
 out:
        return rc;
index 4253370..55152d4 100644 (file)
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
        u32 value;                      /* internal role value */
+       u32 bounds;                     /* boundary of role */
        struct ebitmap dominates;       /* set of roles dominated by this role */
        struct ebitmap types;           /* set of authorized types for role */
 };
@@ -81,12 +82,15 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
        u32 value;              /* internal type value */
+       u32 bounds;             /* boundary of type */
        unsigned char primary;  /* primary name? */
+       unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
        u32 value;                      /* internal user value */
+       u32 bounds;                     /* bounds of user */
        struct ebitmap roles;           /* set of authorized roles for user */
        struct mls_range range;         /* MLS range (min - max) for user */
        struct mls_level dfltlevel;     /* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
        struct class_datum **class_val_to_struct;
        struct role_datum **role_val_to_struct;
        struct user_datum **user_val_to_struct;
+       struct type_datum **type_val_to_struct;
 
        /* type enforcement access vectors and transitions */
        struct avtab te_avtab;
index d11a815..876b815 100644 (file)
@@ -88,6 +88,11 @@ static u32 latest_granting;
 static int context_struct_to_string(struct context *context, char **scontext,
                                    u32 *scontext_len);
 
+static int context_struct_compute_av(struct context *scontext,
+                                    struct context *tcontext,
+                                    u16 tclass,
+                                    u32 requested,
+                                    struct av_decision *avd);
 /*
  * Return the boolean value of a constraint expression
  * when it is applied to the specified source and target
@@ -274,6 +279,100 @@ mls_ops:
 }
 
 /*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
+ */
+static void type_attribute_bounds_av(struct context *scontext,
+                                    struct context *tcontext,
+                                    u16 tclass,
+                                    u32 requested,
+                                    struct av_decision *avd)
+{
+       struct context lo_scontext;
+       struct context lo_tcontext;
+       struct av_decision lo_avd;
+       struct type_datum *source
+               = policydb.type_val_to_struct[scontext->type - 1];
+       struct type_datum *target
+               = policydb.type_val_to_struct[tcontext->type - 1];
+       u32 masked = 0;
+
+       if (source->bounds) {
+               memset(&lo_avd, 0, sizeof(lo_avd));
+
+               memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
+               lo_scontext.type = source->bounds;
+
+               context_struct_compute_av(&lo_scontext,
+                                         tcontext,
+                                         tclass,
+                                         requested,
+                                         &lo_avd);
+               if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+                       return;         /* no masked permission */
+               masked = ~lo_avd.allowed & avd->allowed;
+       }
+
+       if (target->bounds) {
+               memset(&lo_avd, 0, sizeof(lo_avd));
+
+               memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
+               lo_tcontext.type = target->bounds;
+
+               context_struct_compute_av(scontext,
+                                         &lo_tcontext,
+                                         tclass,
+                                         requested,
+                                         &lo_avd);
+               if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+                       return;         /* no masked permission */
+               masked = ~lo_avd.allowed & avd->allowed;
+       }
+
+       if (source->bounds && target->bounds) {
+               memset(&lo_avd, 0, sizeof(lo_avd));
+               /*
+                * lo_scontext and lo_tcontext are already
+                * set up.
+                */
+
+               context_struct_compute_av(&lo_scontext,
+                                         &lo_tcontext,
+                                         tclass,
+                                         requested,
+                                         &lo_avd);
+               if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+                       return;         /* no masked permission */
+               masked = ~lo_avd.allowed & avd->allowed;
+       }
+
+       if (masked) {
+               struct audit_buffer *ab;
+               char *stype_name
+                       = policydb.p_type_val_to_name[source->value - 1];
+               char *ttype_name
+                       = policydb.p_type_val_to_name[target->value - 1];
+               char *tclass_name
+                       = policydb.p_class_val_to_name[tclass - 1];
+
+               /* mask violated permissions */
+               avd->allowed &= ~masked;
+
+               /* notice to userspace via audit message */
+               ab = audit_log_start(current->audit_context,
+                                    GFP_ATOMIC, AUDIT_SELINUX_ERR);
+               if (!ab)
+                       return;
+
+               audit_log_format(ab, "av boundary violation: "
+                                "source=%s target=%s tclass=%s",
+                                stype_name, ttype_name, tclass_name);
+               avc_dump_av(ab, tclass, masked);
+               audit_log_end(ab);
+       }
+}
+
+/*
  * Compute access vectors based on a context structure pair for
  * the permissions in a particular class.
  */
@@ -356,7 +455,7 @@ static int context_struct_compute_av(struct context *scontext,
                        avkey.source_type = i + 1;
                        avkey.target_type = j + 1;
                        for (node = avtab_search_node(&policydb.te_avtab, &avkey);
-                            node != NULL;
+                            node;
                             node = avtab_search_node_next(node, avkey.specified)) {
                                if (node->key.specified == AVTAB_ALLOWED)
                                        avd->allowed |= node->datum.data;
@@ -404,6 +503,14 @@ static int context_struct_compute_av(struct context *scontext,
                                                        PROCESS__DYNTRANSITION);
        }
 
+       /*
+        * If the given source and target types have boundary
+        * constraint, lazy checks have to mask any violated
+        * permission and notice it to userspace via audit.
+        */
+       type_attribute_bounds_av(scontext, tcontext,
+                                tclass, requested, avd);
+
        return 0;
 
 inval_class:
@@ -549,6 +656,69 @@ out:
        return rc;
 }
 
+/*
+ * security_bounded_transition - check whether the given
+ * transition is directed to bounded, or not.
+ * It returns 0, if @newsid is bounded by @oldsid.
+ * Otherwise, it returns error code.
+ *
+ * @oldsid : current security identifier
+ * @newsid : destinated security identifier
+ */
+int security_bounded_transition(u32 old_sid, u32 new_sid)
+{
+       struct context *old_context, *new_context;
+       struct type_datum *type;
+       int index;
+       int rc = -EINVAL;
+
+       read_lock(&policy_rwlock);
+
+       old_context = sidtab_search(&sidtab, old_sid);
+       if (!old_context) {
+               printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+                      __func__, old_sid);
+               goto out;
+       }
+
+       new_context = sidtab_search(&sidtab, new_sid);
+       if (!new_context) {
+               printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+                      __func__, new_sid);
+               goto out;
+       }
+
+       /* type/domain unchaned */
+       if (old_context->type == new_context->type) {
+               rc = 0;
+               goto out;
+       }
+
+       index = new_context->type;
+       while (true) {
+               type = policydb.type_val_to_struct[index - 1];
+               BUG_ON(!type);
+
+               /* not bounded anymore */
+               if (!type->bounds) {
+                       rc = -EPERM;
+                       break;
+               }
+
+               /* @newsid is bounded by @oldsid */
+               if (type->bounds == old_context->type) {
+                       rc = 0;
+                       break;
+               }
+               index = type->bounds;
+       }
+out:
+       read_unlock(&policy_rwlock);
+
+       return rc;
+}
+
+
 /**
  * security_compute_av - Compute access vector decisions.
  * @ssid: source security identifier
@@ -794,7 +964,7 @@ static int string_to_context_struct(struct policydb *pol,
        *p++ = 0;
 
        typdatum = hashtab_search(pol->p_types.table, scontextp);
-       if (!typdatum)
+       if (!typdatum || typdatum->attribute)
                goto out;
 
        ctx->type = typdatum->value;
@@ -1037,7 +1207,7 @@ static int security_compute_sid(u32 ssid,
        /* If no permanent rule, also check for enabled conditional rules */
        if (!avdatum) {
                node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
-               for (; node != NULL; node = avtab_search_node_next(node, specified)) {
+               for (; node; node = avtab_search_node_next(node, specified)) {
                        if (node->key.specified & AVTAB_ENABLED) {
                                avdatum = &node->datum;
                                break;
@@ -2050,7 +2220,7 @@ int security_set_bools(int len, int *values)
                        policydb.bool_val_to_struct[i]->state = 0;
        }
 
-       for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
+       for (cur = policydb.cond_list; cur; cur = cur->next) {
                rc = evaluate_cond_node(&policydb, cur);
                if (rc)
                        goto out;
@@ -2102,7 +2272,7 @@ static int security_preserve_bools(struct policydb *p)
                if (booldatum)
                        booldatum->state = bvalues[i];
        }
-       for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+       for (cur = p->cond_list; cur; cur = cur->next) {
                rc = evaluate_cond_node(p, cur);
                if (rc)
                        goto out;
index a81ded1..e817989 100644 (file)
@@ -43,7 +43,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
        hvalue = SIDTAB_HASH(sid);
        prev = NULL;
        cur = s->htable[hvalue];
-       while (cur != NULL && sid > cur->sid) {
+       while (cur && sid > cur->sid) {
                prev = cur;
                cur = cur->next;
        }
@@ -92,7 +92,7 @@ static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
 
        hvalue = SIDTAB_HASH(sid);
        cur = s->htable[hvalue];
-       while (cur != NULL && sid > cur->sid)
+       while (cur && sid > cur->sid)
                cur = cur->next;
 
        if (force && cur && sid == cur->sid && cur->context.len)
@@ -103,7 +103,7 @@ static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
                sid = SECINITSID_UNLABELED;
                hvalue = SIDTAB_HASH(sid);
                cur = s->htable[hvalue];
-               while (cur != NULL && sid > cur->sid)
+               while (cur && sid > cur->sid)
                        cur = cur->next;
                if (!cur || sid != cur->sid)
                        return NULL;
@@ -136,7 +136,7 @@ int sidtab_map(struct sidtab *s,
 
        for (i = 0; i < SIDTAB_SIZE; i++) {
                cur = s->htable[i];
-               while (cur != NULL) {
+               while (cur) {
                        rc = apply(cur->sid, &cur->context, args);
                        if (rc)
                                goto out;
@@ -155,7 +155,7 @@ static inline u32 sidtab_search_context(struct sidtab *s,
 
        for (i = 0; i < SIDTAB_SIZE; i++) {
                cur = s->htable[i];
-               while (cur != NULL) {
+               while (cur) {
                        if (context_cmp(&cur->context, context))
                                return cur->sid;
                        cur = cur->next;
@@ -242,7 +242,7 @@ void sidtab_destroy(struct sidtab *s)
 
        for (i = 0; i < SIDTAB_SIZE; i++) {
                cur = s->htable[i];
-               while (cur != NULL) {
+               while (cur) {
                        temp = cur;
                        cur = cur->next;
                        context_destroy(&temp->context);
index 4a4477f..31dce55 100644 (file)
@@ -178,6 +178,7 @@ u32 smack_to_secid(const char *);
 extern int smack_cipso_direct;
 extern int smack_net_nltype;
 extern char *smack_net_ambient;
+extern char *smack_onlycap;
 
 extern struct smack_known *smack_known;
 extern struct smack_known smack_known_floor;
index f6b5f6e..79ff21e 100644 (file)
@@ -157,7 +157,7 @@ int smk_access(char *subject_label, char *object_label, int request)
  *
  * This function checks the current subject label/object label pair
  * in the access rule list and returns 0 if the access is permitted,
- * non zero otherwise. It allows that current my have the capability
+ * non zero otherwise. It allows that current may have the capability
  * to override the rules.
  */
 int smk_curacc(char *obj_label, u32 mode)
@@ -168,6 +168,14 @@ int smk_curacc(char *obj_label, u32 mode)
        if (rc == 0)
                return 0;
 
+       /*
+        * Return if a specific label has been designated as the
+        * only one that gets privilege and current does not
+        * have that label.
+        */
+       if (smack_onlycap != NULL && smack_onlycap != current->security)
+               return rc;
+
        if (capable(CAP_MAC_OVERRIDE))
                return 0;
 
index 271a835..e7c6424 100644 (file)
@@ -39,6 +39,7 @@ enum smk_inos {
        SMK_DIRECT      = 6,    /* CIPSO level indicating direct label */
        SMK_AMBIENT     = 7,    /* internet ambient label */
        SMK_NLTYPE      = 8,    /* label scheme to use by default */
+       SMK_ONLYCAP     = 9,    /* the only "capable" label */
 };
 
 /*
@@ -68,6 +69,16 @@ int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
  */
 int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
 
+/*
+ * Unless a process is running with this label even
+ * having CAP_MAC_OVERRIDE isn't enough to grant
+ * privilege to violate MAC policy. If no label is
+ * designated (the NULL case) capabilities apply to
+ * everyone. It is expected that the hat (^) label
+ * will be used if any label is used.
+ */
+char *smack_onlycap;
+
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 struct smk_list_entry *smack_list;
 
@@ -787,6 +798,85 @@ static const struct file_operations smk_ambient_ops = {
        .write          = smk_write_ambient,
 };
 
+/**
+ * smk_read_onlycap - read() for /smack/onlycap
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @cn: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
+                               size_t cn, loff_t *ppos)
+{
+       char *smack = "";
+       ssize_t rc = -EINVAL;
+       int asize;
+
+       if (*ppos != 0)
+               return 0;
+
+       if (smack_onlycap != NULL)
+               smack = smack_onlycap;
+
+       asize = strlen(smack) + 1;
+
+       if (cn >= asize)
+               rc = simple_read_from_buffer(buf, cn, ppos, smack, asize);
+
+       return rc;
+}
+
+/**
+ * smk_write_onlycap - write() for /smack/onlycap
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       char in[SMK_LABELLEN];
+       char *sp = current->security;
+
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       /*
+        * This can be done using smk_access() but is done
+        * explicitly for clarity. The smk_access() implementation
+        * would use smk_access(smack_onlycap, MAY_WRITE)
+        */
+       if (smack_onlycap != NULL && smack_onlycap != sp)
+               return -EPERM;
+
+       if (count >= SMK_LABELLEN)
+               return -EINVAL;
+
+       if (copy_from_user(in, buf, count) != 0)
+               return -EFAULT;
+
+       /*
+        * Should the null string be passed in unset the onlycap value.
+        * This seems like something to be careful with as usually
+        * smk_import only expects to return NULL for errors. It
+        * is usually the case that a nullstring or "\n" would be
+        * bad to pass to smk_import but in fact this is useful here.
+        */
+       smack_onlycap = smk_import(in, count);
+
+       return count;
+}
+
+static const struct file_operations smk_onlycap_ops = {
+       .read           = smk_read_onlycap,
+       .write          = smk_write_onlycap,
+};
+
 struct option_names {
        int     o_number;
        char    *o_name;
@@ -919,6 +1009,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
                        {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
                [SMK_NLTYPE]    =
                        {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
+               [SMK_ONLYCAP]   =
+                       {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
                /* last one */ {""}
        };