Merge branch 'master' into next
authorJames Morris <jmorris@namei.org>
Thu, 28 Aug 2008 00:47:34 +0000 (10:47 +1000)
committerJames Morris <jmorris@namei.org>
Thu, 28 Aug 2008 00:47:34 +0000 (10:47 +1000)
24 files changed:
Documentation/DocBook/kernel-api.tmpl
Documentation/SELinux.txt [new file with mode: 0644]
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/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/inode.c
security/security.c
security/selinux/hooks.c
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/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 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/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 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 03fc6a8..6b5790b 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;
 }
 
 /**
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..2664630 100644 (file)
@@ -932,7 +932,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 +979,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 +1117,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 +1128,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);
@@ -1201,7 +1201,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)
@@ -1262,7 +1262,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)
@@ -1334,7 +1334,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 +1388,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 +1440,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)
@@ -1523,7 +1523,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);
index b52f923..5a0536b 100644 (file)
@@ -356,7 +356,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;
@@ -1037,7 +1037,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 +2050,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 +2102,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 */ {""}
        };