From: Casey Schaufler <[email protected]>
Smack is the Simplified Mandatory Access Control Kernel.
Smack implements mandatory access control (MAC) using labels
attached to tasks and data containers, including files, SVIPC,
and other tasks. Smack is a kernel based scheme that requires
an absolute minimum of application support and a very small
amount of configuration data.
Smack is implemented as a clean LSM. It requires no external
code changes and the patch modifies only the Kconfig and Makefile
in the security directory. Smack uses extended attributes and
provides a set of general mount options, borrowing technics used
elsewhere. Smack uses netlabel for CIPSO labeling. Smack provides
a pseudo-filesystem smackfs that is used for manipulation of
system Smack attributes.
The patch, patches for ls and sshd, a README, a startup script,
and x86 binaries for ls and sshd are also available on
http:/http://www.schaufler-ca.com
The patch has been tested with 2.6.22, 2.6.23-rc8, and
2.6.23-rc8-mm2. Development has been done using Fedora Core 7
in a virtual machine environment and on an old Sony laptop.
Smack provides mandatory access controls based on the label attached
to a task and the label attached to the object it is attempting to
access. Smack labels are deliberately short (1-23 characters) text
strings. Single character labels using special characters are reserved
for system use. The only operation applied to Smack labels is equality
comparison. No wildcards or expressions, regular or otherwise, are
used.
A file always gets the Smack label of the task that created it.
Smack defines and uses these labels:
"*" - pronounced "star"
"_" - pronounced "floor"
"^" - pronounced "hat"
"?" - pronounced "huh"
The access rules enforced by Smack are, in order:
1. Any access requested by a task labeled "*" is denied.
2. A read or execute access requested by a task labeled "^"
is permitted.
3. A read or execute access requested on an object labeled "_"
is permitted.
4. Any access requested on an object labeled "*" is permitted.
5. Any access requested by a task on an object with the same
label is permitted.
6. Any access requested that is explicitly defined in the loaded
rule set is permitted.
7. Any other access is denied.
Rules may be explicitly defined by writing subject,object,access
triples to /smack/load.
Smack rule sets can be easily defined that describe Bell&LaPadula
sensitivity, Biba integrity, and a variety of interesting
configurations. Smack rule sets can be modified on the fly to
accomodate changes in the operating environment or even the time
of day.
Some practical use cases:
Hierarchical levels. The less common of the two usual uses
for MLS systems is to define hierarchical levels, often
unclassified, confidential, secret, and so on. To set up smack
to support this, these rules could be defined:
C Unclass rx
S C rx
S Unclass rx
TS S rx
TS C rx
TS Unclass rx
A TS process can read S, C, and Unclass data, but cannot write it.
An S process can read C and Unclass. Note that specifying that
TS can read S and S can read C does not imply TS can read C, it
has to be explicitly stated.
Non-hierarchical categories. This is the more common of the
usual uses for an MLS system. Since the default rule is that a
subject cannot access an object with a different label no
access rules are required to implement compartmentalization.
A case that the Bell & LaPadula policy does not allow is demonstrated
with this Smack access rule:
A case that Bell&LaPadula does not allow that Smack does:
ESPN ABC r
ABC ESPN r
On my portable video device I have two applications, one that
shows ABC programming and the other ESPN programming. ESPN wants
to show me sport stories that show up as news, and ABC will
only provide minimal information about a sports story if ESPN
is covering it. Each side can look at the other's info, neither
can change the other. Neither can see what FOX is up to, which
is just as well all things considered.
Another case that I especially like:
SatData Guard w
Guard Publish w
A program running with the Guard label opens a UDP socket and
accepts messages sent by a program running with a SatData label.
The Guard program inspects the message to ensure it is wholesome
and if it is sends it to a program running with the Publish label.
This program then puts the information passed in an appropriate
place. Note that the Guard program cannot write to a Publish
file system object because file system semanitic require read as
well as write.
The four cases (categories, levels, mutual read, guardbox) here
are all quite real, and problems I've been asked to solve over
the years. The first two are easy to do with traditonal MLS systems
while the last two you can't without invoking privilege, at least
for a while.
Signed-off-by: Casey Schaufler <[email protected]>
---
Changes since the previous version:
- Smack labels can now be up to 23 characters in length. My UI
expert advised that 12 was the absolute minimum, and CIPSO
starts to get troublesome at 30.
- Reading the SMACK64PACKET attribute from a socket used to provide
the label of the last packet delivered. Now it provides the label
of the packet returned by the most recent recv call, or ENOATTR
if that value is not available. It's better to get no value than
an incorrect value.
Documentation/Smack.txt | 104 +
security/Kconfig | 1
security/Makefile | 2
security/smack/Kconfig | 10
security/smack/Makefile | 9
security/smack/smack.h | 207 ++
security/smack/smack_access.c | 345 ++++
security/smack/smack_lsm.c | 2685 ++++++++++++++++++++++++++++++++
security/smack/smackfs.c | 1201 ++++++++++++++
9 files changed, 4564 insertions(+)
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/Documentation/Smack.txt linux-2.6.23-rc8-smack/Documentation/Smack.txt
--- linux-2.6.23-rc8-base/Documentation/Smack.txt 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.23-rc8-smack/Documentation/Smack.txt 2007-09-25 15:30:37.000000000 -0700
@@ -0,0 +1,104 @@
+
+
+ "Good for you, you've decided to clean the elevator!"
+ - The Elevator, from Dark Star
+
+Smack is the the Simplified Mandatory Access Control Kernel.
+Smack is a kernel based implementation of mandatory access
+control that includes simplicity in its primary design goals.
+
+Smack does not implement Domain Type Enforcement (DTE). If
+you want DTE Linux has an implementation called SELinux.
+Those who really want DTE are encouraged to use SELinux.
+Those who don't know what DTE is are encouraged to compare
+SELinux with Smack to determine which mechanisms are best
+suited to the problem at hand.
+
+Smack consists of three major components:
+ - The kernel
+ - A start-up script and a few modified applications
+ - Configuration data
+
+The kernel component of Smack is implemented as a Linux
+Security Modules (LSM) module. It requires netlabel and
+works best with file systems that support extended attributes,
+although xattr support is not strictly required. The Smack
+patch is (currently) self contained, except for Kconfig
+and Makefile changes in the security directory. It is safe
+to run a Smack kernel under a "vanilla" distribution.
+Smack kernels use the CIPSO IP option. Some network
+configurations are intolerant of IP options and can impede
+access to systems that use them as Smack does.
+
+The startup script etc-init.d-smack should be installed
+in /etc/init.d/smack and should be invoked early in the
+start-up process. On Fedora rc5.d/S02smack is recommended.
+This script ensures that certain devices have the correct
+Smack attributes and loads the Smack configuration if
+any is defined.
+
+A version of "ls" that provides a "-M" option to display
+Smack labels on long listing is available.
+
+A hacked version of sshd that allows network logins by users
+with specific Smack labels is available. This version does
+not work for scp. You must set the /etc/ssh/sshd_config
+line:
+ UsePrivilegeSeparation no
+
+The format of /etc/smack/usr is:
+
+ username smack
+
+In keeping with the intent of Smack, configuration data is
+minimal and not strictly required. The most important
+configuration step is mounting the smackfs pseudo filesystem.
+
+Add this line to /etc/fstab:
+
+ smackfs /smack smackfs smackfsdef=* 0 0
+
+and create the /smack directory for mounting.
+
+Smack uses extended attributes (xattrs) to store file labels.
+The command to set a Smack label on a file is:
+
+ # attr -S -s SMACK64 -V "value" path
+
+NOTE: Smack labels are limited to 23 characters. The attr command
+ does not enforce this restriction and can be used to set
+ invalid Smack labels on files.
+
+The smackfs filesystem treats symbolic links in a special way.
+The Smack label of the process is appended to the link value
+during resolution. To provide a /tmp that is available to users
+with multiple labels:
+
+ # mkdir /moldy
+ # mv /tmp /moldy/_
+ # ln -s /smack/tmp /tmp
+
+For each label users are going to use:
+
+ # mkdir /moldy/label
+ # chmod <appropriate-value> /moldy/label
+ # attr -S -s SMACK64 -V "label" /moldy/label
+
+If you don't do anything special all users will get the floor ("_")
+label when they log in. If you do want to log in via the hacked ssh
+at other labels use the attr command to set the smack value on the
+home directory and it's contents.
+
+You can add access rules in /etc/smack/accesses. They take the form:
+
+ subjectlabel objectlabel access
+
+access is a combination of the letters rwxa which specify the
+kind of access permitted a subject with subjectlabel on an
+object with objectlabel. If there is no rule no access is allowed.
+
+A process can see the smack label it is running with by
+reading /proc/self/attr/current. A privileged process can
+set the process smack by writing there.
+
+
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/Kconfig linux-2.6.23-rc8-smack/security/Kconfig
--- linux-2.6.23-rc8-base/security/Kconfig 2007-07-08 16:32:17.000000000 -0700
+++ linux-2.6.23-rc8-smack/security/Kconfig 2007-09-25 15:30:37.000000000 -0700
@@ -94,6 +94,7 @@ config SECURITY_ROOTPLUG
If you are unsure how to answer this question, answer N.
source security/selinux/Kconfig
+source security/smack/Kconfig
endmenu
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/Makefile linux-2.6.23-rc8-smack/security/Makefile
--- linux-2.6.23-rc8-base/security/Makefile 2007-07-08 16:32:17.000000000 -0700
+++ linux-2.6.23-rc8-smack/security/Makefile 2007-09-25 15:30:37.000000000 -0700
@@ -4,6 +4,7 @@
obj-$(CONFIG_KEYS) += keys/
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
+subdir-$(CONFIG_SECURITY_SMACK) += smack
# if we don't select a security model, use the default capabilities
ifneq ($(CONFIG_SECURITY),y)
@@ -14,5 +15,6 @@ endif
obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
# Must precede capability.o in order to stack properly.
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
+obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/Kconfig linux-2.6.23-rc8-smack/security/smack/Kconfig
--- linux-2.6.23-rc8-base/security/smack/Kconfig 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.23-rc8-smack/security/smack/Kconfig 2007-09-25 15:30:38.000000000 -0700
@@ -0,0 +1,10 @@
+config SECURITY_SMACK
+ bool "Simplified Mandatory Access Control Kernel Support"
+ depends on NETLABEL && SECURITY_NETWORK
+ default n
+ help
+ This selects the Simplified Mandatory Access Control Kernel.
+ Smack is useful for sensitivity, integrity, and a variety
+ of other mandatory security schemes.
+ If you are unsure how to answer this question, answer N.
+
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/Makefile linux-2.6.23-rc8-smack/security/smack/Makefile
--- linux-2.6.23-rc8-base/security/smack/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.23-rc8-smack/security/smack/Makefile 2007-09-25 15:30:38.000000000 -0700
@@ -0,0 +1,9 @@
+#
+# Makefile for the SMACK LSM
+#
+
+obj-$(CONFIG_SECURITY_SMACK) := smack.o
+
+smack-y := smack_lsm.o smack_access.o smackfs.o
+
+EXTRA_CFLAGS += -Inet/netlabel
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smack_access.c linux-2.6.23-rc8-smack/security/smack/smack_access.c
--- linux-2.6.23-rc8-base/security/smack/smack_access.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.23-rc8-smack/security/smack/smack_access.c 2007-09-25 15:30:38.000000000 -0700
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <[email protected]>
+ *
+ * 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, version 2.
+ *
+ * Author:
+ * Casey Schaufler <[email protected]>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include "smack.h"
+
+struct smack_known smack_known_unset = {
+ .smk_next = NULL,
+ .smk_known = "UNSET",
+ .smk_secid = 1,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_huh = {
+ .smk_next = &smack_known_unset,
+ .smk_known = "?",
+ .smk_secid = 2,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_hat = {
+ .smk_next = &smack_known_huh,
+ .smk_known = "^",
+ .smk_secid = 3,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_star = {
+ .smk_next = &smack_known_hat,
+ .smk_known = "*",
+ .smk_secid = 4,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_floor = {
+ .smk_next = &smack_known_star,
+ .smk_known = "_",
+ .smk_secid = 5,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_invalid = {
+ .smk_next = &smack_known_floor,
+ .smk_known = "",
+ .smk_secid = 6,
+ .smk_cipso = NULL,
+};
+
+struct smack_known *smack_known = &smack_known_invalid;
+/*
+ * The initial value needs to be bigger than any of the
+ * known values above.
+ */
+static u32 smack_next_secid = 10;
+
+extern struct smk_list_entry *smack_list;
+
+/**
+ * smk_access - determine if a subject has a specific access to an object
+ * @subject_label: a pointer to the subject's Smack label
+ * @object_label: a pointer to the object's Smack label
+ * @request: the access requested, in "MAY" format
+ *
+ * This function looks up the subject/object pair in the
+ * access rule list and returns 0 if the access is permitted,
+ * non zero otherwise.
+ *
+ * Even though Smack labels are usually shared on smack_list
+ * labels that come in off the network can't be imported
+ * and added to the list for locking reasons.
+ *
+ * Therefore, it is necessary to check the contents of the labels,
+ * not just the pointer values. Of course, in most cases the labels
+ * will be on the list, so checking the pointers may be a worthwhile
+ * optimization.
+ */
+int smk_access(char *subject_label, char *object_label, int request)
+{
+ u32 may = MAY_NOT;
+ struct smk_list_entry *sp;
+ struct smack_rule *srp;
+
+ /*
+ * Hardcoded comparisons.
+ *
+ * A star subject can't access any object.
+ */
+ if (subject_label == smack_known_star.smk_known ||
+ strcmp(subject_label, smack_known_star.smk_known) == 0)
+ return -EACCES;
+ /*
+ * A star object can be accessed by any subject.
+ */
+ if (object_label == smack_known_star.smk_known ||
+ strcmp(object_label, smack_known_star.smk_known) == 0)
+ return 0;
+ /*
+ * An object can be accessed in any way by a subject
+ * with the same label.
+ */
+ if (subject_label == object_label ||
+ strcmp(subject_label, object_label) == 0)
+ return 0;
+ /*
+ * A hat subject can read any object.
+ * A floor object can be read by any subject.
+ */
+ if ((request & MAY_ANYREAD) == request) {
+ if (object_label == smack_known_floor.smk_known ||
+ strcmp(object_label, smack_known_floor.smk_known) == 0)
+ return 0;
+ if (subject_label == smack_known_hat.smk_known ||
+ strcmp(subject_label, smack_known_hat.smk_known) == 0)
+ return 0;
+ }
+ /*
+ * Beyond here an explicit relationship is required.
+ * If the requested access is contained in the available
+ * access (e.g. read is included in readwrite) it's
+ * good.
+ */
+ for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
+ srp = &sp->smk_rule;
+
+ if (srp->smk_subject == subject_label ||
+ strcmp(srp->smk_subject, subject_label) == 0) {
+ if (srp->smk_object == object_label ||
+ strcmp(srp->smk_object, object_label) == 0) {
+ may = srp->smk_access;
+ break;
+ }
+ }
+ }
+ /*
+ * This is a bit map operation.
+ */
+ if ((request & may) == request)
+ return 0;
+
+ return -EACCES;
+}
+
+/**
+ * smk_curacc - determine if current has a specific access to an object
+ * @object_label: a pointer to the object's Smack label
+ * @request: the access requested, in "MAY" format
+ *
+ * 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
+ * to override the rules.
+ */
+int smk_curacc(char *obj_label, u32 mode)
+{
+ int rc;
+
+ rc = smk_access(current->security, obj_label, mode);
+ if (rc == 0)
+ return 0;
+
+ if (capable(CAP_MAC_OVERRIDE))
+ return 0;
+
+ return rc;
+}
+
+extern struct mutex smack_known_lock;
+
+/**
+ * smk_import_entry - import a label, return the list entry
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the entry in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+struct smack_known *smk_import_entry(const char *string, int len)
+{
+ struct smack_known *skp;
+ char smack[SMK_LABELLEN];
+ int found;
+ int i;
+
+ if (len <= 0 || len > SMK_MAXLEN)
+ len = SMK_MAXLEN;
+
+ for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
+ if (found)
+ smack[i] = '\0';
+ else if (i >= len || string[i] > '~' || string[i] <= ' ') {
+ smack[i] = '\0';
+ found = 1;
+ }
+ else
+ smack[i] = string[i];
+ }
+
+ if (smack[0] == '\0')
+ return NULL;
+
+ mutex_lock(&smack_known_lock);
+
+ for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+ if (skp->smk_known == smack)
+ break;
+
+ if (skp == NULL) {
+ skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
+ if (skp != NULL) {
+ skp->smk_next = smack_known;
+ strncpy(skp->smk_known, smack, SMK_MAXLEN);
+ skp->smk_secid = smack_next_secid++;
+ skp->smk_cipso = NULL;
+ spin_lock_init(&skp->smk_cipsolock);
+ smack_known = skp;
+ }
+ }
+
+ mutex_unlock(&smack_known_lock);
+
+ return skp;
+}
+
+/**
+ * smk_import - import a smack label
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the label in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+char *smk_import(const char *string, int len)
+{
+ struct smack_known *skp;
+
+ skp = smk_import_entry(string, len);
+ if (skp == NULL)
+ return NULL;
+ return skp->smk_known;
+}
+
+/**
+ * smack_from_secid - find the Smack label associated with a secid
+ * @secid: an integer that might be associated with a Smack label
+ *
+ * Returns a pointer to the appropraite Smack label if there is one,
+ * otherwise a pointer to the invalid Smack label.
+ */
+char *smack_from_secid(const u32 secid)
+{
+ struct smack_known *skp;
+
+ for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+ if (skp->smk_secid == secid)
+ return skp->smk_known;
+
+ /*
+ * If we got this far someone asked for the translation
+ * of a secid that is not on the list.
+ */
+ return smack_known_invalid.smk_known;
+}
+
+u32 smack_to_secid(const char *smack)
+{
+ struct smack_known *skp;
+
+ for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+ if (skp->smk_known == smack)
+ return skp->smk_secid;
+ return 0;
+}
+
+/**
+ * smack_from_cipso - find the Smack label associated with a CIPSO option
+ * @level: Bell & LaPadula level from the network
+ * @catset: Bell & LaPadula categories from the network
+ * @result: where to put the Smack value
+ *
+ * This is a simple lookup in the label table.
+ *
+ * This is an odd duck as far as smack handling goes in that
+ * it sends back a copy of the smack label rather than a pointer
+ * to the master list. This is done because it is possible for
+ * a foreign host to send a smack label that is new to this
+ * machine and hence not on the list. That would not be an
+ * issue except that adding an entry to the master list can't
+ * be done at that point.
+ */
+void smack_from_cipso(u32 level, char *catset, char *result)
+{
+ struct smack_known *kp;
+ char *final = NULL;
+
+ for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) {
+ if (kp->smk_cipso == NULL)
+ continue;
+
+ spin_lock_bh(&kp->smk_cipsolock);
+
+ if (kp->smk_cipso->smk_level == level &&
+ memcmp(kp->smk_cipso->smk_catset,catset,SMK_LABELLEN) == 0)
+ final = kp->smk_known;
+
+ spin_unlock_bh(&kp->smk_cipsolock);
+ }
+ if (final == NULL)
+ final = smack_known_huh.smk_known;
+ strncpy(result, final, SMK_MAXLEN);
+ return;
+}
+
+/**
+ * smack_to_cipso - find the CIPSO option to go with a Smack label
+ * @smack: a pointer to the smack label in question
+ * @cp: where to put the result
+ *
+ * Returns zero if a value is available, non-zero otherwise.
+ */
+int smack_to_cipso(const char *smack, struct smack_cipso *cp)
+{
+ struct smack_known *kp;
+
+ for (kp = smack_known; kp != NULL; kp = kp->smk_next)
+ if (kp->smk_known == smack ||
+ strcmp(kp->smk_known, smack) == 0)
+ break;
+
+ if (kp == NULL || kp->smk_cipso == NULL)
+ return -ENOENT;
+
+ memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
+ return 0;
+}
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smackfs.c linux-2.6.23-rc8-smack/security/smack/smackfs.c
--- linux-2.6.23-rc8-base/security/smack/smackfs.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.23-rc8-smack/security/smack/smackfs.c 2007-09-25 15:30:38.000000000 -0700
@@ -0,0 +1,1201 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <[email protected]>
+ *
+ * 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, version 2.
+ *
+ * Author:
+ * Casey Schaufler <[email protected]>
+ *
+ * Special thanks to the authors of selinuxfs.
+ *
+ * Karl MacMillan <[email protected]>
+ * James Morris <[email protected]>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/security.h>
+#include <linux/mutex.h>
+#include <net/netlabel.h>
+/*
+ * This include could get changed when the internal
+ * netlabel interface for initializing a netlabel domain
+ * has been worked out.
+ */
+#include "netlabel_domainhash.h"
+#include <net/cipso_ipv4.h>
+#include "smack.h"
+
+extern struct mutex smack_list_lock;
+extern struct smack_known smack_known_floor;
+extern struct smack_known smack_known_star;
+extern struct smack_known *smack_known;
+
+/*
+ * smackfs pseudo filesystem.
+ */
+
+enum smk_inos {
+ SMK_ROOT_INO = 2,
+ SMK_LOAD = 3, /* load policy */
+ SMK_LINKS = 4, /* symlinks */
+ SMK_CIPSO = 5, /* load label -> CIPSO mapping */
+ SMK_DOI = 6, /* CIPSO DOI */
+ SMK_DIRECT = 7, /* CIPSO level indicating direct label */
+ SMK_AMBIENT = 8, /* internet ambient label */
+ SMK_NLTYPE = 9, /* label scheme to use by default */
+ SMK_TMP = 100, /* MUST BE LAST! /smack/tmp */
+};
+
+/*
+ * This is the "ambient" label for network traffic.
+ * If it isn't somehow marked, use this.
+ * It can be reset via smackfs/ambient
+ */
+char *smack_net_ambient = smack_known_floor.smk_known;
+
+/*
+ * This is the default packet marking scheme for network traffic.
+ * It can be reset via smackfs/nltype
+ */
+int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
+
+/*
+ * This is the level in a CIPSO header that indicates a
+ * smack label is contained directly in the category set.
+ * It can be reset via smackfs/direct
+ */
+int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
+
+static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
+static int smack_list_count;
+struct smk_list_entry *smack_list;
+
+/*
+ * 'ssssssss oooooooo mmmm\n\0'
+ */
+#define SMACK_RULE_LINE_SIZE (2 * SMK_MAXLEN + 6)
+
+/**
+ * smk_read_load - read() for /smack/load
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_load(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t bytes;
+ struct smk_list_entry *slp = smack_list;
+ struct smack_rule *srp;
+ char *result;
+ char *cp;
+ int realbytes = 0;
+
+ bytes = SMACK_RULE_LINE_SIZE * smack_list_count;
+ if (bytes == 0)
+ return 0;
+
+ result = kzalloc(bytes, GFP_KERNEL);
+ if (result == NULL)
+ return -ENOMEM;
+
+ for (cp = result; slp != NULL; slp = slp->smk_next) {
+ srp = &slp->smk_rule;
+ sprintf(cp, "%-8s %-8s",
+ (char *)srp->smk_subject, (char *)srp->smk_object);
+ cp += strlen(cp);
+ if (srp->smk_access != 0)
+ *cp++ = ' ';
+ if ((srp->smk_access & MAY_READ) != 0)
+ *cp++ = 'r';
+ if ((srp->smk_access & MAY_WRITE) != 0)
+ *cp++ = 'w';
+ if ((srp->smk_access & MAY_EXEC) != 0)
+ *cp++ = 'x';
+ if ((srp->smk_access & MAY_APPEND) != 0)
+ *cp++ = 'a';
+ *cp++ = '\n';
+ }
+ *cp++ = '\0';
+ realbytes = strlen(result);
+
+ bytes = simple_read_from_buffer(buf, count, ppos, result, realbytes);
+
+ kfree(result);
+
+ return bytes;
+}
+
+/**
+ * smk_set_access - add a rule to the rule list
+ * @srp: the new rule to add
+ *
+ * Looks through the current subject/object/access list for
+ * the subject/object pair and replaces the access that was
+ * there. If the pair isn't found add it with the specified
+ * access.
+ */
+static void smk_set_access(struct smack_rule *srp)
+{
+ struct smk_list_entry *sp;
+ struct smk_list_entry *newp;
+
+ mutex_lock(&smack_list_lock);
+
+ for (sp = smack_list; sp != NULL; sp = sp->smk_next)
+ if (sp->smk_rule.smk_subject == srp->smk_subject &&
+ sp->smk_rule.smk_object == srp->smk_object) {
+ sp->smk_rule.smk_access = srp->smk_access;
+ break;
+ }
+
+ if (sp == NULL) {
+ newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
+ newp->smk_rule = *srp;
+ newp->smk_next = smack_list;
+ smack_list = newp;
+ smack_list_count++;
+ }
+
+ mutex_unlock(&smack_list_lock);
+
+ return;
+}
+
+
+/**
+ * smk_write_load - write() for /smack/load
+ * @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_load(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct smack_rule rule;
+ ssize_t rc = count;
+ char *data = NULL;
+ char subjectstr[SMK_LABELLEN];
+ char objectstr[SMK_LABELLEN];
+ char modestr[8];
+ char *cp;
+
+
+ if (!capable(CAP_MAC_OVERRIDE))
+ return -EPERM;
+ /*
+ * No partial writes.
+ */
+ if (*ppos != 0)
+ return -EINVAL;
+
+ /*
+ * 80 characters per line ought to be enough.
+ */
+ if (count > SMACK_LIST_MAX * 80)
+ return -ENOMEM;
+
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ kfree(data);
+ return -EFAULT;
+ }
+
+ *(data + count) = '\0';
+
+ for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
+ if (*++cp == '\0')
+ break;
+ if (sscanf(cp, "%23s %23s %7s\n", subjectstr, objectstr,
+ modestr) != 3) {
+ printk("%s:%d bad scan\n", __func__, __LINE__);
+ break;
+ }
+ rule.smk_subject = smk_import(subjectstr, 0);
+ if (rule.smk_subject == NULL)
+ break;
+ rule.smk_object = smk_import(objectstr, 0);
+ if (rule.smk_object == NULL)
+ break;
+ rule.smk_access = 0;
+ if (strpbrk(modestr, "rR") != NULL)
+ rule.smk_access |= MAY_READ;
+ if (strpbrk(modestr, "wW") != NULL)
+ rule.smk_access |= MAY_WRITE;
+ if (strpbrk(modestr, "xX") != NULL)
+ rule.smk_access |= MAY_EXEC;
+ if (strpbrk(modestr, "aA") != NULL)
+ rule.smk_access |= MAY_APPEND;
+ smk_set_access(&rule);
+ printk("%s:%d rule %s %s 0x%x\n", __func__, __LINE__,
+ (char *)rule.smk_subject, (char *)rule.smk_object,
+ rule.smk_access);
+ }
+
+ kfree(data);
+ return rc;
+}
+
+static const struct file_operations smk_load_ops = {
+ .read = smk_read_load,
+ .write = smk_write_load,
+};
+
+/**
+ * smk_digit - return a pointer to the next digit
+ * @cp: where to start
+ *
+ * Returns a pointer to the next digit in the string, or NULL
+ */
+static inline char *smk_digit(const char *cp)
+{
+ return strpbrk(cp, "0123456789");
+}
+
+static unsigned int smk_cipso_written;
+
+/**
+ * smk_cipso_doi - initialize the CIPSO domain
+ *
+ * This code reaches too deeply into netlabel internals
+ * for comfort, however there is no netlabel KAPI that
+ * allows for kernel based initialization of a CIPSO DOI.
+ * Until Paul and Casey can work out an appropriate
+ * interface Smack will do it this way.
+ */
+void smk_cipso_doi(void)
+{
+ int rc;
+ struct cipso_v4_doi *doip;
+ struct netlbl_dom_map *ndmp;
+ struct netlbl_audit audit_info;
+
+ doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL);
+ if (doip == NULL)
+ panic("smack: Failed to initialize cipso DOI.\n");
+ doip->map.std = NULL;
+
+ ndmp = kmalloc(sizeof(struct netlbl_dom_map), GFP_KERNEL);
+ if (ndmp == NULL)
+ panic("smack: Failed to initialize cipso ndmp.\n");
+
+ doip->doi = smk_cipso_doi_value;
+ doip->type = CIPSO_V4_MAP_PASS;
+ doip->tags[0] = CIPSO_V4_TAG_RBITMAP;
+ for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
+ doip->tags[rc] = CIPSO_V4_TAG_INVALID;
+
+ rc = cipso_v4_doi_add(doip);
+ if (rc != 0)
+ printk("%s:%d add doi rc = %d\n", __func__, __LINE__, rc);
+
+ ndmp->domain = NULL;
+ ndmp->type = NETLBL_NLTYPE_CIPSOV4;
+ ndmp->type_def.cipsov4 = doip;
+
+ rc = netlbl_domhsh_remove_default(&audit_info);
+ if (rc != 0)
+ printk("%s:%d remove rc = %d\n", __func__, __LINE__, rc);
+
+ rc = netlbl_domhsh_add_default(ndmp, &audit_info);
+ if (rc != 0)
+ printk("%s:%d add rc = %d\n", __func__, __LINE__, rc);
+}
+
+/**
+ * smk_read_cipso - read() for /smack/cipso
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ *
+ * label level[/cat[,cat]]
+ */
+static ssize_t smk_read_cipso(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct smack_known *skp;
+ struct smack_cipso *scp;
+ ssize_t bytes;
+ char sep;
+ char *result;
+ char *cp;
+ char *cbp;
+ int realbytes = 0;
+ int cat = -1;
+ int i;
+ unsigned char m;
+
+ if (smk_cipso_written == 0)
+ return 0;
+
+ result = kzalloc(smk_cipso_written, GFP_KERNEL);
+ if (result == NULL)
+ return -ENOMEM;
+ cp = result;
+
+ for (skp = smack_known; skp != NULL; skp = skp->smk_next) {
+ if (skp->smk_cipso == NULL)
+ continue;
+ scp = skp->smk_cipso;
+ cp += sprintf(cp, "%-8s %3d",
+ (char *)&skp->smk_known, scp->smk_level);
+ cat = 1;
+ sep = '/';
+ cbp = scp->smk_catset;
+ for (i = 0; i < SMK_LABELLEN; i++) {
+ for (m = 0x80; m != 0; m >>= 1) {
+ if ((m & cbp[i]) != 0) {
+ cp += sprintf(cp, "%c%d", sep, cat);
+ sep = ',';
+ }
+ cat++;
+ }
+ }
+ *cp++ = '\n';
+ }
+ *cp++ = '\0';
+ realbytes = strlen(result);
+
+ bytes = simple_read_from_buffer(buf, count, ppos, result, realbytes);
+
+ kfree(result);
+
+ return bytes;
+}
+
+/**
+ * smk_write_cipso - write() for /smack/cipso
+ * @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_cipso(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct smack_known *skp;
+ struct smack_cipso *scp;
+ char *mapsmack;
+ char mapcatset[SMK_LABELLEN];
+ int maplevel;
+ ssize_t rc = count;
+ char *data = NULL;
+ char *cp;
+ char *eolp;
+ char *linep;
+ int cat;
+ int i;
+
+ if (!capable(CAP_MAC_OVERRIDE))
+ return -EPERM;
+ /*
+ * No partial writes.
+ */
+ if (*ppos != 0)
+ return -EINVAL;
+ /*
+ * 80 characters per line ought to be enough.
+ */
+ if (count > SMACK_LIST_MAX * 80)
+ return -ENOMEM;
+
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ kfree(data);
+ return -EFAULT;
+ }
+
+ *(data + count) = '\0';
+ smk_cipso_written += count;
+
+ for (eolp = strchr(data, '\n'), linep = data;
+ eolp != NULL && rc >= 0;
+ linep = eolp + 1, eolp = strchr(linep, '\n')) {
+
+ if (eolp == linep)
+ continue;
+ *eolp = '\0';
+ memset(mapcatset, '\0', SMK_LABELLEN);
+
+ skp = smk_import_entry(linep, 0);
+ if (skp == NULL)
+ continue;
+ mapsmack = skp->smk_known;
+
+ cp = smk_digit(linep + strlen((char *)mapsmack));
+ if (cp == NULL)
+ continue;
+
+ i = sscanf(cp, "%d", &maplevel);
+ if (i != 1)
+ continue;
+
+ cp = strchr(cp, '/');
+ if (cp != NULL) {
+ cp = smk_digit(cp);
+ if (cp == NULL)
+ continue;
+
+ do {
+ i = sscanf(cp, "%d", &cat);
+ if (i != 1)
+ break;
+ if (cat > SMACK_CIPSO_MAXCAT) {
+ i = 0;
+ break;
+ }
+ smack_catset_bit(cat, mapcatset);
+
+ cp = strchr(cp, ',');
+ if (cp != NULL)
+ cp = smk_digit(cp);
+ } while (cp != NULL);
+ }
+
+ if (i != 1)
+ continue;
+
+
+ if (skp->smk_cipso == NULL) {
+ scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL);
+ if (scp == NULL) {
+ rc = -ENOMEM;
+ break;
+ }
+ } else
+ scp = NULL;
+
+ spin_lock_bh(&skp->smk_cipsolock);
+ if (skp->smk_cipso == NULL) {
+ skp->smk_cipso = scp;
+ scp = NULL;
+ }
+ skp->smk_cipso->smk_level = maplevel;
+ memcpy(skp->smk_cipso->smk_catset, mapcatset, SMK_MAXLEN);
+ spin_unlock_bh(&skp->smk_cipsolock);
+
+ /*
+ * The only way this could be true is for there
+ * to have been two attempts to update the cipso
+ * list at the same time. One of the two will have
+ * won cleanly, but there remains cleanup to do.
+ */
+ if (scp != NULL) {
+ printk(KERN_WARNING "%s: CIPSO collision for \"%s\"\n",
+ __func__, skp->smk_known);
+ kfree(scp);
+ }
+ /*
+ * Add this to ensure that there are
+ * enough bytes for the regurgitation
+ */
+ smk_cipso_written += SMK_LABELLEN;
+ }
+
+ kfree(data);
+ return rc;
+}
+
+static const struct file_operations smk_cipso_ops = {
+ .read = smk_read_cipso,
+ .write = smk_write_cipso,
+};
+
+/**
+ * smk_read_doi - read() for /smack/doi
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_doi(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ ssize_t rc;
+
+ if (*ppos != 0)
+ return 0;
+
+ sprintf(temp, "%d", smk_cipso_doi_value);
+ rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+ return rc;
+}
+
+/**
+ * smk_write_doi - write() for /smack/doi
+ * @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_doi(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ int i;
+
+ if (!capable(CAP_MAC_OVERRIDE))
+ return -EPERM;
+
+ if (count > sizeof(temp))
+ return -EINVAL;
+
+ if (copy_from_user(temp, buf, count) != 0)
+ return -EFAULT;
+
+ if (sscanf(temp, "%d", &i) != 1)
+ return -EINVAL;
+
+ smk_cipso_doi_value = i;
+
+ return count;
+}
+
+static const struct file_operations smk_doi_ops = {
+ .read = smk_read_doi,
+ .write = smk_write_doi,
+};
+
+/**
+ * smk_read_direct - read() for /smack/direct
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_direct(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ ssize_t rc;
+
+ if (*ppos != 0)
+ return 0;
+
+ sprintf(temp, "%d", smack_cipso_direct);
+ rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+ return rc;
+}
+
+/**
+ * smk_write_direct - write() for /smack/direct
+ * @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_direct(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ int i;
+
+ if (!capable(CAP_MAC_OVERRIDE))
+ return -EPERM;
+
+ if (count > sizeof(temp))
+ return -EINVAL;
+
+ if (copy_from_user(temp, buf, count) != 0)
+ return -EFAULT;
+
+ if (sscanf(temp, "%d", &i) != 1)
+ return -EINVAL;
+
+ smack_cipso_direct = i;
+
+ return count;
+}
+
+static const struct file_operations smk_direct_ops = {
+ .read = smk_read_direct,
+ .write = smk_write_direct,
+};
+
+/**
+ * smk_read_ambient - read() for /smack/ambient
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t rc;
+ int asize = strlen(smack_net_ambient) + 1;
+
+ if (count < asize)
+ return -EINVAL;
+
+ if (*ppos != 0)
+ return 0;
+
+ rc = simple_read_from_buffer(buf,count,ppos,smack_net_ambient,asize);
+
+ return rc;
+}
+
+/**
+ * smk_write_ambient - write() for /smack/ambient
+ * @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_ambient(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char in[SMK_LABELLEN];
+ char *smack;
+
+ if (!capable(CAP_MAC_OVERRIDE))
+ return -EPERM;
+
+ if (count >= SMK_LABELLEN)
+ return -EINVAL;
+
+ if (copy_from_user(in, buf, count) != 0)
+ return -EFAULT;
+
+ smack = smk_import(in, count);
+ if (smack == NULL)
+ return -EINVAL;
+ /*
+ * Better check to be sure this is OK.
+ */
+ smack_net_ambient = smack;
+
+ return count;
+}
+
+static const struct file_operations smk_ambient_ops = {
+ .read = smk_read_ambient,
+ .write = smk_write_ambient,
+};
+
+struct option_names {
+ int o_number;
+ char *o_name;
+ char *o_alias;
+};
+
+static struct option_names netlbl_choices[] = {
+ { NETLBL_NLTYPE_RIPSO,
+ NETLBL_NLTYPE_RIPSO_NAME, "ripso" },
+ { NETLBL_NLTYPE_CIPSOV4,
+ NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" },
+ { NETLBL_NLTYPE_CIPSOV4,
+ NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" },
+ { NETLBL_NLTYPE_CIPSOV6,
+ NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" },
+ { NETLBL_NLTYPE_UNLABELED,
+ NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" },
+};
+
+/**
+ * smk_read_nltype - read() for /smack/nltype
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char bound[40];
+ ssize_t rc;
+ int i;
+
+ if (count < SMK_LABELLEN)
+ return -EINVAL;
+
+ if (*ppos != 0)
+ return 0;
+
+ sprintf(bound, "unknown");
+
+ for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
+ if (smack_net_nltype == netlbl_choices[i].o_number) {
+ sprintf(bound, "%s", netlbl_choices[i].o_name);
+ break;
+ }
+
+ rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
+
+ return rc;
+}
+
+/**
+ * smk_write_nltype - write() for /smack/nltype
+ * @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_nltype(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char bound[40];
+ char *cp;
+ int i;
+
+ if (!capable(CAP_MAC_OVERRIDE))
+ return -EPERM;
+
+ if (count >= 40)
+ return -EINVAL;
+
+ if (copy_from_user(bound, buf, count) != 0)
+ return -EFAULT;
+
+ bound[count] = '\0';
+ cp = strchr(bound, ' ');
+ if (cp != NULL)
+ *cp = '\0';
+ cp = strchr(bound, '\n');
+ if (cp != NULL)
+ *cp = '\0';
+
+ for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
+ if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
+ strcmp(bound, netlbl_choices[i].o_alias) == 0) {
+ smack_net_nltype = netlbl_choices[i].o_number;
+ return count;
+ }
+ /*
+ * Not a valid choice.
+ */
+ return -EINVAL;
+}
+
+static const struct file_operations smk_nltype_ops = {
+ .read = smk_read_nltype,
+ .write = smk_write_nltype,
+};
+
+/*
+ * mapping for symlinks
+ */
+#define SMK_TMPPATH_SIZE 1024
+#define SMK_TMPPATH_ROOT "/moldy/"
+
+struct smk_link {
+ struct smk_link *sl_next;
+ int sl_inum;
+ char sl_name[SMK_TMPPATH_SIZE];
+ char sl_target[SMK_TMPPATH_SIZE];
+};
+
+static struct super_block *smk_sb = NULL;
+static struct smk_link *smk_links = NULL;
+static int smk_links_count = 0;
+
+/**
+ * smackfs_follow_link - follow a smackfs symlink
+ * @dentry: name cache entry
+ * @nd: name entry
+ *
+ * A symlink on smackfs has unusual semantics.
+ *
+ * The Smack value of the task is appended to the link string.
+ * Thus, if a task labeled "Gentoo" does chdir("/smack/tmp")
+ * it will use "/moldy/Gentoo".
+ *
+ * The expected usage is the /tmp is a symlink to /smack/tmp
+ * which is itself a symlink to /moldy. /moldy should have a
+ * directory for each label in use to accomodate the value
+ * appended on the redirection.
+ *
+ * An interesting addition would be a file system that automatically
+ * creates directories as needed, at the appropriate label.
+ */
+static void *smackfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ char *sp = current->security;
+ char *cp;
+ int inum = dentry->d_inode->i_ino;
+ struct smk_link *slp;
+
+ for (slp = smk_links; slp != NULL; slp = slp->sl_next)
+ if (slp->sl_inum == inum)
+ break;
+
+ if (slp == NULL) {
+ printk("%s:%d failed\n", __func__, __LINE__);
+ return NULL;
+ }
+ cp = kzalloc(SMK_TMPPATH_SIZE, GFP_KERNEL);
+ if (cp == NULL)
+ return NULL;
+
+ strcpy(cp, slp->sl_target);
+ strcat(cp, sp);
+ nd_set_link(nd, cp);
+ /*
+ * Unlike the readlink below, hang on to the memory allocated
+ * because nd_set_link passes it along.
+ */
+ return NULL;
+}
+
+/**
+ * smackfs_readlink - read a smackfs symlink
+ * @dentry: name cache entry
+ * @buffer: where the result goes
+ * @buflen: buffer size
+ *
+ * Returns 0 on success, an error code otherwise
+ *
+ * Supports the same semantics as the follow code.
+ */
+static int smackfs_readlink(struct dentry *dentry, char __user *buffer,
+ int buflen)
+{
+ char *csp = current->security;
+ char *cp;
+ int len;
+ int inum = dentry->d_inode->i_ino;
+ struct smk_link *slp;
+
+ for (slp = smk_links; slp != NULL; slp = slp->sl_next)
+ if (slp->sl_inum == inum)
+ break;
+
+ if (slp == NULL) {
+ printk("%s:%d failed\n", __func__, __LINE__);
+ return -EACCES;
+ }
+
+ cp = kzalloc(SMK_TMPPATH_SIZE, GFP_KERNEL);
+ if (cp == NULL)
+ return -ENOMEM;
+
+ strcpy(cp, slp->sl_target);
+ strcat(cp, csp);
+ len = strlen(cp);
+ len = (len > buflen) ? buflen : len;
+
+ if (copy_to_user(buffer, cp, len) != 0)
+ len = -EFAULT;
+
+ kfree(cp);
+ return len;
+}
+
+/**
+ * smackfs_put_link - free a followed component
+ * @dentry: unused
+ * @nd: name entry
+ * @ptr: unused
+ *
+ * free the buffer used in following the link.
+ */
+static void smackfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+{
+ kfree(nd_get_link(nd));
+}
+
+static struct inode_operations smackfs_symlink_inode_operations = {
+ .readlink = smackfs_readlink,
+ .follow_link = smackfs_follow_link,
+ .put_link = smackfs_put_link,
+};
+
+/**
+ * smk_add_symlink - follow a smackfs symlink
+ * @name: the name of the synlink
+ * @target: where it points to
+ *
+ * Add a smackfs symlink
+ */
+static void smk_add_symlink(char *name, char *target)
+{
+ static int inum = SMK_TMP;
+ struct inode *inode;
+ struct dentry *dentry;
+ struct smk_link *slp;
+
+ for (slp = smk_links; slp != NULL; slp = slp->sl_next) {
+ if (strcmp(slp->sl_name, name) != 0)
+ continue;
+ strcpy(slp->sl_target, target);
+ return;
+ }
+
+ slp = kzalloc(sizeof(struct smk_link), GFP_KERNEL);
+ if (slp == NULL)
+ return;
+
+ dentry = d_alloc_name(smk_sb->s_root, name);
+ if (dentry == NULL) {
+ printk("%s:%d link dentry failed\n", __func__, __LINE__);
+ return;
+ }
+
+ inode = new_inode(smk_sb);
+ if (inode == NULL) {
+ printk("%s:%d link inode failed\n", __func__, __LINE__);
+ return;
+ }
+
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_blocks = 0;
+ inode->i_atime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime;
+ inode->i_ctime = inode->i_atime;
+ inode->i_ino = inum++;
+ inode->i_op = &smackfs_symlink_inode_operations;
+ d_add(dentry, inode);
+
+ strcpy(slp->sl_name, name);
+ strcpy(slp->sl_target, target);
+ slp->sl_inum = inode->i_ino;
+ slp->sl_next = smk_links;
+ smk_links = slp;
+ smk_links_count++;
+
+ return;
+}
+
+/**
+ * smk_read_links - read() for /smack/links
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_links(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t bytes = sizeof(struct smk_link) * smk_links_count;
+ struct smk_link *slp;
+ char *result;
+ char *cp;
+
+
+ result = kzalloc(bytes, GFP_KERNEL);
+ if (result == NULL)
+ return -ENOMEM;
+ *result = '\0';
+
+ for (slp = smk_links, cp = result; slp != NULL; slp = slp->sl_next)
+ cp += sprintf(cp, "%s %s\n", slp->sl_name, slp->sl_target);
+
+ bytes = simple_read_from_buffer(buf,count,ppos,result,strlen(result));
+
+ kfree(result);
+
+ return bytes;
+}
+
+/**
+ * smk_write_links - write() for /smack/links
+ * @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
+ *
+ * This might be better done using "real" symlink creation.
+ */
+static ssize_t smk_write_links(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t rc = count;
+ char *data;
+ char *cp;
+ char name[SMK_TMPPATH_SIZE];
+ char target[SMK_TMPPATH_SIZE];
+
+ /*
+ * No partial writes.
+ */
+ if (*ppos != 0)
+ return -EINVAL;
+ /*
+ * 80 characters per line ought to be enough.
+ */
+ if (count > SMACK_LIST_MAX * 80)
+ return -ENOMEM;
+
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ kfree(data);
+ return -EFAULT;
+ }
+
+ data[count] = '\0';
+
+ for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
+ if (*++cp == '\0')
+ break;
+ if (sscanf(cp, "%14s %30s\n", name, target) != 2) {
+ printk("%s:%d bad scan\n",
+ __func__, __LINE__);
+ break;
+ }
+ smk_add_symlink(name, target);
+ printk("%s:%d add %s -> %s\n",
+ __func__, __LINE__, name, target);
+ }
+
+ kfree(data);
+ return rc;
+}
+
+static const struct file_operations smk_links_ops = {
+ .read = smk_read_links,
+ .write = smk_write_links,
+};
+
+/**
+ * smk_fill_super - fill the /smackfs superblock
+ * @sb: the empty superblock
+ * @data: unused
+ * @silent: unused
+ *
+ * Fill in the well known entries for /smack and set up for
+ * symlinks
+ *
+ * Returns 0 on success, an error code on failure
+ */
+static int smk_fill_super(struct super_block *sb, void * data, int silent)
+{
+ int rc;
+ struct inode *root_inode;
+
+ static struct tree_descr smack_files[] = {
+ [SMK_LOAD] = {"load", &smk_load_ops, S_IRUGO|S_IWUSR},
+ [SMK_LINKS] = {"links", &smk_links_ops, S_IRUGO|S_IWUSR},
+ [SMK_CIPSO] = {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
+ [SMK_DOI] = {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
+ [SMK_DIRECT] = {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
+ [SMK_AMBIENT] = {"ambient", &smk_ambient_ops,S_IRUGO|S_IWUSR},
+ [SMK_NLTYPE] = {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
+ /* last one */ {""}
+ };
+
+ /*
+ * There will be only one smackfs. Casey says so.
+ */
+ smk_sb = sb;
+
+ rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);
+ if (rc != 0) {
+ printk(KERN_ERR "%s failed %d while creating inodes\n",
+ __func__, rc);
+ return rc;
+ }
+
+ root_inode = sb->s_root->d_inode;
+ root_inode->i_security = new_inode_smack(smack_known_floor.smk_known);
+
+ /*
+ * Create a directory for /smack/tmp
+ */
+ smk_add_symlink("tmp", SMK_TMPPATH_ROOT);
+
+ return 0;
+}
+
+/**
+ * smk_get_sb - get the smackfs superblock
+ * @fs_type: passed along without comment
+ * @flags: passed along without comment
+ * @dev_name: passed along without comment
+ * @data: passed along without comment
+ * @mnt: passed along without comment
+ *
+ * Just passes everything along.
+ *
+ * Returns what the lower level code does.
+ */
+static int smk_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, data, smk_fill_super, mnt);
+}
+
+static struct file_system_type smk_fs_type = {
+ .name = "smackfs",
+ .get_sb = smk_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+static struct vfsmount *smackfs_mount;
+
+/**
+ * init_smk_fs - get the smackfs superblock
+ *
+ * register the smackfs
+ *
+ * Returns 0 unless the registration fails.
+ */
+static int __init init_smk_fs(void)
+{
+ int err;
+
+ err = register_filesystem(&smk_fs_type);
+ if (!err) {
+ smackfs_mount = kern_mount(&smk_fs_type);
+ if (IS_ERR(smackfs_mount)) {
+ printk(KERN_ERR "smackfs: could not mount!\n");
+ err = PTR_ERR(smackfs_mount);
+ smackfs_mount = NULL;
+ }
+ }
+
+ return err;
+}
+
+__initcall(init_smk_fs);
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smack.h linux-2.6.23-rc8-smack/security/smack/smack.h
--- linux-2.6.23-rc8-base/security/smack/smack.h 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.23-rc8-smack/security/smack/smack.h 2007-09-25 15:30:38.000000000 -0700
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <[email protected]>
+ *
+ * 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, version 2.
+ *
+ * Author:
+ * Casey Schaufler <[email protected]>
+ *
+ */
+
+#ifndef _SECURITY_SMACK_H
+#define _SECURITY_SMACK_H
+
+#include <linux/capability.h>
+#include <linux/spinlock.h>
+#include <net/netlabel.h>
+
+/*
+ * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
+ * bigger than can be used, and 24 is the next lower multiple
+ * of 8, and there are too many issues if there isn't space set
+ * aside for the terminating null byte.
+ */
+#define SMK_MAXLEN 23
+#define SMK_LABELLEN (SMK_MAXLEN+1)
+
+struct superblock_smack {
+ char *smk_root;
+ char *smk_floor;
+ char *smk_hat;
+ char *smk_default;
+ int smk_initialized;
+};
+
+struct socket_smack {
+ char *smk_out; /* outbound label */
+ char *smk_in; /* inbound label */
+ char smk_packet[SMK_LABELLEN];
+ int smk_depth;
+};
+
+/*
+ * Inode smack data
+ */
+struct inode_smack {
+ char *smk_inode; /* label of the fso */
+ struct mutex smk_lock; /* initialization lock */
+ int smk_flags; /* smack inode flags */
+};
+
+#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
+
+/*
+ * A label access rule.
+ */
+struct smack_rule {
+ char *smk_subject;
+ char *smk_object;
+ int smk_access;
+};
+
+/*
+ * An entry in the table of permitted label accesses.
+ */
+struct smk_list_entry {
+ struct smk_list_entry *smk_next;
+ struct smack_rule smk_rule;
+};
+
+/*
+ * An entry in the table mapping smack values to
+ * CIPSO level/category-set values.
+ */
+struct smack_cipso {
+ int smk_level;
+ char smk_catset[SMK_LABELLEN];
+};
+
+/*
+ * This is the repository for labels seen so that it is
+ * not necessary to keep allocating tiny chuncks of memory
+ * and so that they can be shared.
+ *
+ * Labels are never modified in place. Anytime a label
+ * is imported (e.g. xattrset on a file) the list is checked
+ * for it and it is added if it doesn't exist. The address
+ * is passed out in either case. Entries are added, but
+ * never deleted.
+ *
+ * Since labels are hanging around anyway it doesn't
+ * hurt to maintain a secid for those awkward situations
+ * where kernel components that ought to use LSM independent
+ * interfaces don't. The secid should go away when all of
+ * these components have been repaired.
+ *
+ * If there is a cipso value associated with the label it
+ * gets stored here, too. This will most likely be rare as
+ * the cipso direct mapping in used internally.
+ */
+struct smack_known {
+ struct smack_known *smk_next;
+ char smk_known[SMK_LABELLEN];
+ u32 smk_secid;
+ struct smack_cipso *smk_cipso;
+ spinlock_t smk_cipsolock;
+};
+
+/*
+ * Mount options
+ */
+#define SMK_FSDEFAULT "smackfsdef="
+#define SMK_FSFLOOR "smackfsfloor="
+#define SMK_FSHAT "smackfshat="
+#define SMK_FSROOT "smackfsroot="
+
+/*
+ * xattr names
+ */
+#define XATTR_SMACK_SUFFIX "SMACK64"
+#define XATTR_SMACK_IPIN "SMACK64IPIN"
+#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
+#define XATTR_SMACK_PACKET "SMACK64PACKET"
+#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+
+/*
+ * smackfs macic number
+ */
+#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
+
+/*
+ * A limit on the number of entries in the lists
+ * makes some of the list administration easier.
+ */
+#define SMACK_LIST_MAX 10000
+
+/*
+ * CIPSO defaults.
+ */
+#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
+#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */
+#define SMACK_CIPSO_MAXCAT 63 /* Bigger gets harder */
+
+/*
+ * Just to make the common cases easier to deal with
+ */
+#define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+#define MAY_ANYREAD (MAY_READ | MAY_EXEC)
+#define MAY_ANYWRITE (MAY_WRITE | MAY_APPEND)
+#define MAY_READWRITE (MAY_READ | MAY_WRITE)
+#define MAY_NOT 0
+
+/*
+ * There are not enough CAP bits available to make this
+ * real, so Casey borrowed the capability that looks to
+ * him like it has the best balance of similarity amd
+ * low use.
+ */
+#define CAP_MAC_OVERRIDE CAP_LINUX_IMMUTABLE
+
+/*
+ * These functions are in smackfs.c
+ */
+void smk_cipso_doi(void);
+
+/*
+ * These functions are in smack_lsm.c
+ */
+struct inode_smack *new_inode_smack(char *);
+
+/*
+ * These functions are in smack_access.c
+ */
+int smk_access(char *, char *, int);
+int smk_curacc(char *, u32);
+int smack_to_cipso(const char *, struct smack_cipso *);
+void smack_from_cipso(u32, char *, char *);
+char *smack_from_secid(const u32);
+char *smk_import(const char *, int);
+struct smack_known *smk_import_entry(const char *, int);
+u32 smack_to_secid(const char *);
+
+/*
+ * Stricly for CIPSO level manipulation.
+ * Set the category bit number in a smack label sized buffer.
+ */
+static inline void smack_catset_bit(int cat, char *catsetp)
+{
+ char *cp = (char *)catsetp;
+
+ if (cat > SMK_LABELLEN * 8)
+ return;
+
+ cp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
+}
+
+/*
+ * Present a pointer to the smack label in an inode blob.
+ */
+static inline char *smk_of_inode(const struct inode *isp)
+{
+ struct inode_smack *sip = isp->i_security;
+ return sip->smk_inode;
+}
+
+#endif /* _SECURITY_SMACK_H */
diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smack_lsm.c linux-2.6.23-rc8-smack/security/smack/smack_lsm.c
--- linux-2.6.23-rc8-base/security/smack/smack_lsm.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.23-rc8-smack/security/smack/smack_lsm.c 2007-09-25 15:30:38.000000000 -0700
@@ -0,0 +1,2685 @@
+/*
+ * Simplified MAC Kernel (smack) security module
+ *
+ * This file contains the smack hook function implementations.
+ *
+ * Author:
+ * Casey Schaufler <[email protected]>
+ *
+ * Copyright (C) 2007 Casey Schaufler <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/xattr.h>
+#include <linux/pagemap.h>
+#include <linux/mount.h>
+#include <linux/stat.h>
+#include <linux/ext2_fs.h>
+#include <linux/kd.h>
+#include <asm/ioctls.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/mutex.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "smack.h"
+
+/*
+ * I hope these are the hokeyist lines of code in the module. Casey.
+ */
+#define DEVPTS_SUPER_MAGIC 0x1cd1
+#define SOCKFS_MAGIC 0x534F434B
+#define PIPEFS_MAGIC 0x50495045
+#define TMPFS_MAGIC 0x01021994
+
+/*
+ * These are in smack_access.c
+ */
+extern struct smack_known smack_known_unset;
+extern struct smack_known smack_known_huh;
+extern struct smack_known smack_known_hat;
+extern struct smack_known smack_known_star;
+extern struct smack_known smack_known_floor;
+extern struct smack_known smack_known_invalid;
+
+/*
+ * These are maintained in smackfs.c
+ */
+extern char *smack_net_ambient;
+extern int smack_net_nltype;
+extern int smack_cipso_direct;
+
+/**
+ * smk_fetch - Fetch the smack label from a file.
+ * @ip: a pointer to the inode
+ * @dp: a pointer to the dentry
+ *
+ * Returns a pointer to the master list entry for the Smack label
+ * or NULL if there was no label to fetch.
+ */
+static char *smk_fetch(struct inode *ip, struct dentry *dp)
+{
+ int rc;
+ char in[SMK_LABELLEN];
+
+ if (ip->i_op->getxattr == NULL)
+ return NULL;
+
+ rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, in, SMK_LABELLEN);
+ if (rc < 0)
+ return NULL;
+
+ return smk_import(in, rc);
+}
+
+/**
+ * new_inode_smack - allocate an inode security blob
+ * @smack: a pointer to the Smack label to use in the blob
+ *
+ * Returns the new blob or NULL if there's no memory available
+ */
+struct inode_smack *new_inode_smack(char *smack)
+{
+ struct inode_smack *isp;
+
+ isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL);
+ if (isp == NULL)
+ return NULL;
+
+ isp->smk_inode = smack;
+ isp->smk_flags = 0;
+ mutex_init(&isp->smk_lock);
+
+ return isp;
+}
+
+/*
+ * LSM hooks.
+ * We he, that is fun!
+ */
+
+/**
+ * smack_ptrace - Smack approval on ptrace
+ * @ptp: parent task pointer
+ * @ctp: child task pointer
+ *
+ * Returns 0 if access is OK, an error code otherwise
+ *
+ * Do the capability checks, and require read and write.
+ */
+static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp)
+{
+ int rc;
+
+ rc = cap_ptrace(ptp, ctp);
+ if (rc != 0)
+ return rc;
+
+ rc = smk_access(ptp->security, ctp->security, MAY_READWRITE);
+ if (rc != 0 && __capable(ptp, CAP_MAC_OVERRIDE))
+ return 0;
+
+ return rc;
+}
+
+/**
+ * smack_syslog - Smack approval on syslog
+ * @type: message type
+ *
+ * Require that the task has the floor label
+ *
+ * Returns 0 on success, error code otherwise.
+ */
+static int smack_syslog(int type)
+{
+ int rc;
+ char *sp = current->security;
+
+ rc = cap_syslog(type);
+ if (rc != 0)
+ return rc;
+
+ if (__capable(current, CAP_MAC_OVERRIDE))
+ return 0;
+
+ if (sp != smack_known_floor.smk_known)
+ rc = -EACCES;
+
+ return rc;
+}
+
+/**
+ * smack_task_alloc_security - "allocate" a task blob
+ * @tsk: the task in need of a blob
+ *
+ * Smack isn't using copies of blobs. Everyone
+ * points to an immutible list. No alloc required.
+ * No data copy required.
+ *
+ * Always returns 0
+ */
+static int smack_task_alloc_security(struct task_struct *tsk)
+{
+ tsk->security = current->security;
+
+ return 0;
+}
+
+/**
+ * smack_task_free_security - "free" a task blob
+ * @task: the task with the blob
+ *
+ * Smack isn't using copies of blobs. Everyone
+ * points to an immutible list. The blobs never go away.
+ * There is no leak here.
+ */
+static void smack_task_free_security(struct task_struct *task)
+{
+ task->security = NULL;
+}
+
+/**
+ * smack_task_setpgid - Smack check on setting pgid
+ * @p: the task object
+ * @pgid: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_setnice - Smack check on setting nice
+ * @p: the task object
+ * @nice: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setnice(struct task_struct *p, int nice)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_setioprio - Smack check on setting ioprio
+ * @p: the task object
+ * @ioprio: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setioprio(struct task_struct *p, int ioprio)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getioprio - Smack check on reading ioprio
+ * @p: the task object
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_getioprio(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_setscheduler - Smack check on setting scheduler
+ * @p: the task object
+ * @policy: unused
+ * @lp: unused
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_setscheduler(struct task_struct *p, int policy,
+ struct sched_param *lp)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getscheduler - Smack check on reading scheduler
+ * @p: the task object
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_getscheduler(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_movememory - Smack check on moving memory
+ * @p: the task object
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_movememory(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_kill - Samck check on signal delivery
+ * @p: the task object
+ * @info: unused
+ * @sig: unused
+ * @secid: identifies the smack to use in lieu of current's
+ *
+ * Return 0 if write access is permitted
+ *
+ * The secid behavior is an artifact of an SELinux hack
+ * in the USB code. Someday it may go away.
+ */
+static int smack_task_kill(struct task_struct *p, struct siginfo *info,
+ int sig, u32 secid)
+{
+ /*
+ * Sending a signal requires that the sender
+ * can write the receiver.
+ */
+ if (secid == 0)
+ return smk_curacc(p->security, MAY_WRITE);
+ /*
+ * If the secid isn't 0 we're dealing with some USB IO
+ * specific behavior. This is not clean. For one thing
+ * we can't take privilege into account.
+ */
+ return smk_access(smack_from_secid(secid), p->security, MAY_WRITE);
+}
+
+/*
+ * Superblock Hooks.
+ */
+
+/**
+ * smack_sb_alloc_security - allocate a superblock blob
+ * @sb: the superblock getting the blob
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_sb_alloc_security(struct super_block *sb)
+{
+ struct superblock_smack *sbsp;
+
+ sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
+
+ if (sbsp == NULL)
+ return -ENOMEM;
+
+ sbsp->smk_root = smack_known_floor.smk_known;
+ sbsp->smk_default = smack_known_floor.smk_known;
+ sbsp->smk_floor = smack_known_floor.smk_known;
+ sbsp->smk_hat = smack_known_hat.smk_known;
+ sbsp->smk_initialized = 0;
+
+ sb->s_security = sbsp;
+
+ return 0;
+}
+
+/**
+ * smack_sb_free_security - free a superblock blob
+ * @sb: the superblock getting the blob
+ *
+ */
+static void smack_sb_free_security(struct super_block *sb)
+{
+ kfree(sb->s_security);
+ sb->s_security = NULL;
+}
+
+/**
+ * smack_sb_copy_data - copy mount options data for processing
+ * @type: file system type
+ * @orig: where to start
+ * @smackopts
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ *
+ * Copy the Smack specific mount options out of the mount
+ * options list.
+ */
+static int smack_sb_copy_data(struct file_system_type *type, void *orig,
+ void *smackopts)
+{
+ char *cp, *commap, *otheropts, *dp;
+
+ /* Binary mount data: just copy */
+ if (type->fs_flags & FS_BINARY_MOUNTDATA) {
+ copy_page(smackopts, orig);
+ return 0;
+ }
+
+ otheropts = (char *)get_zeroed_page(GFP_KERNEL);
+ if (otheropts == NULL)
+ return -ENOMEM;
+
+ for (cp = orig, commap = orig; commap != NULL; cp = commap + 1) {
+ if (strstr(cp, SMK_FSDEFAULT) == cp)
+ dp = smackopts;
+ else if (strstr(cp, SMK_FSFLOOR) == cp)
+ dp = smackopts;
+ else if (strstr(cp, SMK_FSHAT) == cp)
+ dp = smackopts;
+ else if (strstr(cp, SMK_FSROOT) == cp)
+ dp = smackopts;
+ else
+ dp = otheropts;
+
+ commap = strchr(cp, ',');
+ if (commap != NULL)
+ *commap = '\0';
+
+ if (*dp != '\0')
+ strcat(dp, ",");
+ strcat(dp, cp);
+ }
+
+ strcpy(orig, otheropts);
+ free_page((unsigned long)otheropts);
+
+ return 0;
+}
+
+/**
+ * smack_sb_kern_mount - Smack specific mount processing
+ * @sb: the file system superblock
+ * @data: the smack mount options
+ *
+ * Returns 0 on success, an error code on failure
+ */
+static int smack_sb_kern_mount(struct super_block *sb, void *data)
+{
+ int rc;
+ struct dentry *root = sb->s_root;
+ struct inode *inode = root->d_inode;
+ struct superblock_smack *sp = sb->s_security;
+ struct inode_smack *isp;
+ char *op;
+ char *commap;
+ char *nsp;
+
+ if (sp == NULL) {
+ rc = smack_sb_alloc_security(sb);
+ if (rc != 0)
+ return rc;
+ }
+ if (sp->smk_initialized != 0)
+ return 0;
+ if (inode == NULL)
+ return 0;
+
+ sp->smk_initialized = 1;
+
+ for (op = data; op != NULL; op = commap) {
+ commap = strchr(op, ',');
+ if (commap != NULL)
+ *commap++ = '\0';
+
+ if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
+ op += strlen(SMK_FSHAT);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_hat = nsp;
+ } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
+ op += strlen(SMK_FSFLOOR);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_floor = nsp;
+ } else if (strncmp(op,SMK_FSDEFAULT,strlen(SMK_FSDEFAULT))==0) {
+ op += strlen(SMK_FSDEFAULT);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_default = nsp;
+ } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
+ op += strlen(SMK_FSROOT);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_root = nsp;
+ }
+ }
+
+ /*
+ * Initialize the root inode.
+ */
+ isp = inode->i_security;
+ if (isp == NULL)
+ inode->i_security = new_inode_smack(sp->smk_root);
+ else
+ isp->smk_inode = sp->smk_root;
+
+ return 0;
+}
+
+/**
+ * smack_sb_statfs - Smack check on statfs
+ * @dentry: identifies the file system in question
+ *
+ * Returns 0 if current can read the floor of the filesystem,
+ * and error code otherwise
+ */
+static int smack_sb_statfs(struct dentry *dentry)
+{
+ struct superblock_smack *sbp;
+
+ if (dentry == NULL || dentry->d_sb == NULL ||
+ dentry->d_sb->s_security == NULL)
+ return 0;
+
+ sbp = dentry->d_sb->s_security;
+
+ return smk_curacc(sbp->smk_floor, MAY_READ);
+}
+
+/**
+ * smack_sb_mount - Smack check for mounting
+ * @dev_name: unused
+ * @nd: mount point
+ * @type: unused
+ * @flags: unused
+ * @data: unused
+ *
+ * Returns 0 if current can write the floor of the filesystem
+ * being mounted on, an error code otherwise.
+ */
+static int smack_sb_mount(char *dev_name, struct nameidata *nd,
+ char *type, unsigned long flags, void *data)
+{
+ struct superblock_smack *sbp;
+
+ if (nd == NULL || nd->mnt == NULL || nd->mnt->mnt_sb == NULL ||
+ nd->mnt->mnt_sb->s_security == NULL)
+ return 0;
+
+ sbp = nd->mnt->mnt_sb->s_security;
+
+ return smk_curacc(sbp->smk_floor, MAY_WRITE);
+}
+
+/**
+ * smack_sb_umount - Smack check for unmounting
+ * @mnt: file system to unmount
+ * @flags: unused
+ *
+ * Returns 0 if current can write the floor of the filesystem
+ * being unmounted, an error code otherwise.
+ */
+static int smack_sb_umount(struct vfsmount *mnt, int flags)
+{
+ struct superblock_smack *sbp;
+
+ sbp = mnt->mnt_sb->s_security;
+
+ return smk_curacc(sbp->smk_floor, MAY_WRITE);
+}
+
+/*
+ * Inode hooks
+ */
+
+/**
+ * smack_inode_alloc_security - allocate an inode blob
+ * @inode - the inode in need of a blob
+ *
+ * Returns 0 if it gets a blob, -ENOMEM otherwise
+ */
+static int smack_inode_alloc_security(struct inode *inode)
+{
+ inode->i_security = new_inode_smack(current->security);
+ if (inode->i_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * smack_inode_free_security - free an inode blob
+ * @inode - the inode with a blob
+ *
+ * Clears the blob pointer in inode
+ */
+static void smack_inode_free_security(struct inode *inode)
+{
+ kfree(inode->i_security);
+ inode->i_security = NULL;
+}
+
+/**
+ * smack_inode_init_security - copy out the smack from an inode
+ * @inode: the inode
+ * @dir: unused
+ * @name: where to put the attribute name
+ * @value: where to put the attribute value
+ * @len: where to put the length of the attribute
+ *
+ * Returns 0 if it all works out, -ENOMEM if there's no memory
+ */
+static int smack_inode_init_security(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len)
+{
+ char *isp = smk_of_inode(inode);
+
+ if (name) {
+ *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
+ if (*name == NULL)
+ return -ENOMEM;
+ }
+
+ if (value) {
+ *value = kstrdup(isp, GFP_KERNEL);
+ if (*value == NULL)
+ return -ENOMEM;
+ }
+
+ if (len)
+ *len = strlen(isp) + 1;
+
+ return 0;
+}
+
+/**
+ * smack_inode_link - Smack check on link
+ * @old_dentry: unused
+ * @dir: the directory with the entry to change
+ * @new_dentry: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *new_dentry)
+{
+ return smk_curacc(smk_of_inode(dir), MAY_WRITE);
+}
+
+/**
+ * smack_inode_symlink - Smack check on symlink
+ * @dir: the directory to add the entry to
+ * @dentry: unused
+ * @name: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_symlink(struct inode *dir, struct dentry *dentry,
+ const char *name)
+{
+ return smk_curacc(smk_of_inode(dir), MAY_WRITE);
+}
+
+/**
+ * smack_inode_mknod - Smack check on mknod
+ * @dir: the directory to add the entry to
+ * @dentry: unused
+ * @mode: unused
+ * @dev: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_mknod(struct inode *dir, struct dentry *dentry,
+ int mode, dev_t dev)
+{
+ return smk_curacc(smk_of_inode(dir), MAY_WRITE);
+}
+
+/**
+ * smack_inode_rename - Smack check on rename
+ * @old_inode: the old directory
+ * @old_dentry: unused
+ * @new_inode: the new directory
+ * @new_dentry: unused
+ *
+ * Read and write access is required on both the old and
+ * new directories.
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_rename(struct inode *old_inode,
+ struct dentry *old_dentry,
+ struct inode *new_inode,
+ struct dentry *new_dentry)
+{
+ int rc;
+
+ rc = smk_curacc(smk_of_inode(old_inode), MAY_READWRITE);
+ if (rc == 0)
+ rc = smk_curacc(smk_of_inode(new_inode), MAY_READWRITE);
+ return rc;
+}
+
+/**
+ * smack_inode_readlink - Smack check on readlink
+ * @dentry: the symlink
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_readlink(struct dentry *dentry)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/**
+ * smack_inode_follow_link - Smack check on following a symlink
+ * @dentry: the symlink
+ * @nameidata: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_follow_link(struct dentry *dentry,
+ struct nameidata *nameidata)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/**
+ * smack_inode_permission - Smack version of permission()
+ * @inode: the inode in question
+ * @mask: the access requested
+ * @nd: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ /*
+ * No permission to check. Existence test. Yup, it's there.
+ */
+ if (mask == 0)
+ return 0;
+
+ return smk_curacc(smk_of_inode(inode), mask);
+}
+
+/**
+ * smack_inode_setattr - Smack check for setting attributes
+ * @dentry: the object
+ * @iattr: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+}
+
+/**
+ * smack_inode_getattr - Smack check for getting attributes
+ * @mnt: unused
+ * @dentry: the object
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/**
+ * smack_inode_setxattr - Smack check for setting xattrs
+ * @dentry: the object
+ * @name: passed to the cap call
+ * @value: passed to the cap call
+ * @size: passed to the cap call
+ * @flags: passed to the cap call
+ *
+ * Check with cap_inode_setxattr to see if the capability
+ * scheme approves, then check the Smack access
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_setxattr(struct dentry *dentry, char *name,
+ void *value, size_t size, int flags)
+{
+ int rc;
+
+ if (strcmp(name, XATTR_NAME_SMACK) == 0 &&
+ !__capable(current, CAP_MAC_OVERRIDE))
+ return -EPERM;
+
+ rc = cap_inode_setxattr(dentry, name, value, size, flags);
+ if (rc == 0)
+ rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+
+ return rc;
+}
+
+/**
+ * smack_inode_post_setxattr - Apply the Smack update approved above
+ * @dentry: object
+ * @name: attribute name
+ * @value: attribute value
+ * @size: attribute size
+ * @flags: unused
+ *
+ * Set the pointer in the inode blob to the entry found
+ * in the master label list.
+ */
+static void smack_inode_post_setxattr(struct dentry *dentry, char *name,
+ void *value, size_t size, int flags)
+{
+ struct inode_smack *isp;
+ char *nsp;
+
+ /*
+ * Not SMACK
+ */
+ if (strcmp(name, XATTR_NAME_SMACK))
+ return;
+
+ if (size >= SMK_LABELLEN)
+ return;
+
+ isp = dentry->d_inode->i_security;
+
+ /*
+ * No locking is done here. This is a pointer
+ * assignment.
+ */
+ nsp = smk_import(value, size);
+ if (nsp != NULL)
+ isp->smk_inode = nsp;
+ else
+ isp->smk_inode = smack_known_invalid.smk_known;
+
+ return;
+}
+
+/*
+ * smack_inode_getxattr - Smack check on getxattr
+ * @dentry: the object
+ * @name: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_getxattr(struct dentry *dentry, char *name)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/*
+ * smack_inode_listxattr - Smack check on listxattr
+ * @dentry: the object
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_listxattr(struct dentry *dentry)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/*
+ * smack_inode_removexattr - Smack check on removexattr
+ * @dentry: the object
+ * @name: name of the attribute
+ *
+ * Removing the Smack attribute requires CAP_MAC_OVERRIDE
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_removexattr(struct dentry *dentry, char *name)
+{
+ int rc;
+
+ if (strcmp(name, XATTR_NAME_SMACK) == 0 &&
+ !__capable(current, CAP_MAC_OVERRIDE))
+ return -EPERM;
+
+ rc = cap_inode_removexattr(dentry, name);
+ if (rc == 0)
+ rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+
+ return rc;
+}
+
+/**
+ * smack_inode_getsecurity - get smack xattrs
+ * @inode: the object
+ * @name: attribute name
+ * @buffer: where to put the result
+ * @size: size of the buffer
+ * @err: unused
+ *
+ * Returns the size of the attribute or an error code
+ */
+static int smack_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+{
+ struct socket_smack *ssp;
+ struct socket *sock;
+ struct super_block *sbp;
+ struct inode *ip = (struct inode *)inode;
+ char *bsp = buffer;
+ char *isp;
+
+ if (size < SMK_LABELLEN || name == NULL || bsp == NULL ||
+ inode == NULL || inode->i_security == NULL)
+ return 0;
+
+ if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+ isp = smk_of_inode(inode);
+ strncpy(buffer, isp, SMK_LABELLEN);
+ return strlen(isp) + 1;
+ }
+
+ /*
+ * The rest of the Smack xattrs are only on sockets.
+ */
+ sbp = ip->i_sb;
+ if (sbp->s_magic != SOCKFS_MAGIC)
+ return -EOPNOTSUPP;
+
+ sock = SOCKET_I(ip);
+ if (sock == NULL)
+ return -EOPNOTSUPP;
+
+ ssp = sock->sk->sk_security;
+
+ /*
+ * Should the packet attribute be unavailable return the error.
+ * This can happen if packets come in too fast.
+ */
+ if (strcmp(name, XATTR_SMACK_PACKET) == 0) {
+ if (ssp->smk_packet[0] == '\0')
+ return -ENODATA;
+ isp = ssp->smk_packet;
+ }
+ else if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+ isp = ssp->smk_in;
+ else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
+ isp = ssp->smk_out;
+ else
+ return -EOPNOTSUPP;
+
+ strncpy(buffer, isp, SMK_LABELLEN);
+ return strlen(isp) + 1;
+}
+
+/**
+ * smack_inode_setsecurity - set smack xattrs
+ * @inode: the object
+ * @name: attribute name
+ * @value: attribute value
+ * @size: size of the attribute
+ * @flags: unused
+ *
+ * Sets the named attribute in the appropriate blob
+ *
+ * Returns 0 on success, or an error code
+ */
+static int smack_inode_setsecurity(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ char *sp;
+ struct inode_smack *nsp = (struct inode_smack *)inode->i_security;
+ struct socket_smack *ssp;
+ struct socket *sock;
+
+ if (value == NULL || size > SMK_LABELLEN)
+ return -EACCES;
+
+ sp = smk_import(value, size);
+ if (sp == NULL)
+ return -EINVAL;
+
+ if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+ mutex_lock(&nsp->smk_lock);
+ nsp->smk_inode = sp;
+ mutex_unlock(&nsp->smk_lock);
+ return 0;
+ }
+ /*
+ * The rest of the Smack xattrs are only on sockets.
+ */
+ if (inode->i_sb->s_magic != SOCKFS_MAGIC)
+ return -EOPNOTSUPP;
+
+ sock = SOCKET_I(inode);
+ if (sock == NULL)
+ return -EOPNOTSUPP;
+
+ ssp = sock->sk->sk_security;
+
+ if (strcmp(name, XATTR_SMACK_PACKET) == 0) {
+ memset(ssp->smk_packet, '\0', SMK_LABELLEN);
+ strncpy(ssp->smk_packet, sp, SMK_LABELLEN);
+ }
+ else if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+ ssp->smk_in = sp;
+ else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
+ ssp->smk_out = sp;
+ else
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+/**
+ * smack_inode_listsecurity - list the Smack attributes
+ * @inode: the object
+ * @buffer: where they go
+ * @buffer_size: size of buffer
+ *
+ * Returns 0 on success, -EINVAL otherwise
+ */
+static int smack_inode_listsecurity(struct inode *inode, char *buffer,
+ size_t buffer_size)
+{
+ int len = strlen(XATTR_NAME_SMACK);
+
+ if (buffer != NULL && len <= buffer_size) {
+ memcpy(buffer, XATTR_NAME_SMACK, len);
+ return len;
+ }
+ return -EINVAL;
+}
+
+/**
+ * smack_d_instantiate - Make sure the blob is correct on an inode
+ * @opt_dentry: unused
+ * @inode: the object
+ *
+ * Set the inode's security blob if it hasn't been done already.
+ */
+static void smack_d_instantiate (struct dentry *opt_dentry, struct inode *inode)
+{
+ struct super_block *sbp;
+ struct superblock_smack *sbsp;
+ struct inode_smack *isp;
+ char *csp = current->security;
+ char *fetched;
+ char *final;
+ struct dentry *dp;
+
+ if (inode == NULL)
+ return;
+
+ if (inode->i_security == NULL)
+ inode->i_security =
+ new_inode_smack(smack_known_unset.smk_known);
+
+ isp = inode->i_security;
+
+ mutex_lock(&isp->smk_lock);
+ /*
+ * If the inode is already instantiated
+ * take the quick way out
+ */
+ if (isp->smk_flags & SMK_INODE_INSTANT)
+ goto unlockandout;
+
+ sbp = inode->i_sb;
+ sbsp = sbp->s_security;
+ /*
+ * We're going to use the superblock default label
+ * if there's no label on the file.
+ */
+ final = sbsp->smk_default;
+
+ /*
+ * This is pretty hackish.
+ * Casey says that we shouldn't have to do
+ * file system specific code, but it does help
+ * with keeping it simple.
+ */
+ switch (sbp->s_magic) {
+ case SMACK_MAGIC:
+ /*
+ * Casey says that it's a little embarassing
+ * that the smack file system doesn't do
+ * extended attributes.
+ */
+ final = smack_known_star.smk_known;
+ break;
+ case PIPEFS_MAGIC:
+ /*
+ * Casey says pipes are easy (?)
+ */
+ final = smack_known_star.smk_known;
+ break;
+ case DEVPTS_SUPER_MAGIC:
+ /*
+ * devpts seems content with the label of the task.
+ * Programs that change smack have to treat the
+ * pty with respect.
+ */
+ final = csp;
+ break;
+ case SOCKFS_MAGIC:
+ /*
+ * Casey says sockets get the smack of the task.
+ */
+ final = csp;
+ break;
+ case PROC_SUPER_MAGIC:
+ /*
+ * Casey says procfs appears not to care.
+ * The superblock default suffices.
+ */
+ break;
+ case TMPFS_MAGIC:
+ /*
+ * Device labels should come from the filesystem,
+ * but watch out, because they're volitile,
+ * getting recreated on every reboot.
+ */
+ final = smack_known_star.smk_known;
+ /*
+ * No break.
+ *
+ * If a smack value has been set we want to use it,
+ * but since tmpfs isn't giving us the opportunity
+ * to set mount options simulate setting the
+ * superblock default.
+ */
+ default:
+ /*
+ * This isn't an understood special case.
+ * Get the value from the xattr.
+ *
+ * No xattr support means, alas, no SMACK label.
+ * Use the aforeapplied default.
+ * It would be curious if the label of the task
+ * does not match that assigned.
+ */
+ if (inode->i_op->getxattr == NULL)
+ break;
+ /*
+ * Get the dentry for xattr.
+ */
+ if (opt_dentry == NULL) {
+ dp = d_find_alias(inode);
+ if (dp == NULL)
+ break;
+ } else {
+ dp = dget(opt_dentry);
+ if (dp == NULL)
+ break;
+ }
+
+ fetched = smk_fetch(inode, dp);
+ if (fetched != NULL)
+ final = fetched;
+
+ dput(dp);
+ break;
+ }
+
+ if (final == NULL)
+ isp->smk_inode = csp;
+ else
+ isp->smk_inode = final;
+
+ isp->smk_flags |= SMK_INODE_INSTANT;
+
+unlockandout:
+ mutex_unlock(&isp->smk_lock);
+ return;
+}
+
+/*
+ * File Hooks
+ */
+
+/**
+ * smack_file_alloc_security - assign a file security blob
+ * @file: the object
+ *
+ * The security blob for a file is a pointer to the master
+ * label list, so no allocation is done.
+ *
+ * Returns 0
+ */
+static int smack_file_alloc_security(struct file *file)
+{
+ file->f_security = current->security;
+ return 0;
+}
+
+/**
+ * smack_file_free_security - clear a file security blob
+ * @file: the object
+ *
+ * The security blob for a file is a pointer to the master
+ * label list, so no memory is freed.
+ */
+static void smack_file_free_security(struct file *file)
+{
+ file->f_security = NULL;
+}
+
+/**
+ * smack_file_permission - Smack check on file operations
+ * @file: unused
+ * @mask: unused
+ *
+ * Returns 0
+ *
+ * Should access checks be done on each read or write?
+ * UNICOS and SELinux say yes.
+ * Trusted Solaris, Trusted Irix, and just about everyone else says no.
+ *
+ * I'll say no for now. Smack does not do the frequent
+ * label changing that SELinux does.
+ */
+static int smack_file_permission(struct file *file, int mask)
+{
+ return 0;
+}
+
+/**
+ * smack_file_ioctl - Smack check on ioctls
+ * @file: the object
+ * @cmd: what to do
+ * @arg: unused
+ *
+ * Relies heavily on the correct use of the ioctl command conventions.
+ *
+ * Returns 0 if allowed, error code otherwise
+ */
+static int smack_file_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ rc = smk_curacc(file->f_security, MAY_WRITE);
+
+ if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
+ rc = smk_curacc(file->f_security, MAY_READ);
+
+ return rc;
+}
+
+/**
+ * smack_file_lock - Smack check on file locking
+ * @file: the object
+ * @cmd unused
+ *
+ * Returns 0 if current has write access, error code otherwise
+ */
+static int smack_file_lock(struct file *file, unsigned int cmd)
+{
+ return smk_curacc(file->f_security, MAY_WRITE);
+}
+
+/**
+ * smack_file_fcntl - Smack check on fcntl
+ * @file: the object
+ * @cmd: what action to check
+ * @arg: unused
+ *
+ * Returns 0 if current has access, error code otherwise
+ */
+static int smack_file_fcntl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+
+ switch (cmd) {
+ case F_DUPFD:
+ case F_GETFD:
+ case F_GETFL:
+ case F_GETLK:
+ case F_GETOWN:
+ case F_GETSIG:
+ rc = smk_curacc(file->f_security, MAY_READ);
+ break;
+ case F_SETFD:
+ case F_SETFL:
+ case F_SETLK:
+ case F_SETLKW:
+ case F_SETOWN:
+ case F_SETSIG:
+ rc = smk_curacc(file->f_security, MAY_WRITE);
+ break;
+ default:
+ rc = smk_curacc(file->f_security, MAY_READWRITE);
+ }
+
+ return rc;
+}
+
+/**
+ * smack_file_send_sigiotask - Smack on sigio
+ * @tsk: The target task
+ * @fown: the object the signal come from
+ * @signum: unused
+ *
+ * Allow a privileged task to get signals even if it shouldn't
+ *
+ * Returns 0 if a subject with the object's smack could
+ * write to the task, an error code otherwise.
+ */
+static int smack_file_send_sigiotask(struct task_struct *tsk,
+ struct fown_struct *fown, int signum)
+{
+ struct file *file;
+ int rc;
+
+ /*
+ * struct fown_struct is never outside the context of a struct file
+ */
+ file = (struct file *)((long)fown - offsetof(struct file,f_owner));
+ rc = smk_access(file->f_security, tsk->security, MAY_WRITE);
+ if (rc != 0 && __capable(tsk, CAP_MAC_OVERRIDE))
+ return 0;
+ return rc;
+}
+
+/**
+ * smack_file_receive - Smack file receive check
+ * @file: the object
+ *
+ * Returns 0 if current has access, error code otherwise
+ */
+static int smack_file_receive(struct file *file)
+{
+ int may = 0;
+
+ /*
+ * This code relies on bitmasks.
+ */
+ if (file->f_mode & FMODE_READ)
+ may = MAY_READ;
+ if (file->f_mode & FMODE_WRITE)
+ may |= MAY_WRITE;
+
+ return smk_curacc(file->f_security, may);
+}
+
+/*
+ * Socket hooks.
+ */
+
+/**
+ * smack_sk_alloc_security - Allocate a socket blob
+ * @sk: the socket
+ * @family: unused
+ * @priority: memory allocation priority
+ *
+ * Assign Smack pointers to current except for smk_packet which
+ * is not a pointer but the real thing.
+ *
+ * Returns 0 on success, -ENOMEM is there's no memory
+ */
+static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
+{
+ char *csp = current->security;
+ struct socket_smack *ssp;
+
+ ssp = kzalloc(sizeof(struct socket_smack), priority);
+ if (ssp == NULL)
+ return -ENOMEM;
+
+ ssp->smk_in = csp;
+ ssp->smk_out = csp;
+ memset(ssp->smk_packet, '\0', SMK_LABELLEN);
+ strcpy(ssp->smk_packet, smack_known_invalid.smk_known);
+ ssp->smk_depth = 0;
+
+ sk->sk_security = ssp;
+
+ return 0;
+}
+
+/**
+ * smack_sk_free_security - Free a socket blob
+ * @sk: the socket
+ *
+ * Clears the blob pointer
+ */
+static void smack_sk_free_security(struct sock *sk)
+{
+ kfree(sk->sk_security);
+ sk->sk_security = NULL;
+}
+
+/**
+ * smack_set_catset - convert a capset to netlabel mls categories
+ * @catset: the Smack categories
+ * @sap: where to put the netlabel categories
+ *
+ * Allocates and fills mls_cat
+ */
+static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap)
+{
+ unsigned char *cp;
+ unsigned char m;
+ int cat;
+ int rc;
+
+ if (catset == 0)
+ return;
+
+ sap->flags |= NETLBL_SECATTR_MLS_CAT;
+ sap->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ sap->mls_cat->startbit = 0;
+
+ for (cat = 1, cp = catset; *cp != 0; cp++)
+ for (m = 0x80; m != 0; m >>= 1, cat++) {
+ if ((m & *cp) == 0)
+ continue;
+ rc = netlbl_secattr_catmap_setbit(sap->mls_cat, cat,
+ GFP_ATOMIC);
+ }
+}
+
+/**
+ * smack_to_secattr - fill a secattr from a smack value
+ * @smack: the smack value
+ * @nlsp: where the result goes
+ *
+ * Casey says that CIPSO is good enough for now.
+ * It can be used to effect.
+ * It can also be abused to effect when necessary.
+ * Appologies to the TSIG group in general and GW in particular.
+ */
+static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
+{
+ struct smack_cipso cipso;
+ int rc;
+
+ switch (smack_net_nltype) {
+ case NETLBL_NLTYPE_CIPSOV4:
+ nlsp->domain = NULL;
+ nlsp->flags = NETLBL_SECATTR_DOMAIN;
+ nlsp->flags |= NETLBL_SECATTR_MLS_LVL;
+
+ rc = smack_to_cipso(smack, &cipso);
+ if (rc == 0) {
+ nlsp->mls_lvl = cipso.smk_level;
+ smack_set_catset(cipso.smk_catset, nlsp);
+ } else {
+ nlsp->mls_lvl = smack_cipso_direct;
+ smack_set_catset(smack, nlsp);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * smack_netlabel - Set the secattr on a socket
+ * @sk: the socket
+ *
+ * Convert the outbound smack value (smk_out) to a
+ * secattr and attach it to the socket.
+ *
+ * Returns 0 on success or an error code
+ */
+static int smack_netlabel(struct sock *sk)
+{
+ static int initialized;
+ struct socket_smack *ssp = sk->sk_security;
+ struct netlbl_lsm_secattr secattr;
+ int rc;
+
+ if (!initialized) {
+ smk_cipso_doi();
+ initialized = 1;
+ }
+
+ netlbl_secattr_init(&secattr);
+ smack_to_secattr(ssp->smk_out, &secattr);
+ if (secattr.flags != NETLBL_SECATTR_NONE)
+ rc = netlbl_sock_setattr(sk, &secattr);
+ else
+ rc = -EINVAL;
+
+ netlbl_secattr_destroy(&secattr);
+ return rc;
+}
+
+/**
+ * smack_socket_post_create - finish socket setup
+ * @sock: the socket
+ * @family: protocol family
+ * @type: unused
+ * @protocol: unused
+ * @kern: indicates kern vs task socket
+ *
+ * Sets the security blob on the socket's inode.
+ * Sets the secattr value for outgoing packets.
+ *
+ * Returns 0 on success, and error code otherwise
+ */
+static int smack_socket_post_create(struct socket *sock, int family,
+ int type, int protocol, int kern)
+{
+ struct inode_smack *isp;
+
+ isp = SOCK_INODE(sock)->i_security;
+
+ if (isp == NULL) {
+ if (kern)
+ isp = new_inode_smack(smack_known_floor.smk_known);
+ else
+ isp = new_inode_smack(current->security);
+ SOCK_INODE(sock)->i_security = isp;
+ }
+
+ if (family != PF_INET)
+ return 0;
+
+ /*
+ * Set the outbound netlbl.
+ */
+ return smack_netlabel(sock->sk);
+}
+
+/**
+ * smack_inode_create - Smack check on inode creation
+ * @dir: containing directory object
+ * @dentry: unused
+ * @mode: unused
+ *
+ * Returns 0 if current can write the containing directory,
+ * error code otherwise
+ */
+static int smack_inode_create(struct inode *dir, struct dentry *dentry,
+ int mode)
+{
+ return smk_curacc(smk_of_inode(dir), MAY_WRITE);
+}
+
+/**
+ * smack_inode_unlink - Smack check on inode deletion
+ * @dir: containing directory object
+ * @dentry: file to unlink
+ *
+ * Returns 0 if current can write the containing directory
+ * and the object, error code otherwise
+ */
+static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *ip = dentry->d_inode;
+ int rc;
+
+ /*
+ * You need write access to the thing you're unlinking
+ */
+ rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
+ if (rc == 0)
+ /*
+ * You also need write access to the containing directory
+ */
+ rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
+
+ return rc;
+}
+
+/**
+ * smack_inode_mkdir - Smack check on directory creation
+ * @dir: containing directory object
+ * @dentry: unused
+ * @mode: unused
+ *
+ * Returns 0 if current can write the containing directory,
+ * error code otherwise
+ */
+static int smack_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ return smk_curacc(smk_of_inode(dir), MAY_WRITE);
+}
+
+/**
+ * smack_inode_rmdir - Smack check on directory deletion
+ * @dir: containing directory object
+ * @dentry: directory to unlink
+ *
+ * Returns 0 if current can write the containing directory
+ * and the directory, error code otherwise
+ */
+static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *ip = dentry->d_inode;
+ int rc;
+
+ /*
+ * You need write access to the thing you're removing
+ */
+ rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
+ if (rc == 0)
+ /*
+ * You also need write access to the containing directory
+ */
+ rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
+
+ return rc;
+}
+
+/**
+ * smack_file_set_fowner - set the file security blob value
+ * @file: object in question
+ *
+ * Returns 0
+ * Further research may be required on this one.
+ */
+static int smack_file_set_fowner(struct file *file)
+{
+ file->f_security = current->security;
+ return 0;
+}
+
+/**
+ * smack_task_getpgid - Smack access check for getpgid
+ * @p: the object task
+ *
+ * Returns 0 if current can read the object task, error code otherwise
+ */
+static int smack_task_getpgid(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_getsid - Smack access check for getsid
+ * @p: the object task
+ *
+ * Returns 0 if current can read the object task, error code otherwise
+ */
+static int smack_task_getsid(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_getsecid - get the secid of the task
+ * @p: the object task
+ * @secid: where to put the result
+ *
+ * Sets the secid to contain a u32 version of the smack label.
+ */
+static void smack_task_getsecid(struct task_struct *p, u32 *secid)
+{
+ *secid = smack_to_secid(p->security);
+}
+
+/**
+ * smack_flags_to_may - convert S_ to MAY_ values
+ * @flags: the S_ value
+ *
+ * Returns the equivalent MAY_ value
+ */
+static int smack_flags_to_may(int flags)
+{
+ int may = 0;
+
+ if (flags & S_IRUGO)
+ may |= MAY_READ;
+ if (flags & S_IWUGO)
+ may |= MAY_WRITE;
+ if (flags & S_IXUGO)
+ may |= MAY_EXEC;
+
+ return may;
+}
+
+/**
+ * smack_msg_msg_alloc_security - Set the security blob for msg_msg
+ * @msg: the object
+ *
+ * Returns 0
+ */
+static int smack_msg_msg_alloc_security(struct msg_msg *msg)
+{
+ msg->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_msg_msg_free_security - Clear the security blob for msg_msg
+ * @msg: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_msg_msg_free_security(struct msg_msg *msg)
+{
+ msg->security = NULL;
+}
+
+/**
+ * smack_of_shm - the smack pointer for the shm
+ * @shp: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_shm(struct shmid_kernel *shp)
+{
+ if (shp == NULL)
+ return NULL;
+
+ return (char *)shp->shm_perm.security;
+}
+
+/**
+ * smack_shm_alloc_security - Set the security blob for shm
+ * @shp: the object
+ *
+ * Returns 0
+ */
+static int smack_shm_alloc_security(struct shmid_kernel *shp)
+{
+ struct kern_ipc_perm *isp = &shp->shm_perm;
+
+ isp->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_shm_free_security - Clear the security blob for shm
+ * @shp: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_shm_free_security(struct shmid_kernel *shp)
+{
+ struct kern_ipc_perm *isp = &shp->shm_perm;
+
+ isp->security = NULL;
+}
+
+/**
+ * smack_shm_associate - Smack access check for shm
+ * @shp: the object
+ * @shmflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
+{
+ char *ssp = smack_of_shm(shp);
+ int may;
+
+ if (ssp == NULL)
+ return 0;
+
+ may = smack_flags_to_may(shmflg);
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_shm_shmctl - Smack access check for shm
+ * @shp: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
+{
+ char *ssp = smack_of_shm(shp);
+ int may;
+
+ if (ssp == NULL)
+ return 0;
+
+ switch(cmd) {
+ case IPC_STAT:
+ case SHM_STAT:
+ may = MAY_READ;
+ break;
+ case IPC_SET:
+ case SHM_LOCK:
+ case SHM_UNLOCK:
+ case IPC_RMID:
+ may = MAY_READWRITE;
+ break;
+ case IPC_INFO:
+ case SHM_INFO:
+ /*
+ * System level information.
+ */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_shm_shmat - Smack access for shmat
+ * @shp: the object
+ * @shmaddr: unused
+ * @shmflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
+ int shmflg)
+{
+ char *ssp = smack_of_shm(shp);
+ int may;
+
+ if (ssp == NULL)
+ return 0;
+
+ may = smack_flags_to_may(shmflg);
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_of_sem - the smack pointer for the sem
+ * @sma: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_sem(struct sem_array *sma)
+{
+ if (sma == NULL)
+ return NULL;
+
+ return (char *)sma->sem_perm.security;
+}
+
+/**
+ * smack_sem_alloc_security - Set the security blob for sem
+ * @sma: the object
+ *
+ * Returns 0
+ */
+static int smack_sem_alloc_security(struct sem_array *sma)
+{
+ struct kern_ipc_perm *isp = &sma->sem_perm;
+
+ isp->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_sem_free_security - Clear the security blob for sem
+ * @sma: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_sem_free_security(struct sem_array *sma)
+{
+ struct kern_ipc_perm *isp = &sma->sem_perm;
+
+ isp->security = NULL;
+}
+
+/**
+ * smack_sem_associate - Smack access check for sem
+ * @sma: the object
+ * @semflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_sem_associate(struct sem_array *sma, int semflg)
+{
+ char *ssp = smack_of_sem(sma);
+ int may;
+
+ if (ssp == NULL)
+ return 0;
+
+ may = smack_flags_to_may(semflg);
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_sem_shmctl - Smack access check for sem
+ * @sma: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_sem_semctl(struct sem_array *sma, int cmd)
+{
+ char *ssp = smack_of_sem(sma);
+ int may;
+
+ if (ssp == NULL)
+ return 0;
+
+ switch(cmd) {
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETVAL:
+ case GETALL:
+ case IPC_STAT:
+ case SEM_STAT:
+ may = MAY_READ;
+ break;
+ case SETVAL:
+ case SETALL:
+ case IPC_RMID:
+ case IPC_SET:
+ may = MAY_READWRITE;
+ break;
+ case IPC_INFO:
+ case SEM_INFO:
+ /*
+ * System level information
+ */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_sem_semop - Smack checks of semaphore operations
+ * @sma: the object
+ * @sops: unused
+ * @nsops: unused
+ * @alter: unused
+ *
+ * Treated as read and write in all cases.
+ *
+ * Returns 0 if access is allowed, error code otherwise
+ */
+static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, unsigned nsops, int alter)
+{
+ char *ssp = smack_of_sem(sma);
+
+ if (ssp == NULL)
+ return 0;
+
+ return smk_curacc(ssp, MAY_READWRITE);
+}
+
+/**
+ * smack_msg_alloc_security - Set the security blob for msg
+ * @msq: the object
+ *
+ * Returns 0
+ */
+static int smack_msg_queue_alloc_security(struct msg_queue *msq)
+{
+ struct kern_ipc_perm *kisp = &msq->q_perm;
+
+ kisp->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_msg_free_security - Clear the security blob for msg
+ * @msq: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_msg_queue_free_security(struct msg_queue *msq)
+{
+ struct kern_ipc_perm *kisp = &msq->q_perm;
+
+ kisp->security = NULL;
+}
+
+/**
+ * smack_of_msq - the smack pointer for the msq
+ * @msq: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_msq(struct msg_queue *msq)
+{
+ if (msq == NULL)
+ return NULL;
+
+ return (char *)msq->q_perm.security;
+}
+
+/**
+ * smack_msg_queue_associate - Smack access check for msg_queue
+ * @msq: the object
+ * @msqflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
+{
+ char *msp = smack_of_msq(msq);
+ int may;
+
+ if (msp == NULL)
+ return 0;
+
+ may = smack_flags_to_may(msqflg);
+ return smk_curacc(msp, may);
+}
+
+/**
+ * smack_msg_queue_msgctl - Smack access check for msg_queue
+ * @msq: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+{
+ char *msp = smack_of_msq(msq);
+ int may;
+
+ if (msp == NULL)
+ return 0;
+
+ switch(cmd) {
+ case IPC_STAT:
+ case MSG_STAT:
+ may = MAY_READ;
+ break;
+ case IPC_SET:
+ case IPC_RMID:
+ may = MAY_READWRITE;
+ break;
+ case IPC_INFO:
+ case MSG_INFO:
+ /*
+ * System level information
+ */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return smk_curacc(msp, may);
+}
+
+/**
+ * smack_msg_queue_msgsnd - Smack access check for msg_queue
+ * @msq: the object
+ * @msg: unused
+ * @msqflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
+ int msqflg)
+{
+ char *msp = smack_of_msq(msq);
+ int rc;
+
+ if (msp == NULL)
+ return 0;
+
+ rc = smack_flags_to_may(msqflg);
+ return smk_curacc(msp, rc);
+}
+
+/**
+ * smack_msg_queue_msgsnd - Smack access check for msg_queue
+ * @msq: the object
+ * @msg: unused
+ * @target: unused
+ * @type: unused
+ * @mode: unused
+ *
+ * Returns 0 if current has read and write access, error code otherwise
+ */
+static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+ struct task_struct *target, long type, int mode)
+{
+ char *msp = smack_of_msq(msq);
+
+ if (msp == NULL)
+ return 0;
+
+ return smk_curacc(msp, MAY_READWRITE);
+}
+
+/**
+ * smack_ipc_permission - Smack access for ipc_permission()
+ * @ipp: the object permissions
+ * @flag: access requested
+ *
+ * Returns 0 if current has read and write access, error code otherwise
+ */
+static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
+{
+ char *isp = ipp->security;
+ int may;
+
+ may = smack_flags_to_may(flag);
+ return smk_curacc(isp, may);
+}
+
+/**
+ * smack_task_to_inode - copy task smack into the inode blob
+ * @p: task to copy from
+ * inode: inode to copy to
+ *
+ * Sets the smack pointer in the inode security blob
+ */
+static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
+{
+ struct inode_smack *isp = inode->i_security;
+ isp->smk_inode = p->security;
+}
+
+/**
+ * smack_task_wait - Smack access check for waiting
+ * @p: task to wait for
+ *
+ * Returns 0 if current can wait for p, error code otherwise
+ */
+static int smack_task_wait(struct task_struct *p)
+{
+ int rc;
+
+ rc = smk_access(current->security, p->security, MAY_WRITE);
+ if (rc == 0)
+ return 0;
+
+ /*
+ * Allow the operation to succeed if either task
+ * has privilege to perform operations that might
+ * account for the smack labels having gotten to
+ * be different in the first place.
+ *
+ * This breaks the strict subjet/object access
+ * control ideal, taking the object's privilege
+ * state into account in the decision as well as
+ * the smack value.
+ */
+ if (__capable(current, CAP_MAC_OVERRIDE) ||
+ __capable(p, CAP_MAC_OVERRIDE))
+ return 0;
+
+ return rc;
+}
+
+/**
+ * smack_getprocattr - Smack process attribute access
+ * @p: the object task
+ * @name: the name of the attribute in /proc/.../attr
+ * @value: where to put the result
+ *
+ * Places a copy of the task Smack into value
+ *
+ * Returns the length of the smack label or an error code
+ */
+static int smack_getprocattr(struct task_struct *p, char *name, char **value)
+{
+ char *cp;
+ int slen;
+
+ if (strcmp(name, "current") != 0)
+ return -EINVAL;
+
+ cp = kstrdup(current->security, GFP_KERNEL);
+ if (cp == NULL)
+ return -ENOMEM;
+
+ slen = strlen(cp);
+ *value = cp;
+ return slen;
+}
+
+/**
+ * smack_setprocattr - Smack process attribute setting
+ * @p: the object task
+ * @name: the name of the attribute in /proc/.../attr
+ * @value: the value to set
+ * @size: the size of the value
+ *
+ * Sets the Smack value of the task. Only setting self
+ * is permitted and only with privilege
+ *
+ * Returns the length of the smack label or an error code
+ */
+static int smack_setprocattr(struct task_struct *p, char *name,
+ void *value, size_t size)
+{
+ char *newsmack;
+
+ if (!__capable(p, CAP_MAC_OVERRIDE))
+ return -EPERM;
+
+ /*
+ * Changing another process' Smack value is too dangerous
+ * and supports no sane use case.
+ */
+ if (p != current)
+ return -EPERM;
+
+ if (value == NULL || size == 0 || size >= SMK_LABELLEN)
+ return -EINVAL;
+
+ if (strcmp(name, "current") != 0)
+ return -EINVAL;
+
+ newsmack = smk_import(value, size);
+ if (newsmack == NULL)
+ return -EINVAL;
+
+ p->security = newsmack;
+ return size;
+}
+
+/**
+ * smack_unix_stream_connect - Smack access on UDS
+ * @sock: one socket
+ * @other: the other socket
+ * @newsk: unused
+ *
+ * Return 0 if a subject with the smack of sock could access
+ * an object with the smack of other, otherwise an error code
+ */
+static int smack_unix_stream_connect(struct socket *sock,
+ struct socket *other, struct sock *newsk)
+{
+ struct inode *sp = SOCK_INODE(sock);
+ struct inode *op = SOCK_INODE(other);
+
+ return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE);
+}
+
+/**
+ * smack_unix_may_send - Smack access on UDS
+ * @sock: one socket
+ * @other: the other socket
+ *
+ * Return 0 if a subject with the smack of sock could access
+ * an object with the smack of other, otherwise an error code
+ */
+static int smack_unix_may_send(struct socket *sock, struct socket *other)
+{
+ struct inode *sp = SOCK_INODE(sock);
+ struct inode *op = SOCK_INODE(other);
+
+ return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
+}
+
+/**
+ * smack_from_secattr - Convert a netlabel mls_lvl/mls_cat pair to smack
+ * @sap: netlabel secattr
+ * @sip: where to put the result
+ *
+ * Copies a smack label into sip
+ */
+static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
+{
+ char smack[SMK_LABELLEN];
+ int pcat;
+
+ if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
+ /*
+ * If there are flags but no level netlabel isn't
+ * behaving the way we expect it to.
+ *
+ * Without guidance regarding the smack value
+ * for the packet fall back on the network
+ * ambient value.
+ */
+ strncpy(sip, smack_net_ambient, SMK_MAXLEN);
+ return;
+ }
+ /*
+ * Get the categories, if any
+ */
+ memset(smack, '\0', SMK_LABELLEN);
+ if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
+ for (pcat = -1;;) {
+ pcat = netlbl_secattr_catmap_walk(sap->mls_cat, pcat+1);
+ if (pcat < 0)
+ break;
+ smack_catset_bit(pcat, smack);
+ }
+ /*
+ * If it is CIPSO using smack direct mapping
+ * we are already done. WeeHee.
+ */
+ if (sap->mls_lvl == smack_cipso_direct) {
+ memcpy(sip, smack, SMK_MAXLEN);
+ return;
+ }
+ /*
+ * Look it up in the supplied table if it is not a direct mapping.
+ */
+ smack_from_cipso(sap->mls_lvl, smack, sip);
+ return;
+}
+
+static int smack_socket_recvmsg(struct socket *sock, struct msghdr *msg,
+ int size, int flags)
+{
+ struct socket_smack *ssp = sock->sk->sk_security;
+
+ /*
+ * If the depth is 0 no packets are queued.
+ * If the depth is > 1 the "current" has been overwritten.
+ */
+
+ if (ssp->smk_depth != 1)
+ ssp->smk_packet[0] = '\0';
+ if (ssp->smk_depth != 0)
+ ssp->smk_depth--;
+
+ return 0;
+}
+
+/**
+ * smack_socket_sock_rcv_skb - Smack packet delivery access check
+ * @sk: socket
+ * @skb: packet
+ *
+ * Returns 0 if the packet should be delivered, an error code otherwise
+ */
+static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ struct netlbl_lsm_secattr secattr;
+ struct socket_smack *ssp = sk->sk_security;
+ char smack[SMK_LABELLEN];
+ int rc;
+
+ if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+ return 0;
+
+ /*
+ * Translate what netlabel gave us.
+ */
+ memset(smack, '\0', SMK_LABELLEN);
+ netlbl_secattr_init(&secattr);
+ rc = netlbl_skbuff_getattr(skb, &secattr);
+ if (rc == 0)
+ smack_from_secattr(&secattr, smack);
+ else
+ strncpy(smack, smack_net_ambient, SMK_MAXLEN);
+ netlbl_secattr_destroy(&secattr);
+ /*
+ * Receiving a packet requires that the other end
+ * be able to write here. Read access is not required.
+ * This is the simplist possible security model
+ * for networking.
+ */
+ rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+ if (rc != 0)
+ return rc;
+
+ /*
+ * If recv was called and there were no outstanding packets
+ * this is the "current" Smack value to make available.
+ */
+ if (ssp->smk_depth == 0)
+ strcpy(ssp->smk_packet, smack);
+ ssp->smk_depth++;
+
+ return 0;
+}
+
+/**
+ * smack_sock_graft - graft access state between two sockets
+ * @sk: fresh sock
+ * @parent: donor socket
+ *
+ * Sets the netlabel socket state on sk from parent
+ */
+static void smack_sock_graft(struct sock *sk, struct socket *parent)
+{
+ struct socket_smack *ssp;
+ struct netlbl_lsm_secattr secattr;
+ char smack[SMK_LABELLEN];
+ int rc;
+
+ if (sk == NULL || parent == NULL || parent->sk == NULL)
+ return;
+
+ if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+ return;
+
+ ssp = parent->sk->sk_security;
+
+ memset(smack, '\0', SMK_LABELLEN);
+ netlbl_secattr_init(&secattr);
+ rc = netlbl_sock_getattr(sk, &secattr);
+ if (rc == 0)
+ smack_from_secattr(&secattr, smack);
+ else
+ strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
+ netlbl_secattr_destroy(&secattr);
+
+ netlbl_secattr_init(&secattr);
+
+ smack_to_secattr(smack, &secattr);
+ if (secattr.flags != NETLBL_SECATTR_NONE)
+ rc = netlbl_sock_setattr(parent->sk, &secattr);
+ netlbl_secattr_destroy(&secattr);
+}
+
+/**
+ * smack_inet_conn_request - Smack access check on connect
+ * @sk: socket involved
+ * @skb: packet
+ * @req: unused
+ *
+ * Returns 0 if a task with the packet label could write to
+ * the socket, otherwise an error code
+ */
+static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req)
+{
+ struct netlbl_lsm_secattr skb_secattr;
+ struct socket_smack *ssp = sk->sk_security;
+ char smack[SMK_LABELLEN];
+ int rc;
+
+ if (skb == NULL)
+ return -EACCES;
+
+ memset(smack, '\0', SMK_LABELLEN);
+ netlbl_secattr_init(&skb_secattr);
+ rc = netlbl_skbuff_getattr(skb, &skb_secattr);
+ if (rc == 0)
+ smack_from_secattr(&skb_secattr, smack);
+ else
+ strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
+ netlbl_secattr_destroy(&skb_secattr);
+ /*
+ * Receiving a packet requires that the other end
+ * be able to write here. Read access is not required.
+ */
+ return smk_access(smack, ssp->smk_in, MAY_WRITE);
+}
+
+/*
+ * Key management security hooks
+ *
+ * Casey has not tested key support very heavily.
+ * The permission check is most likely too restrictive.
+ * If you care about keys please have a look.
+ */
+#ifdef CONFIG_KEYS
+
+/**
+ * smack_key_alloc - Set the key security blob
+ * @key: object
+ * @tsk: the task associated with the key
+ * @flags: unused
+ *
+ * No allocation required
+ *
+ * Returns 0
+ */
+static int smack_key_alloc(struct key *key, struct task_struct *tsk,
+ unsigned long flags)
+{
+ key->security = tsk->security;
+ return 0;
+}
+
+/**
+ * smack_key_free - Clear the key security blob
+ * @key: the object
+ *
+ * Clear the blob pointer
+ */
+static void smack_key_free(struct key *key)
+{
+ key->security = NULL;
+}
+
+/*
+ * smack_key_permission - Smack access on a key
+ * @key_ref: gets to the object
+ * @context: task involved
+ * @perm: unused
+ *
+ * Return 0 if the task has read and write to the object,
+ * an error code otherwise
+ */
+static int smack_key_permission(key_ref_t key_ref,
+ struct task_struct *context, key_perm_t perm)
+{
+ struct key *keyp;
+
+ keyp = key_ref_to_ptr(key_ref);
+ if (keyp == NULL)
+ return -EINVAL;
+ /*
+ * If the key hasn't been initialized give it access so that
+ * it may do so.
+ */
+ if (keyp->security == NULL)
+ return 0;
+ /*
+ * This should not occur
+ */
+ if (context->security == NULL)
+ return -EACCES;
+
+ return smk_access(context->security, keyp->security, MAY_READWRITE);
+}
+#endif /* CONFIG_KEYS */
+
+static struct security_operations smack_ops = {
+ .ptrace = smack_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ /* .acct No hook required */
+ /* .sysctl No hook required */
+ /* .quotactl No hook required */
+ /* .quota_on No hook required */
+ .syslog = smack_syslog,
+ .settime = cap_settime,
+ .vm_enough_memory = cap_vm_enough_memory,
+
+ /* .bprm_alloc_security No hook required */
+ /* .bprm_free_security No hook required */
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ /* .bprm_post_apply_creds No hook required */
+ .bprm_set_security = cap_bprm_set_security,
+ /* .bprm_check_security No hook required */
+ .bprm_secureexec = cap_bprm_secureexec,
+
+ .sb_alloc_security = smack_sb_alloc_security,
+ .sb_free_security = smack_sb_free_security,
+ .sb_copy_data = smack_sb_copy_data,
+ .sb_kern_mount = smack_sb_kern_mount,
+ .sb_statfs = smack_sb_statfs,
+ .sb_mount = smack_sb_mount,
+ /* .sb_check_sb No hook required */
+ .sb_umount = smack_sb_umount,
+ /* .sb_umount_close No hook required */
+ /* .sb_umount_busy No hook required */
+ /* .sb_post_remount No hook required */
+ /* .sb_post_mountroot No hook required */
+ /* .sb_post_addmount No hook required */
+ /* .sb_pivotroot No hook required */
+ /* .sb_post_pivotroot No hook required */
+
+ .inode_alloc_security = smack_inode_alloc_security,
+ .inode_free_security = smack_inode_free_security,
+ .inode_init_security = smack_inode_init_security,
+ .inode_create = smack_inode_create,
+ .inode_link = smack_inode_link,
+ .inode_unlink = smack_inode_unlink,
+ .inode_symlink = smack_inode_symlink,
+ .inode_mkdir = smack_inode_mkdir,
+ .inode_rmdir = smack_inode_rmdir,
+ .inode_mknod = smack_inode_mknod,
+ .inode_rename = smack_inode_rename,
+ .inode_readlink = smack_inode_readlink,
+ .inode_follow_link = smack_inode_follow_link,
+ .inode_permission = smack_inode_permission,
+ .inode_setattr = smack_inode_setattr,
+ .inode_getattr = smack_inode_getattr,
+ /* .inode_delete No hook required */
+ .inode_setxattr = smack_inode_setxattr,
+ .inode_post_setxattr = smack_inode_post_setxattr,
+ .inode_getxattr = smack_inode_getxattr,
+ .inode_listxattr = smack_inode_listxattr,
+ .inode_removexattr = smack_inode_removexattr,
+ /* .inode_xattr_getsuffix No hook required */
+ .inode_getsecurity = smack_inode_getsecurity,
+ .inode_setsecurity = smack_inode_setsecurity,
+ .inode_listsecurity = smack_inode_listsecurity,
+
+ .file_permission = smack_file_permission,
+ .file_alloc_security = smack_file_alloc_security,
+ .file_free_security = smack_file_free_security,
+ .file_ioctl = smack_file_ioctl,
+ /* .file_mmap No hook required */
+ /* .file_mprotect No hook required */
+ .file_lock = smack_file_lock,
+ .file_fcntl = smack_file_fcntl,
+ .file_set_fowner = smack_file_set_fowner,
+ .file_send_sigiotask = smack_file_send_sigiotask,
+ .file_receive = smack_file_receive,
+
+ /* .task_create No hook required */
+ .task_alloc_security = smack_task_alloc_security,
+ .task_free_security = smack_task_free_security,
+ /* .task_setuid No hook required */
+ .task_post_setuid = cap_task_post_setuid,
+ /* .task_setgid No hook required */
+ .task_setpgid = smack_task_setpgid,
+ .task_getpgid = smack_task_getpgid,
+ .task_getsid = smack_task_getsid,
+ .task_getsecid = smack_task_getsecid,
+ /* .task_setgroups No hook required */
+ .task_setnice = smack_task_setnice,
+ .task_setioprio = smack_task_setioprio,
+ .task_getioprio = smack_task_getioprio,
+ /* .task_setrlimit No hook required */
+ .task_setscheduler = smack_task_setscheduler,
+ .task_getscheduler = smack_task_getscheduler,
+ .task_movememory = smack_task_movememory,
+ .task_kill = smack_task_kill,
+ .task_wait = smack_task_wait,
+ /* .task_prctl No hook required */
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .task_to_inode = smack_task_to_inode,
+
+ .ipc_permission = smack_ipc_permission,
+
+ .msg_msg_alloc_security = smack_msg_msg_alloc_security,
+ .msg_msg_free_security = smack_msg_msg_free_security,
+
+ .msg_queue_alloc_security = smack_msg_queue_alloc_security,
+ .msg_queue_free_security = smack_msg_queue_free_security,
+ .msg_queue_associate = smack_msg_queue_associate,
+ .msg_queue_msgctl = smack_msg_queue_msgctl,
+ .msg_queue_msgsnd = smack_msg_queue_msgsnd,
+ .msg_queue_msgrcv = smack_msg_queue_msgrcv,
+
+ .shm_alloc_security = smack_shm_alloc_security,
+ .shm_free_security = smack_shm_free_security,
+ .shm_associate = smack_shm_associate,
+ .shm_shmctl = smack_shm_shmctl,
+ .shm_shmat = smack_shm_shmat,
+
+ .sem_alloc_security = smack_sem_alloc_security,
+ .sem_free_security = smack_sem_free_security,
+ .sem_associate = smack_sem_associate,
+ .sem_semctl = smack_sem_semctl,
+ .sem_semop = smack_sem_semop,
+
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+ /* .register_security No hook required */
+ /* .unregister_security No hook required */
+
+ .d_instantiate = smack_d_instantiate,
+
+ .getprocattr = smack_getprocattr,
+ .setprocattr = smack_setprocattr,
+ /* .secid_to_secctx No hook required */
+ /* .release_secctx No hook required */
+
+ .unix_stream_connect = smack_unix_stream_connect,
+ .unix_may_send = smack_unix_may_send,
+
+ /* .socket_create No hook required */
+ .socket_post_create = smack_socket_post_create,
+ /* .socket_bind No hook required */
+ /* .socket_connect No hook required */
+ /* .socket_listen No hook required */
+ /* .socket_accept No hook required */
+ /* .socket_post_accept No hook required */
+ /* .socket_sendmsg No hook required */
+ .socket_recvmsg = smack_socket_recvmsg,
+ /* .socket_getsockname No hook required */
+ /* .socket_getpeername No hook required */
+ /* .socket_getsockopt No hook required */
+ /* .socket_setsockopt No hook required */
+ /* .socket_shutdown No hook required */
+ .socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
+ /* .socket_getpeersec_stream No hook required */
+ /* .socket_getpeersec_dgram No hook required */
+ .sk_alloc_security = smack_sk_alloc_security,
+ .sk_free_security = smack_sk_free_security,
+ /* .sk_clone_security No hook required */
+ /* .sk_getsecid No hook required */
+ .sock_graft = smack_sock_graft,
+ .inet_conn_request = smack_inet_conn_request,
+ /* .inet_csk_clone No hook required */
+ /* .inet_conn_established No hook required */
+
+ /* .req_classify_flow No hook required */
+ /* .xfrm_policy_alloc_security no xfrm for smack */
+ /* .xfrm_policy_clone_security no xfrm for smack */
+ /* .xfrm_policy_free_security no xfrm for smack */
+ /* .xfrm_policy_delete_security no xfrm for smack */
+ /* .xfrm_state_alloc_security no xfrm for smack */
+ /* .xfrm_state_free_security no xfrm for smack */
+ /* .xfrm_state_delete_security no xfrm for smack */
+ /* .xfrm_policy_lookup no xfrm for smack */
+ /* .xfrm_state_pol_flow_match no xfrm for smack */
+ /* .xfrm_decode_session no xfrm for smack */
+
+ /* key management security hooks */
+#ifdef CONFIG_KEYS
+ .key_alloc = smack_key_alloc,
+ .key_free = smack_key_free,
+ .key_permission = smack_key_permission,
+#endif /* CONFIG_KEYS */
+
+};
+
+DEFINE_MUTEX(smack_list_lock);
+DEFINE_MUTEX(smack_known_lock);
+
+/**
+ * smack_init - initialize the smack system
+ *
+ * Returns 0
+ */
+static __init int smack_init(void)
+{
+ printk(KERN_INFO "Smack: Initializing.\n");
+
+ /*
+ * Set the security state for the initial task.
+ */
+ current->security = &smack_known_floor.smk_known;
+
+ /*
+ * Initialize locks
+ */
+ spin_lock_init(&smack_known_unset.smk_cipsolock);
+ spin_lock_init(&smack_known_huh.smk_cipsolock);
+ spin_lock_init(&smack_known_hat.smk_cipsolock);
+ spin_lock_init(&smack_known_star.smk_cipsolock);
+ spin_lock_init(&smack_known_floor.smk_cipsolock);
+ spin_lock_init(&smack_known_invalid.smk_cipsolock);
+
+ mutex_init(&smack_known_lock);
+ mutex_init(&smack_list_lock);
+
+ /*
+ * Register with LSM
+ */
+ if (register_security(&smack_ops))
+ panic("smack: Unable to register with kernel.\n");
+
+ return 0;
+}
+
+/*
+ * Smack requires early initialization in order to label
+ * all processes and objects when they are created.
+ */
+security_initcall(smack_init);
+
On Sat, 29 Sep 2007 17:20:36 -0700 Casey Schaufler <[email protected]> wrote:
>
> Smack is the Simplified Mandatory Access Control Kernel.
>
I don't know enough about security even to be dangerous. I went back and
reviewed the August thread from your version 1 submission and the message I
take away is that the code has been well-received and looks good when
considered on its own merits, but selinux could probably be configured to
do something sufficiently similar.
I'd have trouble declaring that "but" to be a reason to not merge smack.
I'm more thinking "let's merge it and see if people use it".
>
> Documentation/Smack.txt | 104 +
> security/Kconfig | 1
> security/Makefile | 2
> security/smack/Kconfig | 10
> security/smack/Makefile | 9
> security/smack/smack.h | 207 ++
> security/smack/smack_access.c | 345 ++++
> security/smack/smack_lsm.c | 2685 ++++++++++++++++++++++++++++++++
> security/smack/smackfs.c | 1201 ++++++++++++++
> 9 files changed, 4564 insertions(+)
And that wonderful diffstat really is key to being able to do this.
My major non-technical concern is that Casey Schaufler might get hit by a
bus. If this happens, we can remove the feature in three minutes (that
diffstat again), but that may not be feasible if people have come to rely
upon the feature.
otoh, if a significant number of people are using smack, presumably someone
else would step up to maintain smack post-bus. The risk seems acceptable
to me.
My major technical concern is the apparent paucity of documentation.
So with the information which I presently have available to me, I'm
thinking that this should go into 2.6.24.
Is smack useful without a patched ls, sshd and init.d? What is the status
of getting those userspace patches merged? ie: do you know who to send the
diffs to, and are they likely to take them?
What other userspace tools are likely to need patching?
Notes on the code:
- Please run scripts/checkpatch.pl across the diff. It generates 50-100
warnings about minor stylistic matters, and those warnings all look legit
to me. (extern decls in C are my fave peeve).
- Smack.txt and the website seem a bit skimpy. Is there enough
documentation out there for someone to usefully (and, more importantly,
safely) start using smack?
- In his review of version 1, Andi suggested that your ruleset traversal
be protected by RCU. But it seems that this wasn't done. Were the races
which he identified fixed by other means? If so, what were they?
- hm, netlabels. Who might be a suitable person to review that code?
Seems that Paul Moore is the man. Maybe he'd be interested in taking a
look over it (please?)
- some parts of the code use the "smack_foo" naming convention and other
parts use "smk_foo". Seems odd. Deliberate?
- According to git-log, you haven't merged any kernel code at all in at
least 5.5 years. This patch makes it look like you've been doing kernel
full time for a decade. That thing in my hand is a hat.
> - Smack.txt and the website seem a bit skimpy. Is there enough
> documentation out there for someone to usefully (and, more importantly,
> safely) start using smack?
Yes that's the important thing.
> - In his review of version 1, Andi suggested that your ruleset traversal
> be protected by RCU. But it seems that this wasn't done. Were the races
> which he identified fixed by other means? If so, what were they?
The issue was moot because rulesets never get removed in the current
implementation. I had missed that. If that ever changes RCU would be likely
needed though.
> - hm, netlabels. Who might be a suitable person to review that code?
> Seems that Paul Moore is the man. Maybe he'd be interested in taking a
> look over it (please?)
I personally consider these IP options it uses to be pretty useless. Who could
ever use that without cryptographic authentication? Clearly when they
were designed in the original IP spec long ago the designers didn't understand
network security very well because the whole field was at its infancy. And
CIPSO doesn't solve any of these fundamental issues.
It assumes a trusted network which is a very dangerous assumption. I don't
think that was in the original patch I looked at, I surely would have
objected to it.
Perhaps take the network part out? I guess SMACK would be useful
locally even without questionable network support.
-Andi
On Sun, Sep 30, 2007 at 01:16:18AM -0700, Andrew Morton wrote:
> reviewed the August thread from your version 1 submission and the message I
> take away is that the code has been well-received and looks good when
> considered on its own merits, but selinux could probably be configured to
> do something sufficiently similar.
>
> I'd have trouble declaring that "but" to be a reason to not merge smack.
> I'm more thinking "let's merge it and see if people use it".
I'm not sure this was discussed on the list, but as long as Casey doesn't
get rid of the magic symlinks (smackfs_follow_link), there's a clear NACK
from the VFS perspective.
Otherwise the code looks pretty well written, alhough a run through
checkpath.pl to fix the lose end might help. Oh, and please to compile-time
initializations for the spinlocks and mutex currently initializes in
smack_init. Also the -Inet/netlabel looks rather odd, please work with
the netlabel maintainer to move the required files to the include/
hierachy.
--- Andrew Morton <[email protected]> wrote:
> On Sat, 29 Sep 2007 17:20:36 -0700 Casey Schaufler <[email protected]>
> wrote:
>
> >
> > Smack is the Simplified Mandatory Access Control Kernel.
> >
>
> I don't know enough about security even to be dangerous. I went back and
> reviewed the August thread from your version 1 submission and the message I
> take away is that the code has been well-received and looks good when
> considered on its own merits, but selinux could probably be configured to
> do something sufficiently similar.
>
> I'd have trouble declaring that "but" to be a reason to not merge smack.
> I'm more thinking "let's merge it and see if people use it".
>
> >
> > Documentation/Smack.txt | 104 +
> > security/Kconfig | 1
> > security/Makefile | 2
> > security/smack/Kconfig | 10
> > security/smack/Makefile | 9
> > security/smack/smack.h | 207 ++
> > security/smack/smack_access.c | 345 ++++
> > security/smack/smack_lsm.c | 2685 ++++++++++++++++++++++++++++++++
> > security/smack/smackfs.c | 1201 ++++++++++++++
> > 9 files changed, 4564 insertions(+)
>
> And that wonderful diffstat really is key to being able to do this.
>
> My major non-technical concern is that Casey Schaufler might get hit by a
> bus. If this happens, we can remove the feature in three minutes (that
> diffstat again), but that may not be feasible if people have come to rely
> upon the feature.
>
> otoh, if a significant number of people are using smack, presumably someone
> else would step up to maintain smack post-bus. The risk seems acceptable
> to me.
>
> My major technical concern is the apparent paucity of documentation.
I've been leading with code, and working on the documentation
less agressively. I will pick up the text pace.
> So with the information which I presently have available to me, I'm
> thinking that this should go into 2.6.24.
That would be OK by me. Thank you.
> Is smack useful without a patched ls, sshd and init.d? What is the status
> of getting those userspace patches merged? ie: do you know who to send the
> diffs to, and are they likely to take them?
Yes, haven't been pushing, don't know, and haven't a clue.
> What other userspace tools are likely to need patching?
Over time the Smack application changes will fairly
closely follow those for SELinux, e.g. cron, login,
su, the MLS window environment. There won't be a major
set of new applications or libraries as there isn't a
policy compliation step involved.
> Notes on the code:
>
>
> - Please run scripts/checkpatch.pl across the diff. It generates 50-100
> warnings about minor stylistic matters, and those warnings all look legit
> to me. (extern decls in C are my fave peeve).
Will do.
> - Smack.txt and the website seem a bit skimpy. Is there enough
> documentation out there for someone to usefully (and, more importantly,
> safely) start using smack?
Current feedback says they need more work.
> - In his review of version 1, Andi suggested that your ruleset traversal
> be protected by RCU. But it seems that this wasn't done. Were the races
> which he identified fixed by other means? If so, what were they?
The ruleset code was completly revised in Version 2.
> - hm, netlabels. Who might be a suitable person to review that code?
> Seems that Paul Moore is the man. Maybe he'd be interested in taking a
> look over it (please?)
Paul was the first person to whom I sent the patch. I would be
delighted to have him review it again.
> - some parts of the code use the "smack_foo" naming convention and other
> parts use "smk_foo". Seems odd. Deliberate?
The original intent was an "external" vs "internal" distinction,
but it greyed over time. I will look at cleaning this up.
> - According to git-log, you haven't merged any kernel code at all in at
> least 5.5 years. This patch makes it look like you've been doing kernel
> full time for a decade. That thing in my hand is a hat.
Thank you. The current set of interfaces and practices make
kernel coding much easier than it was back in the Unix days.
Casey Schaufler
[email protected]
--- Andi Kleen <[email protected]> wrote:
>
> > - Smack.txt and the website seem a bit skimpy. Is there enough
> > documentation out there for someone to usefully (and, more importantly,
> > safely) start using smack?
>
> Yes that's the important thing.
>
> > - In his review of version 1, Andi suggested that your ruleset traversal
> > be protected by RCU. But it seems that this wasn't done. Were the races
> > which he identified fixed by other means? If so, what were they?
>
> The issue was moot because rulesets never get removed in the current
> implementation. I had missed that. If that ever changes RCU would be likely
> needed though.
>
> > - hm, netlabels. Who might be a suitable person to review that code?
> > Seems that Paul Moore is the man. Maybe he'd be interested in taking a
> > look over it (please?)
>
> I personally consider these IP options it uses to be pretty useless. Who
> could
> ever use that without cryptographic authentication? Clearly when they
> were designed in the original IP spec long ago the designers didn't
> understand
> network security very well because the whole field was at its infancy. And
> CIPSO doesn't solve any of these fundamental issues.
Real quickly, CIPSO doesn't try to. CIPSO attaches attribute information
to the packet, and that's it. Smack uses CIPSO because it's available
and sufficient to get the required information about packets from one
task to another inside the box. It does the job going off box, too.
The authentication issues are very real, but a separate issue.
> It assumes a trusted network which is a very dangerous assumption. I don't
> think that was in the original patch I looked at, I surely would have
> objected to it.
>
> Perhaps take the network part out? I guess SMACK would be useful
> locally even without questionable network support.
That would break sockets. I really doubt that you're suggesting that
cryptographic authentication is required on the loopback interface.
Casey Schaufler
[email protected]
--- Christoph Hellwig <[email protected]> wrote:
> On Sun, Sep 30, 2007 at 01:16:18AM -0700, Andrew Morton wrote:
> > reviewed the August thread from your version 1 submission and the message I
> > take away is that the code has been well-received and looks good when
> > considered on its own merits, but selinux could probably be configured to
> > do something sufficiently similar.
> >
> > I'd have trouble declaring that "but" to be a reason to not merge smack.
> > I'm more thinking "let's merge it and see if people use it".
>
> I'm not sure this was discussed on the list, but as long as Casey doesn't
> get rid of the magic symlinks (smackfs_follow_link), there's a clear NACK
> from the VFS perspective.
OK, this is news to me. What's the objection?
> Otherwise the code looks pretty well written, alhough a run through
> checkpath.pl to fix the lose end might help. Oh, and please to compile-time
> initializations for the spinlocks and mutex currently initializes in
> smack_init. Also the -Inet/netlabel looks rather odd, please work with
> the netlabel maintainer to move the required files to the include/
> hierachy.
Paul and I discussed this earlier, and will again.
Thank you.
Casey Schaufler
[email protected]
> It does the job going off box, too.
It does not as far as I can see. The IETF seems to have had very good
reasons to never advance that draft any further.
> The authentication issues are very real, but a separate issue.
First rule of network security: don't trust the network. And you seem
to trust your security to the network which is just double plus bogus.
Without authentication it's completely useless. I don't understand
how you can disregard that as "separate issue". Security is only
secure if you plugged all applicable holes; without that it's useless
and you might as well not bother.
> > It assumes a trusted network which is a very dangerous assumption. I don't
> > think that was in the original patch I looked at, I surely would have
> > objected to it.
> >
> > Perhaps take the network part out? I guess SMACK would be useful
> > locally even without questionable network support.
>
> That would break sockets.
You didn't solve sockets security, so they cannot be really broken.
And it's not that network security isn't well understood and well supported
in Linux by various proven subsystems (ipsec, netfilter, ssh, openssl etc.).
Adding a insecure additional placebo just doesn't seem like a good idea.
> I really doubt that you're suggesting that
> cryptographic authentication is required on the loopback interface.
For local communication security there are better options like Unix sockets
which can be protected by standard file system protections. And most
networking is not over loopback after all. Only handling loopback is so limited
that it's bordering to useless.
And again we have plenty of proven networking security solutions anyways.
They all work fine over loopback too. I don't really see what SMACK can add here.
-Andi
> CIPSO is supported on SELinux as well.
That's no reason to extend that design mistake.
> It certainly has uses where IPSec
> is excessive. One example is someone I talked to recently that basically
> has a set of blade systems connected with a high speed backplane that
> looks like a network interface. CIPSO is useful in this case because
> they can't afford the overhead of IPSec but need to transfer the level
> of the connection to the other machines. The backplane is a trusted
> network and that isn't a dangerous assumption in this case.
If one of the boxes gets broken in all are compromised this way?
> CIPSO also lets systems like SELinux and SMACK talk to other trusted
> systems (eg., trusted solaris) in a way they understand.
Perhaps, but is the result secure? I have severe doubts.
> I don't
> regularly support CIPSO as I believe IPSec labeling is more useful in
> more situations but that doesn't mean CIPSO is never useful.
Security that isn't secure is not really useful. You might as well not
bother.
-Andi
Andi Kleen wrote:
>> - hm, netlabels. Who might be a suitable person to review that code?
>> Seems that Paul Moore is the man. Maybe he'd be interested in taking a
>> look over it (please?)
>>
>
> I personally consider these IP options it uses to be pretty useless. Who could
> ever use that without cryptographic authentication? Clearly when they
> were designed in the original IP spec long ago the designers didn't understand
> network security very well because the whole field was at its infancy. And
> CIPSO doesn't solve any of these fundamental issues.
>
> It assumes a trusted network which is a very dangerous assumption. I don't
> think that was in the original patch I looked at, I surely would have
> objected to it.
>
> Perhaps take the network part out? I guess SMACK would be useful
> locally even without questionable network support.
>
CIPSO is supported on SELinux as well. It certainly has uses where IPSec
is excessive. One example is someone I talked to recently that basically
has a set of blade systems connected with a high speed backplane that
looks like a network interface. CIPSO is useful in this case because
they can't afford the overhead of IPSec but need to transfer the level
of the connection to the other machines. The backplane is a trusted
network and that isn't a dangerous assumption in this case.
CIPSO also lets systems like SELinux and SMACK talk to other trusted
systems (eg., trusted solaris) in a way they understand. I don't
regularly support CIPSO as I believe IPSec labeling is more useful in
more situations but that doesn't mean CIPSO is never useful.
On Sun, Sep 30, 2007 at 07:39:57PM +0200, Andi Kleen wrote:
> > CIPSO also lets systems like SELinux and SMACK talk to other trusted
> > systems (eg., trusted solaris) in a way they understand.
>
> Perhaps, but is the result secure? I have severe doubts.
As always, it depends on your environment. There are people who are
using Linux systems where trusting the network makes sense. For
example, if you're on a battleship, say, or all of the machines are in
a cluster which is inside a Tempest-shielded machine room with a
massive combination lock that you might find on a bank vault, or if
you're environment where network cables are protected by pressurized
pipes (so any attempt to tamper with or tap the cables causes a
pressure drop which sets off the alarm which summons the Marines armed
with M-16's...).
(I've been inside classified machine rooms, which is why my laptop has
the 'Unclassified' label on it; it's needed so people can easily
eyeball it and know that I'm not allowed to connect it to any of the
classified networks. And those are just the less serious machine
rooms. In the really serious classified areas with the bank
vault-like doors, and the copper-tinted windows, I'm not allowed to
bring in an unclassified laptop at all --- and yes, Linux is being
used in such environments. And yes, they do sometimes use IPSO and/or
CIPSO.)
> Security that isn't secure is not really useful. You might as well not
> bother.
There are different kinds of security. Not all of them involve
cryptography and IPSEC. Some of them involve armed soldiers and air
gap firewalls. :-)
Yes, normally the network is outside the Trusted Computing Base (TCB),
but a cluster of Linux machines in a rack is roughly the same size of
a huge Unix server tens year ago --- and it's not like Ethernet is any
more secure than the PCI bus. So why do we consider communications
across a PCI bus secure even though they aren't encrypted? Why,
because normally we assume the PCI bus is inside the trust boundary,
and so we don't worry about bad guys tapping communications between
the CPU and the hard drive on the PCI bus.
But these days, it is obviously possible to create clusters where
certain network interfaces are only connected to machines contained
completely inside the trust boundary, just like a PCI bus in a
traditional server. So don't be so quick to dismiss something like
CIPSO out of hand, just because it doesn't use IPSEC.
Regards,
- Ted
> Yes, normally the network is outside the Trusted Computing Base (TCB),
Normally as in the 99.99999% case.
> but a cluster of Linux machines in a rack is roughly the same size of
> a huge Unix server tens year ago --- and it's not like Ethernet is any
> more secure than the PCI bus.
PCI busses normally don't have routers to networks outside the box connected
to them.
> So don't be so quick to dismiss something like
> CIPSO out of hand, just because it doesn't use IPSEC.
With your argumentation we could also just disable all security
in these situations (as in null LSM to save some overhead); after all these
systems are protected by armed guards. If someone gets past the guards
they could connect their laptop to the network and fake all the "secured"
packets. If you assume that won't happen why do you need computer security at all?
Anyways; if someone wants to cripple their security for some
performance this way they can surely do this; but i don't think we should
offer it as a default configuration option (just as we don't have a
CONFIG_NULL_LSM even though there are undoubtedly systems that don't
care about permission checking[1])
-Andi
[1] I bet I gave the linux-tiny crowd an idea now ;-)
On Sunday 30 September 2007 3:07:42 pm Theodore Tso wrote:
> There are different kinds of security. Not all of them involve
> cryptography and IPSEC. Some of them involve armed soldiers and air
> gap firewalls. :-)
>
> Yes, normally the network is outside the Trusted Computing Base (TCB),
> but a cluster of Linux machines in a rack is roughly the same size of
> a huge Unix server tens year ago --- and it's not like Ethernet is any
> more secure than the PCI bus. So why do we consider communications
> across a PCI bus secure even though they aren't encrypted? Why,
> because normally we assume the PCI bus is inside the trust boundary,
> and so we don't worry about bad guys tapping communications between
> the CPU and the hard drive on the PCI bus.
>
> But these days, it is obviously possible to create clusters where
> certain network interfaces are only connected to machines contained
> completely inside the trust boundary, just like a PCI bus in a
> traditional server. So don't be so quick to dismiss something like
> CIPSO out of hand, just because it doesn't use IPSEC.
Sorry I'm a bit late to the discussion (been busy doing "weekend" things), but
I see that Casey, Josh, and Ted have already given a pretty good explanation
of why CIPSO is not as "evil" as it appears at first glance. I won't restate
the points they have already made, but I think there are two other points
worth mentioning:
The first is that CIPSO options are immutable, which means they work
wonderfully with IPsec. Label integrity can be provided through the use of
AH and/or tunneled ESP, label confidentiality can be provided through
tunneled ESP. While the SELinux specific labeled IPsec implementation we
currently have in the kernel is nice if you are talking to other SELinux
machines, it has a very real handicap in that you can't use it to talk
anything else. CIPSO, or CIPSO in combination with standard, non-labeled
IPsec, can be used to talk to pretty much any trusted OSs out there.
Adherence to standards and interoperability with other OSs have always been a
key factor of Linux's acceptance into new areas; support for CIPSO is just
another part of this drive for greater interoperability.
The second point I wanted to make is that in the course of putting together
the CIPSO implementation in the kernel I ended up talking with a few people
who were involved in the original TSIG effort and the mess with the IETF.
>From what I could gather, the main technical complaint (other than a variety
of political complaints which aren't relevant to our discussion here) was
that CIPSO options are difficult to parse (they are, look at the format -
it's an option within an option format - yuck) and the intermediate node
vendors did not like it all (too much work to do in a fastpath ASIC). After
all, look at the [R]IPSO RFC, dated only eight months earlier, and there is
no cryptographic "special sauce" in that protocol.
CIPSO isn't for everyone, I'll be the first to admit that. However, if you
look at the mailing list archive for the Linux LSPP effort, the SELinux list,
and to a lesser extent the netdev and LSM lists you will see that there are a
set of users who care very much about this functionality. Our support of
CIPSO is helping Linux operate in areas it wouldn't be able to elsewhere and
I consider that a "win".
--
paul moore
linux security @ hp
On Sun, Sep 30, 2007 at 10:05:57PM +0200, Andi Kleen wrote:
> > but a cluster of Linux machines in a rack is roughly the same size of
> > a huge Unix server tens year ago --- and it's not like Ethernet is any
> > more secure than the PCI bus.
>
> PCI busses normally don't have routers to networks outside the box connected
> to them.
The whole *point* is that the routers are interconnecting boxes inside
the cluster, and none of them connect to the outside world. It's no
different than a SCSI cable connecting to JBOD in a separate box, or a
Fiber Channel router connected to a SAN network connecting to a
storrage array. The SCSI or FC buses aren't encrypted either, and the
in the Fiber channel case we have a router --- yet people aren't
stressing out that we're not encrpying the traffic over the Storage
Area Network? Why? Because it's understood the network stays inside
the machine room. The same thing can true for Ethernet --- think
iSCSI, for example.
> > So don't be so quick to dismiss something like
> > CIPSO out of hand, just because it doesn't use IPSEC.
>
> With your argumentation we could also just disable all security
> in these situations (as in null LSM to save some overhead); after all these
> systems are protected by armed guards. If someone gets past the guards
> they could connect their laptop to the network and fake all the "secured"
> packets. If you assume that won't happen why do you need computer security at all?
If you get past all of the guards, you can usually reboot in single
user mode, and get root anyway. If you have physical access to the
computer, you're generally doomed anyway, unless you are willing to
pay the cost of encrypting everything on every single disk platter.
(And yes, in the more paranoid environments, where it's too expensive
to have 7x24 armed guards, maybe that makes sense.)
The point of something like CIPSO is because you want to label the
packets so the otherside knows how they should be treated. We don't
encrypt unix permission bits on most on-disk filesystems, either. Yet
I haven't heard people saying that just because someone could break
into a machine room, disconnect the JBOD from the computer, hook up
the JBOD to their laptop, and futz with the Unix permission bits,
rehook up the JBOD and reboot, that Unix permission bits are useless,
and we should leave all files at mode 777 --- since clearly we're not
secure against someone who can break into the machine room.....
I *hope* that sounds absurd, right?
- Ted
On Sunday 30 September 2007 4:16:18 am Andrew Morton wrote:
> - hm, netlabels. Who might be a suitable person to review that code?
> Seems that Paul Moore is the man. Maybe he'd be interested in taking a
> look over it (please?)
Yep, I've been tracking Casey's work on this since the first patch and sending
comments when appropriate. I'm going to take a look at the latest rev of the
patch and if anything looks awry I'll be sure to let Casey know.
The only real wart that still remains from the original patch is the code in
smk_cipso_doi() which has a nice comment at the top saying that Paul and
Casey need to work out an appropriate interface between NetLabel and SMACK.
We punted on it before because SMACK's future was still a bit uncertain and
SELinux has no need for an interface like this at present. Now that SMACK
looks to be queued up for 2.6.24 it's time to revisit this discussion.
--
paul moore
linux security @ hp
On Sun, 30 Sep 2007, Andi Kleen wrote:
>> The authentication issues are very real, but a separate issue.
>
> First rule of network security: don't trust the network.
This I agree with
> Without authentication it's completely useless. I don't understand
> how you can disregard that as "separate issue". Security is only
> secure if you plugged all applicable holes; without that it's useless
> and you might as well not bother.
but this is so silly that I have to object.
saying that any security short of perfect security is worthless and we
shouldn't bother is wrong, and needs to be countered every time it's
said.
as ted pointed out in response to your other comments, it very much
depends on where the trust boundry is. so from the point of view of
absolute security you are wrong.
but even more then that, the vast majority of the time absolute security
isn't what matters, relative security is what matters (the model of "I
don't have to outrun the bear, I only have to outrun you") and in these
envrionments things that are less then absolute can still be very useful.
how useful they are depends on a lot of details, and in the case of the
network security being discussed it sure sounds like it's pretty close to
useless if you can't trust the network and the other machines on it, but
that is seperate from the mentality that "anything less then perfect
security is worthless and shouldn't be bothered with" which is what I'm
objecting to.
David Lang
Quoting Casey Schaufler ([email protected]):
>
> From: Casey Schaufler <[email protected]>
>
> Smack is the Simplified Mandatory Access Control Kernel.
>
> Smack implements mandatory access control (MAC) using labels
> attached to tasks and data containers, including files, SVIPC,
> and other tasks. Smack is a kernel based scheme that requires
> an absolute minimum of application support and a very small
> amount of configuration data.
>
> Smack is implemented as a clean LSM. It requires no external
> code changes and the patch modifies only the Kconfig and Makefile
> in the security directory. Smack uses extended attributes and
> provides a set of general mount options, borrowing technics used
> elsewhere. Smack uses netlabel for CIPSO labeling. Smack provides
> a pseudo-filesystem smackfs that is used for manipulation of
> system Smack attributes.
>
> The patch, patches for ls and sshd, a README, a startup script,
> and x86 binaries for ls and sshd are also available on
>
> http:/http://www.schaufler-ca.com
>
> The patch has been tested with 2.6.22, 2.6.23-rc8, and
> 2.6.23-rc8-mm2. Development has been done using Fedora Core 7
> in a virtual machine environment and on an old Sony laptop.
>
> Smack provides mandatory access controls based on the label attached
> to a task and the label attached to the object it is attempting to
> access. Smack labels are deliberately short (1-23 characters) text
> strings. Single character labels using special characters are reserved
> for system use. The only operation applied to Smack labels is equality
> comparison. No wildcards or expressions, regular or otherwise, are
> used.
>
> A file always gets the Smack label of the task that created it.
>
> Smack defines and uses these labels:
>
> "*" - pronounced "star"
> "_" - pronounced "floor"
> "^" - pronounced "hat"
> "?" - pronounced "huh"
>
> The access rules enforced by Smack are, in order:
>
> 1. Any access requested by a task labeled "*" is denied.
> 2. A read or execute access requested by a task labeled "^"
> is permitted.
> 3. A read or execute access requested on an object labeled "_"
> is permitted.
> 4. Any access requested on an object labeled "*" is permitted.
> 5. Any access requested by a task on an object with the same
> label is permitted.
> 6. Any access requested that is explicitly defined in the loaded
> rule set is permitted.
> 7. Any other access is denied.
>
> Rules may be explicitly defined by writing subject,object,access
> triples to /smack/load.
>
> Smack rule sets can be easily defined that describe Bell&LaPadula
> sensitivity, Biba integrity, and a variety of interesting
> configurations. Smack rule sets can be modified on the fly to
> accomodate changes in the operating environment or even the time
> of day.
>
> Some practical use cases:
>
> Hierarchical levels. The less common of the two usual uses
> for MLS systems is to define hierarchical levels, often
> unclassified, confidential, secret, and so on. To set up smack
> to support this, these rules could be defined:
>
> C Unclass rx
> S C rx
> S Unclass rx
> TS S rx
> TS C rx
> TS Unclass rx
>
> A TS process can read S, C, and Unclass data, but cannot write it.
> An S process can read C and Unclass. Note that specifying that
> TS can read S and S can read C does not imply TS can read C, it
> has to be explicitly stated.
>
> Non-hierarchical categories. This is the more common of the
> usual uses for an MLS system. Since the default rule is that a
> subject cannot access an object with a different label no
> access rules are required to implement compartmentalization.
>
> A case that the Bell & LaPadula policy does not allow is demonstrated
> with this Smack access rule:
>
> A case that Bell&LaPadula does not allow that Smack does:
>
> ESPN ABC r
> ABC ESPN r
>
> On my portable video device I have two applications, one that
> shows ABC programming and the other ESPN programming. ESPN wants
> to show me sport stories that show up as news, and ABC will
> only provide minimal information about a sports story if ESPN
> is covering it. Each side can look at the other's info, neither
> can change the other. Neither can see what FOX is up to, which
> is just as well all things considered.
>
> Another case that I especially like:
>
> SatData Guard w
> Guard Publish w
>
> A program running with the Guard label opens a UDP socket and
> accepts messages sent by a program running with a SatData label.
> The Guard program inspects the message to ensure it is wholesome
> and if it is sends it to a program running with the Publish label.
> This program then puts the information passed in an appropriate
> place. Note that the Guard program cannot write to a Publish
> file system object because file system semanitic require read as
> well as write.
>
> The four cases (categories, levels, mutual read, guardbox) here
> are all quite real, and problems I've been asked to solve over
> the years. The first two are easy to do with traditonal MLS systems
> while the last two you can't without invoking privilege, at least
> for a while.
>
>
> Signed-off-by: Casey Schaufler <[email protected]>
>
> ---
>
> Changes since the previous version:
>
> - Smack labels can now be up to 23 characters in length. My UI
> expert advised that 12 was the absolute minimum, and CIPSO
> starts to get troublesome at 30.
>
> - Reading the SMACK64PACKET attribute from a socket used to provide
> the label of the last packet delivered. Now it provides the label
> of the packet returned by the most recent recv call, or ENOATTR
> if that value is not available. It's better to get no value than
> an incorrect value.
>
> Documentation/Smack.txt | 104 +
> security/Kconfig | 1
> security/Makefile | 2
> security/smack/Kconfig | 10
> security/smack/Makefile | 9
> security/smack/smack.h | 207 ++
> security/smack/smack_access.c | 345 ++++
> security/smack/smack_lsm.c | 2685 ++++++++++++++++++++++++++++++++
> security/smack/smackfs.c | 1201 ++++++++++++++
> 9 files changed, 4564 insertions(+)
>
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/Documentation/Smack.txt linux-2.6.23-rc8-smack/Documentation/Smack.txt
> --- linux-2.6.23-rc8-base/Documentation/Smack.txt 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.23-rc8-smack/Documentation/Smack.txt 2007-09-25 15:30:37.000000000 -0700
> @@ -0,0 +1,104 @@
> +
> +
> + "Good for you, you've decided to clean the elevator!"
> + - The Elevator, from Dark Star
> +
> +Smack is the the Simplified Mandatory Access Control Kernel.
> +Smack is a kernel based implementation of mandatory access
> +control that includes simplicity in its primary design goals.
> +
> +Smack does not implement Domain Type Enforcement (DTE). If
> +you want DTE Linux has an implementation called SELinux.
> +Those who really want DTE are encouraged to use SELinux.
> +Those who don't know what DTE is are encouraged to compare
> +SELinux with Smack to determine which mechanisms are best
> +suited to the problem at hand.
> +
> +Smack consists of three major components:
> + - The kernel
> + - A start-up script and a few modified applications
> + - Configuration data
> +
> +The kernel component of Smack is implemented as a Linux
> +Security Modules (LSM) module. It requires netlabel and
> +works best with file systems that support extended attributes,
> +although xattr support is not strictly required. The Smack
> +patch is (currently) self contained, except for Kconfig
> +and Makefile changes in the security directory. It is safe
> +to run a Smack kernel under a "vanilla" distribution.
> +Smack kernels use the CIPSO IP option. Some network
> +configurations are intolerant of IP options and can impede
> +access to systems that use them as Smack does.
> +
> +The startup script etc-init.d-smack should be installed
> +in /etc/init.d/smack and should be invoked early in the
> +start-up process. On Fedora rc5.d/S02smack is recommended.
> +This script ensures that certain devices have the correct
> +Smack attributes and loads the Smack configuration if
> +any is defined.
> +
> +A version of "ls" that provides a "-M" option to display
> +Smack labels on long listing is available.
> +
> +A hacked version of sshd that allows network logins by users
> +with specific Smack labels is available. This version does
> +not work for scp. You must set the /etc/ssh/sshd_config
> +line:
> + UsePrivilegeSeparation no
> +
> +The format of /etc/smack/usr is:
> +
> + username smack
> +
> +In keeping with the intent of Smack, configuration data is
> +minimal and not strictly required. The most important
> +configuration step is mounting the smackfs pseudo filesystem.
> +
> +Add this line to /etc/fstab:
> +
> + smackfs /smack smackfs smackfsdef=* 0 0
> +
> +and create the /smack directory for mounting.
> +
> +Smack uses extended attributes (xattrs) to store file labels.
> +The command to set a Smack label on a file is:
> +
> + # attr -S -s SMACK64 -V "value" path
> +
> +NOTE: Smack labels are limited to 23 characters. The attr command
> + does not enforce this restriction and can be used to set
> + invalid Smack labels on files.
> +
> +The smackfs filesystem treats symbolic links in a special way.
> +The Smack label of the process is appended to the link value
> +during resolution. To provide a /tmp that is available to users
> +with multiple labels:
> +
> + # mkdir /moldy
> + # mv /tmp /moldy/_
> + # ln -s /smack/tmp /tmp
> +
> +For each label users are going to use:
> +
> + # mkdir /moldy/label
> + # chmod <appropriate-value> /moldy/label
> + # attr -S -s SMACK64 -V "label" /moldy/label
> +
> +If you don't do anything special all users will get the floor ("_")
> +label when they log in. If you do want to log in via the hacked ssh
> +at other labels use the attr command to set the smack value on the
> +home directory and it's contents.
> +
> +You can add access rules in /etc/smack/accesses. They take the form:
> +
> + subjectlabel objectlabel access
> +
> +access is a combination of the letters rwxa which specify the
> +kind of access permitted a subject with subjectlabel on an
> +object with objectlabel. If there is no rule no access is allowed.
> +
> +A process can see the smack label it is running with by
> +reading /proc/self/attr/current. A privileged process can
> +set the process smack by writing there.
Ok, so to control smack label transitions, basically you would
run with CAP_MAC_OVERRIDE (see my note later) so that you're
allowed to change your smack label by writing to
/proc/self/attr/current, then you drop CAP_MAC_OVERRIDE, then you're
no longer able to change your label? I.e. no inherent label changing
rules through smack itself?
Just making sure I have that right. If I do, then I think at least
defining the word 'privileged' above, given that this is mac,
would help.
> +
> +
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/Kconfig linux-2.6.23-rc8-smack/security/Kconfig
> --- linux-2.6.23-rc8-base/security/Kconfig 2007-07-08 16:32:17.000000000 -0700
> +++ linux-2.6.23-rc8-smack/security/Kconfig 2007-09-25 15:30:37.000000000 -0700
> @@ -94,6 +94,7 @@ config SECURITY_ROOTPLUG
> If you are unsure how to answer this question, answer N.
>
> source security/selinux/Kconfig
> +source security/smack/Kconfig
>
> endmenu
>
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/Makefile linux-2.6.23-rc8-smack/security/Makefile
> --- linux-2.6.23-rc8-base/security/Makefile 2007-07-08 16:32:17.000000000 -0700
> +++ linux-2.6.23-rc8-smack/security/Makefile 2007-09-25 15:30:37.000000000 -0700
> @@ -4,6 +4,7 @@
>
> obj-$(CONFIG_KEYS) += keys/
> subdir-$(CONFIG_SECURITY_SELINUX) += selinux
> +subdir-$(CONFIG_SECURITY_SMACK) += smack
>
> # if we don't select a security model, use the default capabilities
> ifneq ($(CONFIG_SECURITY),y)
> @@ -14,5 +15,6 @@ endif
> obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
> # Must precede capability.o in order to stack properly.
> obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
> +obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
> obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
> obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/Kconfig linux-2.6.23-rc8-smack/security/smack/Kconfig
> --- linux-2.6.23-rc8-base/security/smack/Kconfig 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.23-rc8-smack/security/smack/Kconfig 2007-09-25 15:30:38.000000000 -0700
> @@ -0,0 +1,10 @@
> +config SECURITY_SMACK
> + bool "Simplified Mandatory Access Control Kernel Support"
> + depends on NETLABEL && SECURITY_NETWORK
> + default n
> + help
> + This selects the Simplified Mandatory Access Control Kernel.
> + Smack is useful for sensitivity, integrity, and a variety
> + of other mandatory security schemes.
> + If you are unsure how to answer this question, answer N.
Might point out that no other modules must be compiled in along with
smack, and that smack will do posix capabilities.
> +
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/Makefile linux-2.6.23-rc8-smack/security/smack/Makefile
> --- linux-2.6.23-rc8-base/security/smack/Makefile 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.23-rc8-smack/security/smack/Makefile 2007-09-25 15:30:38.000000000 -0700
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for the SMACK LSM
> +#
> +
> +obj-$(CONFIG_SECURITY_SMACK) := smack.o
> +
> +smack-y := smack_lsm.o smack_access.o smackfs.o
> +
> +EXTRA_CFLAGS += -Inet/netlabel
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smack_access.c linux-2.6.23-rc8-smack/security/smack/smack_access.c
> --- linux-2.6.23-rc8-base/security/smack/smack_access.c 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.23-rc8-smack/security/smack/smack_access.c 2007-09-25 15:30:38.000000000 -0700
> @@ -0,0 +1,345 @@
> +/*
> + * Copyright (C) 2007 Casey Schaufler <[email protected]>
> + *
> + * 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, version 2.
> + *
> + * Author:
> + * Casey Schaufler <[email protected]>
> + *
> + */
> +
> +#include <linux/types.h>
> +#include <linux/fs.h>
> +#include <linux/sched.h>
> +#include "smack.h"
> +
> +struct smack_known smack_known_unset = {
> + .smk_next = NULL,
> + .smk_known = "UNSET",
> + .smk_secid = 1,
> + .smk_cipso = NULL,
> +};
> +
> +struct smack_known smack_known_huh = {
> + .smk_next = &smack_known_unset,
> + .smk_known = "?",
> + .smk_secid = 2,
> + .smk_cipso = NULL,
> +};
> +
> +struct smack_known smack_known_hat = {
> + .smk_next = &smack_known_huh,
> + .smk_known = "^",
> + .smk_secid = 3,
> + .smk_cipso = NULL,
> +};
> +
> +struct smack_known smack_known_star = {
> + .smk_next = &smack_known_hat,
> + .smk_known = "*",
> + .smk_secid = 4,
> + .smk_cipso = NULL,
> +};
> +
> +struct smack_known smack_known_floor = {
> + .smk_next = &smack_known_star,
> + .smk_known = "_",
> + .smk_secid = 5,
> + .smk_cipso = NULL,
> +};
> +
> +struct smack_known smack_known_invalid = {
> + .smk_next = &smack_known_floor,
> + .smk_known = "",
> + .smk_secid = 6,
> + .smk_cipso = NULL,
> +};
> +
> +struct smack_known *smack_known = &smack_known_invalid;
> +/*
> + * The initial value needs to be bigger than any of the
> + * known values above.
> + */
> +static u32 smack_next_secid = 10;
> +
> +extern struct smk_list_entry *smack_list;
> +
> +/**
> + * smk_access - determine if a subject has a specific access to an object
> + * @subject_label: a pointer to the subject's Smack label
> + * @object_label: a pointer to the object's Smack label
> + * @request: the access requested, in "MAY" format
> + *
> + * This function looks up the subject/object pair in the
> + * access rule list and returns 0 if the access is permitted,
> + * non zero otherwise.
> + *
> + * Even though Smack labels are usually shared on smack_list
> + * labels that come in off the network can't be imported
> + * and added to the list for locking reasons.
> + *
> + * Therefore, it is necessary to check the contents of the labels,
> + * not just the pointer values. Of course, in most cases the labels
> + * will be on the list, so checking the pointers may be a worthwhile
> + * optimization.
> + */
> +int smk_access(char *subject_label, char *object_label, int request)
> +{
> + u32 may = MAY_NOT;
> + struct smk_list_entry *sp;
> + struct smack_rule *srp;
> +
> + /*
> + * Hardcoded comparisons.
> + *
> + * A star subject can't access any object.
> + */
> + if (subject_label == smack_known_star.smk_known ||
> + strcmp(subject_label, smack_known_star.smk_known) == 0)
> + return -EACCES;
> + /*
> + * A star object can be accessed by any subject.
> + */
> + if (object_label == smack_known_star.smk_known ||
> + strcmp(object_label, smack_known_star.smk_known) == 0)
> + return 0;
> + /*
> + * An object can be accessed in any way by a subject
> + * with the same label.
> + */
> + if (subject_label == object_label ||
> + strcmp(subject_label, object_label) == 0)
> + return 0;
> + /*
> + * A hat subject can read any object.
> + * A floor object can be read by any subject.
> + */
> + if ((request & MAY_ANYREAD) == request) {
> + if (object_label == smack_known_floor.smk_known ||
> + strcmp(object_label, smack_known_floor.smk_known) == 0)
> + return 0;
> + if (subject_label == smack_known_hat.smk_known ||
> + strcmp(subject_label, smack_known_hat.smk_known) == 0)
> + return 0;
> + }
> + /*
> + * Beyond here an explicit relationship is required.
> + * If the requested access is contained in the available
> + * access (e.g. read is included in readwrite) it's
> + * good.
> + */
> + for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
> + srp = &sp->smk_rule;
> +
> + if (srp->smk_subject == subject_label ||
> + strcmp(srp->smk_subject, subject_label) == 0) {
> + if (srp->smk_object == object_label ||
> + strcmp(srp->smk_object, object_label) == 0) {
> + may = srp->smk_access;
> + break;
> + }
> + }
> + }
> + /*
> + * This is a bit map operation.
> + */
> + if ((request & may) == request)
> + return 0;
> +
> + return -EACCES;
> +}
> +
> +/**
> + * smk_curacc - determine if current has a specific access to an object
> + * @object_label: a pointer to the object's Smack label
> + * @request: the access requested, in "MAY" format
> + *
> + * 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
> + * to override the rules.
> + */
> +int smk_curacc(char *obj_label, u32 mode)
> +{
> + int rc;
> +
> + rc = smk_access(current->security, obj_label, mode);
> + if (rc == 0)
> + return 0;
> +
> + if (capable(CAP_MAC_OVERRIDE))
> + return 0;
> +
> + return rc;
> +}
> +
> +extern struct mutex smack_known_lock;
> +
> +/**
> + * smk_import_entry - import a label, return the list entry
> + * @string: a text string that might be a Smack label
> + * @len: the maximum size, or zero if it is NULL terminated.
> + *
> + * Returns a pointer to the entry in the label list that
> + * matches the passed string, adding it if necessary.
> + */
> +struct smack_known *smk_import_entry(const char *string, int len)
> +{
> + struct smack_known *skp;
> + char smack[SMK_LABELLEN];
> + int found;
> + int i;
> +
> + if (len <= 0 || len > SMK_MAXLEN)
> + len = SMK_MAXLEN;
> +
> + for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
> + if (found)
> + smack[i] = '\0';
> + else if (i >= len || string[i] > '~' || string[i] <= ' ') {
> + smack[i] = '\0';
> + found = 1;
> + }
> + else
> + smack[i] = string[i];
> + }
> +
> + if (smack[0] == '\0')
> + return NULL;
> +
> + mutex_lock(&smack_known_lock);
> +
> + for (skp = smack_known; skp != NULL; skp = skp->smk_next)
> + if (skp->smk_known == smack)
> + break;
> +
> + if (skp == NULL) {
> + skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
> + if (skp != NULL) {
> + skp->smk_next = smack_known;
> + strncpy(skp->smk_known, smack, SMK_MAXLEN);
> + skp->smk_secid = smack_next_secid++;
> + skp->smk_cipso = NULL;
> + spin_lock_init(&skp->smk_cipsolock);
> + smack_known = skp;
> + }
> + }
> +
> + mutex_unlock(&smack_known_lock);
> +
> + return skp;
> +}
> +
> +/**
> + * smk_import - import a smack label
> + * @string: a text string that might be a Smack label
> + * @len: the maximum size, or zero if it is NULL terminated.
> + *
> + * Returns a pointer to the label in the label list that
> + * matches the passed string, adding it if necessary.
> + */
> +char *smk_import(const char *string, int len)
> +{
> + struct smack_known *skp;
> +
> + skp = smk_import_entry(string, len);
> + if (skp == NULL)
> + return NULL;
> + return skp->smk_known;
> +}
> +
> +/**
> + * smack_from_secid - find the Smack label associated with a secid
> + * @secid: an integer that might be associated with a Smack label
> + *
> + * Returns a pointer to the appropraite Smack label if there is one,
> + * otherwise a pointer to the invalid Smack label.
> + */
> +char *smack_from_secid(const u32 secid)
> +{
> + struct smack_known *skp;
> +
> + for (skp = smack_known; skp != NULL; skp = skp->smk_next)
> + if (skp->smk_secid == secid)
> + return skp->smk_known;
> +
> + /*
> + * If we got this far someone asked for the translation
> + * of a secid that is not on the list.
> + */
> + return smack_known_invalid.smk_known;
> +}
> +
> +u32 smack_to_secid(const char *smack)
> +{
> + struct smack_known *skp;
> +
> + for (skp = smack_known; skp != NULL; skp = skp->smk_next)
> + if (skp->smk_known == smack)
> + return skp->smk_secid;
> + return 0;
> +}
> +
> +/**
> + * smack_from_cipso - find the Smack label associated with a CIPSO option
> + * @level: Bell & LaPadula level from the network
> + * @catset: Bell & LaPadula categories from the network
> + * @result: where to put the Smack value
> + *
> + * This is a simple lookup in the label table.
> + *
> + * This is an odd duck as far as smack handling goes in that
> + * it sends back a copy of the smack label rather than a pointer
> + * to the master list. This is done because it is possible for
> + * a foreign host to send a smack label that is new to this
> + * machine and hence not on the list. That would not be an
> + * issue except that adding an entry to the master list can't
> + * be done at that point.
> + */
> +void smack_from_cipso(u32 level, char *catset, char *result)
> +{
> + struct smack_known *kp;
> + char *final = NULL;
> +
> + for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) {
> + if (kp->smk_cipso == NULL)
> + continue;
> +
> + spin_lock_bh(&kp->smk_cipsolock);
> +
> + if (kp->smk_cipso->smk_level == level &&
> + memcmp(kp->smk_cipso->smk_catset,catset,SMK_LABELLEN) == 0)
> + final = kp->smk_known;
> +
> + spin_unlock_bh(&kp->smk_cipsolock);
> + }
> + if (final == NULL)
> + final = smack_known_huh.smk_known;
> + strncpy(result, final, SMK_MAXLEN);
> + return;
> +}
> +
> +/**
> + * smack_to_cipso - find the CIPSO option to go with a Smack label
> + * @smack: a pointer to the smack label in question
> + * @cp: where to put the result
> + *
> + * Returns zero if a value is available, non-zero otherwise.
> + */
> +int smack_to_cipso(const char *smack, struct smack_cipso *cp)
> +{
> + struct smack_known *kp;
> +
> + for (kp = smack_known; kp != NULL; kp = kp->smk_next)
> + if (kp->smk_known == smack ||
> + strcmp(kp->smk_known, smack) == 0)
> + break;
> +
> + if (kp == NULL || kp->smk_cipso == NULL)
> + return -ENOENT;
> +
> + memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
> + return 0;
> +}
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smackfs.c linux-2.6.23-rc8-smack/security/smack/smackfs.c
> --- linux-2.6.23-rc8-base/security/smack/smackfs.c 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.23-rc8-smack/security/smack/smackfs.c 2007-09-25 15:30:38.000000000 -0700
> @@ -0,0 +1,1201 @@
> +/*
> + * Copyright (C) 2007 Casey Schaufler <[email protected]>
> + *
> + * 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, version 2.
> + *
> + * Author:
> + * Casey Schaufler <[email protected]>
> + *
> + * Special thanks to the authors of selinuxfs.
> + *
> + * Karl MacMillan <[email protected]>
> + * James Morris <[email protected]>
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/vmalloc.h>
> +#include <linux/security.h>
> +#include <linux/mutex.h>
> +#include <net/netlabel.h>
> +/*
> + * This include could get changed when the internal
> + * netlabel interface for initializing a netlabel domain
> + * has been worked out.
> + */
> +#include "netlabel_domainhash.h"
> +#include <net/cipso_ipv4.h>
> +#include "smack.h"
> +
> +extern struct mutex smack_list_lock;
> +extern struct smack_known smack_known_floor;
> +extern struct smack_known smack_known_star;
> +extern struct smack_known *smack_known;
> +
> +/*
> + * smackfs pseudo filesystem.
> + */
> +
> +enum smk_inos {
> + SMK_ROOT_INO = 2,
> + SMK_LOAD = 3, /* load policy */
> + SMK_LINKS = 4, /* symlinks */
> + SMK_CIPSO = 5, /* load label -> CIPSO mapping */
> + SMK_DOI = 6, /* CIPSO DOI */
> + SMK_DIRECT = 7, /* CIPSO level indicating direct label */
> + SMK_AMBIENT = 8, /* internet ambient label */
> + SMK_NLTYPE = 9, /* label scheme to use by default */
> + SMK_TMP = 100, /* MUST BE LAST! /smack/tmp */
> +};
> +
> +/*
> + * This is the "ambient" label for network traffic.
> + * If it isn't somehow marked, use this.
> + * It can be reset via smackfs/ambient
> + */
> +char *smack_net_ambient = smack_known_floor.smk_known;
> +
> +/*
> + * This is the default packet marking scheme for network traffic.
> + * It can be reset via smackfs/nltype
> + */
> +int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
> +
> +/*
> + * This is the level in a CIPSO header that indicates a
> + * smack label is contained directly in the category set.
> + * It can be reset via smackfs/direct
> + */
> +int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
> +
> +static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
> +static int smack_list_count;
> +struct smk_list_entry *smack_list;
> +
> +/*
> + * 'ssssssss oooooooo mmmm\n\0'
> + */
> +#define SMACK_RULE_LINE_SIZE (2 * SMK_MAXLEN + 6)
> +
> +/**
> + * smk_read_load - read() for /smack/load
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @count: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_load(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + ssize_t bytes;
> + struct smk_list_entry *slp = smack_list;
> + struct smack_rule *srp;
> + char *result;
> + char *cp;
> + int realbytes = 0;
> +
> + bytes = SMACK_RULE_LINE_SIZE * smack_list_count;
> + if (bytes == 0)
> + return 0;
> +
> + result = kzalloc(bytes, GFP_KERNEL);
> + if (result == NULL)
> + return -ENOMEM;
> +
> + for (cp = result; slp != NULL; slp = slp->smk_next) {
> + srp = &slp->smk_rule;
> + sprintf(cp, "%-8s %-8s",
> + (char *)srp->smk_subject, (char *)srp->smk_object);
> + cp += strlen(cp);
> + if (srp->smk_access != 0)
> + *cp++ = ' ';
> + if ((srp->smk_access & MAY_READ) != 0)
> + *cp++ = 'r';
> + if ((srp->smk_access & MAY_WRITE) != 0)
> + *cp++ = 'w';
> + if ((srp->smk_access & MAY_EXEC) != 0)
> + *cp++ = 'x';
> + if ((srp->smk_access & MAY_APPEND) != 0)
> + *cp++ = 'a';
> + *cp++ = '\n';
> + }
> + *cp++ = '\0';
> + realbytes = strlen(result);
> +
> + bytes = simple_read_from_buffer(buf, count, ppos, result, realbytes);
> +
> + kfree(result);
> +
> + return bytes;
> +}
> +
> +/**
> + * smk_set_access - add a rule to the rule list
> + * @srp: the new rule to add
> + *
> + * Looks through the current subject/object/access list for
> + * the subject/object pair and replaces the access that was
> + * there. If the pair isn't found add it with the specified
> + * access.
> + */
> +static void smk_set_access(struct smack_rule *srp)
> +{
> + struct smk_list_entry *sp;
> + struct smk_list_entry *newp;
> +
> + mutex_lock(&smack_list_lock);
> +
> + for (sp = smack_list; sp != NULL; sp = sp->smk_next)
> + if (sp->smk_rule.smk_subject == srp->smk_subject &&
> + sp->smk_rule.smk_object == srp->smk_object) {
> + sp->smk_rule.smk_access = srp->smk_access;
> + break;
> + }
> +
> + if (sp == NULL) {
> + newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
> + newp->smk_rule = *srp;
> + newp->smk_next = smack_list;
> + smack_list = newp;
> + smack_list_count++;
> + }
> +
> + mutex_unlock(&smack_list_lock);
> +
> + return;
> +}
> +
> +
> +/**
> + * smk_write_load - write() for /smack/load
> + * @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_load(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + struct smack_rule rule;
> + ssize_t rc = count;
> + char *data = NULL;
> + char subjectstr[SMK_LABELLEN];
> + char objectstr[SMK_LABELLEN];
> + char modestr[8];
> + char *cp;
> +
> +
> + if (!capable(CAP_MAC_OVERRIDE))
> + return -EPERM;
> + /*
> + * No partial writes.
> + */
> + if (*ppos != 0)
> + return -EINVAL;
> +
> + /*
> + * 80 characters per line ought to be enough.
> + */
> + if (count > SMACK_LIST_MAX * 80)
> + return -ENOMEM;
> +
> + data = kzalloc(count + 1, GFP_KERNEL);
> + if (data == NULL)
> + return -ENOMEM;
> +
> + if (copy_from_user(data, buf, count) != 0) {
> + kfree(data);
> + return -EFAULT;
> + }
> +
> + *(data + count) = '\0';
> +
> + for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
> + if (*++cp == '\0')
> + break;
> + if (sscanf(cp, "%23s %23s %7s\n", subjectstr, objectstr,
> + modestr) != 3) {
> + printk("%s:%d bad scan\n", __func__, __LINE__);
> + break;
> + }
> + rule.smk_subject = smk_import(subjectstr, 0);
> + if (rule.smk_subject == NULL)
> + break;
> + rule.smk_object = smk_import(objectstr, 0);
> + if (rule.smk_object == NULL)
> + break;
> + rule.smk_access = 0;
> + if (strpbrk(modestr, "rR") != NULL)
> + rule.smk_access |= MAY_READ;
> + if (strpbrk(modestr, "wW") != NULL)
> + rule.smk_access |= MAY_WRITE;
> + if (strpbrk(modestr, "xX") != NULL)
> + rule.smk_access |= MAY_EXEC;
> + if (strpbrk(modestr, "aA") != NULL)
> + rule.smk_access |= MAY_APPEND;
> + smk_set_access(&rule);
> + printk("%s:%d rule %s %s 0x%x\n", __func__, __LINE__,
> + (char *)rule.smk_subject, (char *)rule.smk_object,
> + rule.smk_access);
Are you sure this isn't something you'd like to really audit?
(Sorry if that's been asked before)
> + }
> +
> + kfree(data);
> + return rc;
> +}
> +
> +static const struct file_operations smk_load_ops = {
> + .read = smk_read_load,
> + .write = smk_write_load,
> +};
> +
> +/**
> + * smk_digit - return a pointer to the next digit
> + * @cp: where to start
> + *
> + * Returns a pointer to the next digit in the string, or NULL
> + */
> +static inline char *smk_digit(const char *cp)
> +{
> + return strpbrk(cp, "0123456789");
> +}
> +
> +static unsigned int smk_cipso_written;
> +
> +/**
> + * smk_cipso_doi - initialize the CIPSO domain
> + *
> + * This code reaches too deeply into netlabel internals
> + * for comfort, however there is no netlabel KAPI that
> + * allows for kernel based initialization of a CIPSO DOI.
> + * Until Paul and Casey can work out an appropriate
> + * interface Smack will do it this way.
> + */
> +void smk_cipso_doi(void)
> +{
> + int rc;
> + struct cipso_v4_doi *doip;
> + struct netlbl_dom_map *ndmp;
> + struct netlbl_audit audit_info;
> +
> + doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL);
> + if (doip == NULL)
> + panic("smack: Failed to initialize cipso DOI.\n");
> + doip->map.std = NULL;
> +
> + ndmp = kmalloc(sizeof(struct netlbl_dom_map), GFP_KERNEL);
> + if (ndmp == NULL)
> + panic("smack: Failed to initialize cipso ndmp.\n");
> +
> + doip->doi = smk_cipso_doi_value;
> + doip->type = CIPSO_V4_MAP_PASS;
> + doip->tags[0] = CIPSO_V4_TAG_RBITMAP;
> + for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
> + doip->tags[rc] = CIPSO_V4_TAG_INVALID;
> +
> + rc = cipso_v4_doi_add(doip);
> + if (rc != 0)
> + printk("%s:%d add doi rc = %d\n", __func__, __LINE__, rc);
> +
> + ndmp->domain = NULL;
> + ndmp->type = NETLBL_NLTYPE_CIPSOV4;
> + ndmp->type_def.cipsov4 = doip;
> +
> + rc = netlbl_domhsh_remove_default(&audit_info);
> + if (rc != 0)
> + printk("%s:%d remove rc = %d\n", __func__, __LINE__, rc);
> +
> + rc = netlbl_domhsh_add_default(ndmp, &audit_info);
> + if (rc != 0)
> + printk("%s:%d add rc = %d\n", __func__, __LINE__, rc);
> +}
> +
> +/**
> + * smk_read_cipso - read() for /smack/cipso
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @count: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + *
> + * label level[/cat[,cat]]
> + */
> +static ssize_t smk_read_cipso(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + struct smack_known *skp;
> + struct smack_cipso *scp;
> + ssize_t bytes;
> + char sep;
> + char *result;
> + char *cp;
> + char *cbp;
> + int realbytes = 0;
> + int cat = -1;
> + int i;
> + unsigned char m;
> +
> + if (smk_cipso_written == 0)
> + return 0;
> +
> + result = kzalloc(smk_cipso_written, GFP_KERNEL);
> + if (result == NULL)
> + return -ENOMEM;
> + cp = result;
> +
> + for (skp = smack_known; skp != NULL; skp = skp->smk_next) {
> + if (skp->smk_cipso == NULL)
> + continue;
> + scp = skp->smk_cipso;
> + cp += sprintf(cp, "%-8s %3d",
> + (char *)&skp->smk_known, scp->smk_level);
> + cat = 1;
> + sep = '/';
> + cbp = scp->smk_catset;
> + for (i = 0; i < SMK_LABELLEN; i++) {
> + for (m = 0x80; m != 0; m >>= 1) {
> + if ((m & cbp[i]) != 0) {
> + cp += sprintf(cp, "%c%d", sep, cat);
> + sep = ',';
> + }
> + cat++;
> + }
> + }
> + *cp++ = '\n';
> + }
> + *cp++ = '\0';
> + realbytes = strlen(result);
> +
> + bytes = simple_read_from_buffer(buf, count, ppos, result, realbytes);
> +
> + kfree(result);
> +
> + return bytes;
> +}
> +
> +/**
> + * smk_write_cipso - write() for /smack/cipso
> + * @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_cipso(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + struct smack_known *skp;
> + struct smack_cipso *scp;
> + char *mapsmack;
> + char mapcatset[SMK_LABELLEN];
> + int maplevel;
> + ssize_t rc = count;
> + char *data = NULL;
> + char *cp;
> + char *eolp;
> + char *linep;
> + int cat;
> + int i;
> +
> + if (!capable(CAP_MAC_OVERRIDE))
> + return -EPERM;
> + /*
> + * No partial writes.
> + */
> + if (*ppos != 0)
> + return -EINVAL;
> + /*
> + * 80 characters per line ought to be enough.
> + */
> + if (count > SMACK_LIST_MAX * 80)
> + return -ENOMEM;
> +
> + data = kzalloc(count + 1, GFP_KERNEL);
> + if (data == NULL)
> + return -ENOMEM;
> +
> + if (copy_from_user(data, buf, count) != 0) {
> + kfree(data);
> + return -EFAULT;
> + }
> +
> + *(data + count) = '\0';
> + smk_cipso_written += count;
> +
> + for (eolp = strchr(data, '\n'), linep = data;
> + eolp != NULL && rc >= 0;
> + linep = eolp + 1, eolp = strchr(linep, '\n')) {
> +
> + if (eolp == linep)
> + continue;
> + *eolp = '\0';
> + memset(mapcatset, '\0', SMK_LABELLEN);
> +
> + skp = smk_import_entry(linep, 0);
> + if (skp == NULL)
> + continue;
> + mapsmack = skp->smk_known;
> +
> + cp = smk_digit(linep + strlen((char *)mapsmack));
> + if (cp == NULL)
> + continue;
> +
> + i = sscanf(cp, "%d", &maplevel);
> + if (i != 1)
> + continue;
> +
> + cp = strchr(cp, '/');
> + if (cp != NULL) {
> + cp = smk_digit(cp);
> + if (cp == NULL)
> + continue;
> +
> + do {
> + i = sscanf(cp, "%d", &cat);
> + if (i != 1)
> + break;
> + if (cat > SMACK_CIPSO_MAXCAT) {
> + i = 0;
> + break;
> + }
> + smack_catset_bit(cat, mapcatset);
> +
> + cp = strchr(cp, ',');
> + if (cp != NULL)
> + cp = smk_digit(cp);
> + } while (cp != NULL);
> + }
> +
> + if (i != 1)
> + continue;
> +
> +
> + if (skp->smk_cipso == NULL) {
> + scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL);
> + if (scp == NULL) {
> + rc = -ENOMEM;
> + break;
> + }
> + } else
> + scp = NULL;
> +
> + spin_lock_bh(&skp->smk_cipsolock);
> + if (skp->smk_cipso == NULL) {
> + skp->smk_cipso = scp;
> + scp = NULL;
> + }
> + skp->smk_cipso->smk_level = maplevel;
> + memcpy(skp->smk_cipso->smk_catset, mapcatset, SMK_MAXLEN);
> + spin_unlock_bh(&skp->smk_cipsolock);
> +
> + /*
> + * The only way this could be true is for there
> + * to have been two attempts to update the cipso
> + * list at the same time. One of the two will have
> + * won cleanly, but there remains cleanup to do.
> + */
> + if (scp != NULL) {
> + printk(KERN_WARNING "%s: CIPSO collision for \"%s\"\n",
> + __func__, skp->smk_known);
> + kfree(scp);
> + }
> + /*
> + * Add this to ensure that there are
> + * enough bytes for the regurgitation
> + */
> + smk_cipso_written += SMK_LABELLEN;
> + }
> +
> + kfree(data);
> + return rc;
> +}
> +
> +static const struct file_operations smk_cipso_ops = {
> + .read = smk_read_cipso,
> + .write = smk_write_cipso,
> +};
> +
> +/**
> + * smk_read_doi - read() for /smack/doi
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @count: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_doi(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char temp[80];
> + ssize_t rc;
> +
> + if (*ppos != 0)
> + return 0;
> +
> + sprintf(temp, "%d", smk_cipso_doi_value);
> + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
> +
> + return rc;
> +}
> +
> +/**
> + * smk_write_doi - write() for /smack/doi
> + * @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_doi(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char temp[80];
> + int i;
> +
> + if (!capable(CAP_MAC_OVERRIDE))
> + return -EPERM;
> +
> + if (count > sizeof(temp))
> + return -EINVAL;
> +
> + if (copy_from_user(temp, buf, count) != 0)
> + return -EFAULT;
> +
> + if (sscanf(temp, "%d", &i) != 1)
> + return -EINVAL;
> +
> + smk_cipso_doi_value = i;
> +
> + return count;
> +}
> +
> +static const struct file_operations smk_doi_ops = {
> + .read = smk_read_doi,
> + .write = smk_write_doi,
> +};
> +
> +/**
> + * smk_read_direct - read() for /smack/direct
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @count: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_direct(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char temp[80];
> + ssize_t rc;
> +
> + if (*ppos != 0)
> + return 0;
> +
> + sprintf(temp, "%d", smack_cipso_direct);
> + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
> +
> + return rc;
> +}
> +
> +/**
> + * smk_write_direct - write() for /smack/direct
> + * @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_direct(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char temp[80];
> + int i;
> +
> + if (!capable(CAP_MAC_OVERRIDE))
> + return -EPERM;
> +
> + if (count > sizeof(temp))
> + return -EINVAL;
> +
> + if (copy_from_user(temp, buf, count) != 0)
> + return -EFAULT;
> +
> + if (sscanf(temp, "%d", &i) != 1)
> + return -EINVAL;
> +
> + smack_cipso_direct = i;
> +
> + return count;
> +}
> +
> +static const struct file_operations smk_direct_ops = {
> + .read = smk_read_direct,
> + .write = smk_write_direct,
> +};
> +
> +/**
> + * smk_read_ambient - read() for /smack/ambient
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @count: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + ssize_t rc;
> + int asize = strlen(smack_net_ambient) + 1;
> +
> + if (count < asize)
> + return -EINVAL;
> +
> + if (*ppos != 0)
> + return 0;
> +
> + rc = simple_read_from_buffer(buf,count,ppos,smack_net_ambient,asize);
> +
> + return rc;
> +}
> +
> +/**
> + * smk_write_ambient - write() for /smack/ambient
> + * @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_ambient(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char in[SMK_LABELLEN];
> + char *smack;
> +
> + if (!capable(CAP_MAC_OVERRIDE))
> + return -EPERM;
> +
> + if (count >= SMK_LABELLEN)
> + return -EINVAL;
> +
> + if (copy_from_user(in, buf, count) != 0)
> + return -EFAULT;
> +
> + smack = smk_import(in, count);
> + if (smack == NULL)
> + return -EINVAL;
> + /*
> + * Better check to be sure this is OK.
> + */
> + smack_net_ambient = smack;
> +
> + return count;
> +}
> +
> +static const struct file_operations smk_ambient_ops = {
> + .read = smk_read_ambient,
> + .write = smk_write_ambient,
> +};
> +
> +struct option_names {
> + int o_number;
> + char *o_name;
> + char *o_alias;
> +};
> +
> +static struct option_names netlbl_choices[] = {
> + { NETLBL_NLTYPE_RIPSO,
> + NETLBL_NLTYPE_RIPSO_NAME, "ripso" },
> + { NETLBL_NLTYPE_CIPSOV4,
> + NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" },
> + { NETLBL_NLTYPE_CIPSOV4,
> + NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" },
> + { NETLBL_NLTYPE_CIPSOV6,
> + NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" },
> + { NETLBL_NLTYPE_UNLABELED,
> + NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" },
> +};
> +
> +/**
> + * smk_read_nltype - read() for /smack/nltype
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @count: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char bound[40];
> + ssize_t rc;
> + int i;
> +
> + if (count < SMK_LABELLEN)
> + return -EINVAL;
> +
> + if (*ppos != 0)
> + return 0;
> +
> + sprintf(bound, "unknown");
> +
> + for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
> + if (smack_net_nltype == netlbl_choices[i].o_number) {
> + sprintf(bound, "%s", netlbl_choices[i].o_name);
> + break;
> + }
> +
> + rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
> +
> + return rc;
> +}
> +
> +/**
> + * smk_write_nltype - write() for /smack/nltype
> + * @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_nltype(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char bound[40];
> + char *cp;
> + int i;
> +
> + if (!capable(CAP_MAC_OVERRIDE))
> + return -EPERM;
> +
> + if (count >= 40)
> + return -EINVAL;
> +
> + if (copy_from_user(bound, buf, count) != 0)
> + return -EFAULT;
> +
> + bound[count] = '\0';
> + cp = strchr(bound, ' ');
> + if (cp != NULL)
> + *cp = '\0';
> + cp = strchr(bound, '\n');
> + if (cp != NULL)
> + *cp = '\0';
> +
> + for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
> + if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
> + strcmp(bound, netlbl_choices[i].o_alias) == 0) {
> + smack_net_nltype = netlbl_choices[i].o_number;
> + return count;
> + }
> + /*
> + * Not a valid choice.
> + */
> + return -EINVAL;
> +}
> +
> +static const struct file_operations smk_nltype_ops = {
> + .read = smk_read_nltype,
> + .write = smk_write_nltype,
> +};
> +
> +/*
> + * mapping for symlinks
> + */
> +#define SMK_TMPPATH_SIZE 1024
> +#define SMK_TMPPATH_ROOT "/moldy/"
> +
> +struct smk_link {
> + struct smk_link *sl_next;
> + int sl_inum;
> + char sl_name[SMK_TMPPATH_SIZE];
> + char sl_target[SMK_TMPPATH_SIZE];
> +};
> +
> +static struct super_block *smk_sb = NULL;
> +static struct smk_link *smk_links = NULL;
> +static int smk_links_count = 0;
> +
> +/**
> + * smackfs_follow_link - follow a smackfs symlink
> + * @dentry: name cache entry
> + * @nd: name entry
> + *
> + * A symlink on smackfs has unusual semantics.
> + *
> + * The Smack value of the task is appended to the link string.
> + * Thus, if a task labeled "Gentoo" does chdir("/smack/tmp")
> + * it will use "/moldy/Gentoo".
> + *
> + * The expected usage is the /tmp is a symlink to /smack/tmp
> + * which is itself a symlink to /moldy. /moldy should have a
> + * directory for each label in use to accomodate the value
> + * appended on the redirection.
> + *
> + * An interesting addition would be a file system that automatically
> + * creates directories as needed, at the appropriate label.
> + */
> +static void *smackfs_follow_link(struct dentry *dentry, struct nameidata *nd)
> +{
> + char *sp = current->security;
> + char *cp;
> + int inum = dentry->d_inode->i_ino;
> + struct smk_link *slp;
> +
> + for (slp = smk_links; slp != NULL; slp = slp->sl_next)
> + if (slp->sl_inum == inum)
> + break;
> +
> + if (slp == NULL) {
> + printk("%s:%d failed\n", __func__, __LINE__);
> + return NULL;
> + }
> + cp = kzalloc(SMK_TMPPATH_SIZE, GFP_KERNEL);
> + if (cp == NULL)
> + return NULL;
> +
> + strcpy(cp, slp->sl_target);
> + strcat(cp, sp);
> + nd_set_link(nd, cp);
> + /*
> + * Unlike the readlink below, hang on to the memory allocated
> + * because nd_set_link passes it along.
> + */
> + return NULL;
> +}
> +
> +/**
> + * smackfs_readlink - read a smackfs symlink
> + * @dentry: name cache entry
> + * @buffer: where the result goes
> + * @buflen: buffer size
> + *
> + * Returns 0 on success, an error code otherwise
> + *
> + * Supports the same semantics as the follow code.
> + */
> +static int smackfs_readlink(struct dentry *dentry, char __user *buffer,
> + int buflen)
> +{
> + char *csp = current->security;
> + char *cp;
> + int len;
> + int inum = dentry->d_inode->i_ino;
> + struct smk_link *slp;
> +
> + for (slp = smk_links; slp != NULL; slp = slp->sl_next)
> + if (slp->sl_inum == inum)
> + break;
> +
> + if (slp == NULL) {
> + printk("%s:%d failed\n", __func__, __LINE__);
> + return -EACCES;
> + }
> +
> + cp = kzalloc(SMK_TMPPATH_SIZE, GFP_KERNEL);
> + if (cp == NULL)
> + return -ENOMEM;
> +
> + strcpy(cp, slp->sl_target);
> + strcat(cp, csp);
> + len = strlen(cp);
> + len = (len > buflen) ? buflen : len;
> +
> + if (copy_to_user(buffer, cp, len) != 0)
> + len = -EFAULT;
> +
> + kfree(cp);
> + return len;
> +}
> +
> +/**
> + * smackfs_put_link - free a followed component
> + * @dentry: unused
> + * @nd: name entry
> + * @ptr: unused
> + *
> + * free the buffer used in following the link.
> + */
> +static void smackfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
> +{
> + kfree(nd_get_link(nd));
> +}
> +
> +static struct inode_operations smackfs_symlink_inode_operations = {
> + .readlink = smackfs_readlink,
> + .follow_link = smackfs_follow_link,
> + .put_link = smackfs_put_link,
> +};
> +
> +/**
> + * smk_add_symlink - follow a smackfs symlink
> + * @name: the name of the synlink
> + * @target: where it points to
> + *
> + * Add a smackfs symlink
> + */
> +static void smk_add_symlink(char *name, char *target)
> +{
> + static int inum = SMK_TMP;
> + struct inode *inode;
> + struct dentry *dentry;
> + struct smk_link *slp;
> +
> + for (slp = smk_links; slp != NULL; slp = slp->sl_next) {
> + if (strcmp(slp->sl_name, name) != 0)
> + continue;
> + strcpy(slp->sl_target, target);
> + return;
> + }
> +
> + slp = kzalloc(sizeof(struct smk_link), GFP_KERNEL);
> + if (slp == NULL)
> + return;
> +
> + dentry = d_alloc_name(smk_sb->s_root, name);
> + if (dentry == NULL) {
> + printk("%s:%d link dentry failed\n", __func__, __LINE__);
> + return;
> + }
> +
> + inode = new_inode(smk_sb);
> + if (inode == NULL) {
> + printk("%s:%d link inode failed\n", __func__, __LINE__);
> + return;
> + }
> +
> + inode->i_mode = S_IFLNK | S_IRWXUGO;
> + inode->i_uid = 0;
> + inode->i_gid = 0;
> + inode->i_blocks = 0;
> + inode->i_atime = CURRENT_TIME;
> + inode->i_mtime = inode->i_atime;
> + inode->i_ctime = inode->i_atime;
> + inode->i_ino = inum++;
> + inode->i_op = &smackfs_symlink_inode_operations;
> + d_add(dentry, inode);
> +
> + strcpy(slp->sl_name, name);
> + strcpy(slp->sl_target, target);
> + slp->sl_inum = inode->i_ino;
> + slp->sl_next = smk_links;
> + smk_links = slp;
> + smk_links_count++;
> +
> + return;
> +}
> +
> +/**
> + * smk_read_links - read() for /smack/links
> + * @filp: file pointer, not actually used
> + * @buf: where to put the result
> + * @count: maximum to send along
> + * @ppos: where to start
> + *
> + * Returns number of bytes read or error code, as appropriate
> + */
> +static ssize_t smk_read_links(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + ssize_t bytes = sizeof(struct smk_link) * smk_links_count;
> + struct smk_link *slp;
> + char *result;
> + char *cp;
> +
> +
> + result = kzalloc(bytes, GFP_KERNEL);
> + if (result == NULL)
> + return -ENOMEM;
> + *result = '\0';
> +
> + for (slp = smk_links, cp = result; slp != NULL; slp = slp->sl_next)
> + cp += sprintf(cp, "%s %s\n", slp->sl_name, slp->sl_target);
> +
> + bytes = simple_read_from_buffer(buf,count,ppos,result,strlen(result));
> +
> + kfree(result);
> +
> + return bytes;
> +}
> +
> +/**
> + * smk_write_links - write() for /smack/links
> + * @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
> + *
> + * This might be better done using "real" symlink creation.
> + */
> +static ssize_t smk_write_links(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + ssize_t rc = count;
> + char *data;
> + char *cp;
> + char name[SMK_TMPPATH_SIZE];
> + char target[SMK_TMPPATH_SIZE];
> +
> + /*
> + * No partial writes.
> + */
> + if (*ppos != 0)
> + return -EINVAL;
> + /*
> + * 80 characters per line ought to be enough.
> + */
> + if (count > SMACK_LIST_MAX * 80)
> + return -ENOMEM;
> +
> + data = kzalloc(count + 1, GFP_KERNEL);
> + if (data == NULL)
> + return -ENOMEM;
> +
> + if (copy_from_user(data, buf, count) != 0) {
> + kfree(data);
> + return -EFAULT;
> + }
> +
> + data[count] = '\0';
> +
> + for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
> + if (*++cp == '\0')
> + break;
> + if (sscanf(cp, "%14s %30s\n", name, target) != 2) {
> + printk("%s:%d bad scan\n",
> + __func__, __LINE__);
> + break;
> + }
> + smk_add_symlink(name, target);
> + printk("%s:%d add %s -> %s\n",
> + __func__, __LINE__, name, target);
> + }
> +
> + kfree(data);
> + return rc;
> +}
> +
> +static const struct file_operations smk_links_ops = {
> + .read = smk_read_links,
> + .write = smk_write_links,
> +};
> +
> +/**
> + * smk_fill_super - fill the /smackfs superblock
> + * @sb: the empty superblock
> + * @data: unused
> + * @silent: unused
> + *
> + * Fill in the well known entries for /smack and set up for
> + * symlinks
> + *
> + * Returns 0 on success, an error code on failure
> + */
> +static int smk_fill_super(struct super_block *sb, void * data, int silent)
> +{
> + int rc;
> + struct inode *root_inode;
> +
> + static struct tree_descr smack_files[] = {
> + [SMK_LOAD] = {"load", &smk_load_ops, S_IRUGO|S_IWUSR},
> + [SMK_LINKS] = {"links", &smk_links_ops, S_IRUGO|S_IWUSR},
> + [SMK_CIPSO] = {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
> + [SMK_DOI] = {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
> + [SMK_DIRECT] = {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
> + [SMK_AMBIENT] = {"ambient", &smk_ambient_ops,S_IRUGO|S_IWUSR},
> + [SMK_NLTYPE] = {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
> + /* last one */ {""}
> + };
> +
> + /*
> + * There will be only one smackfs. Casey says so.
> + */
> + smk_sb = sb;
> +
> + rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);
> + if (rc != 0) {
> + printk(KERN_ERR "%s failed %d while creating inodes\n",
> + __func__, rc);
> + return rc;
> + }
> +
> + root_inode = sb->s_root->d_inode;
> + root_inode->i_security = new_inode_smack(smack_known_floor.smk_known);
> +
> + /*
> + * Create a directory for /smack/tmp
> + */
> + smk_add_symlink("tmp", SMK_TMPPATH_ROOT);
> +
> + return 0;
> +}
> +
> +/**
> + * smk_get_sb - get the smackfs superblock
> + * @fs_type: passed along without comment
> + * @flags: passed along without comment
> + * @dev_name: passed along without comment
> + * @data: passed along without comment
> + * @mnt: passed along without comment
> + *
> + * Just passes everything along.
> + *
> + * Returns what the lower level code does.
> + */
> +static int smk_get_sb(struct file_system_type *fs_type,
> + int flags, const char *dev_name, void *data,
> + struct vfsmount *mnt)
> +{
> + return get_sb_single(fs_type, flags, data, smk_fill_super, mnt);
> +}
> +
> +static struct file_system_type smk_fs_type = {
> + .name = "smackfs",
> + .get_sb = smk_get_sb,
> + .kill_sb = kill_litter_super,
> +};
> +
> +static struct vfsmount *smackfs_mount;
> +
> +/**
> + * init_smk_fs - get the smackfs superblock
> + *
> + * register the smackfs
> + *
> + * Returns 0 unless the registration fails.
> + */
> +static int __init init_smk_fs(void)
> +{
> + int err;
> +
> + err = register_filesystem(&smk_fs_type);
> + if (!err) {
> + smackfs_mount = kern_mount(&smk_fs_type);
> + if (IS_ERR(smackfs_mount)) {
> + printk(KERN_ERR "smackfs: could not mount!\n");
> + err = PTR_ERR(smackfs_mount);
> + smackfs_mount = NULL;
> + }
> + }
> +
> + return err;
> +}
> +
> +__initcall(init_smk_fs);
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smack.h linux-2.6.23-rc8-smack/security/smack/smack.h
> --- linux-2.6.23-rc8-base/security/smack/smack.h 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.23-rc8-smack/security/smack/smack.h 2007-09-25 15:30:38.000000000 -0700
> @@ -0,0 +1,207 @@
> +/*
> + * Copyright (C) 2007 Casey Schaufler <[email protected]>
> + *
> + * 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, version 2.
> + *
> + * Author:
> + * Casey Schaufler <[email protected]>
> + *
> + */
> +
> +#ifndef _SECURITY_SMACK_H
> +#define _SECURITY_SMACK_H
> +
> +#include <linux/capability.h>
> +#include <linux/spinlock.h>
> +#include <net/netlabel.h>
> +
> +/*
> + * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
> + * bigger than can be used, and 24 is the next lower multiple
> + * of 8, and there are too many issues if there isn't space set
> + * aside for the terminating null byte.
> + */
> +#define SMK_MAXLEN 23
> +#define SMK_LABELLEN (SMK_MAXLEN+1)
> +
> +struct superblock_smack {
> + char *smk_root;
> + char *smk_floor;
> + char *smk_hat;
> + char *smk_default;
> + int smk_initialized;
> +};
> +
> +struct socket_smack {
> + char *smk_out; /* outbound label */
> + char *smk_in; /* inbound label */
> + char smk_packet[SMK_LABELLEN];
> + int smk_depth;
> +};
> +
> +/*
> + * Inode smack data
> + */
> +struct inode_smack {
> + char *smk_inode; /* label of the fso */
> + struct mutex smk_lock; /* initialization lock */
> + int smk_flags; /* smack inode flags */
> +};
> +
> +#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
> +
> +/*
> + * A label access rule.
> + */
> +struct smack_rule {
> + char *smk_subject;
> + char *smk_object;
> + int smk_access;
> +};
> +
> +/*
> + * An entry in the table of permitted label accesses.
> + */
> +struct smk_list_entry {
> + struct smk_list_entry *smk_next;
> + struct smack_rule smk_rule;
> +};
> +
> +/*
> + * An entry in the table mapping smack values to
> + * CIPSO level/category-set values.
> + */
> +struct smack_cipso {
> + int smk_level;
> + char smk_catset[SMK_LABELLEN];
> +};
> +
> +/*
> + * This is the repository for labels seen so that it is
> + * not necessary to keep allocating tiny chuncks of memory
> + * and so that they can be shared.
> + *
> + * Labels are never modified in place. Anytime a label
> + * is imported (e.g. xattrset on a file) the list is checked
> + * for it and it is added if it doesn't exist. The address
> + * is passed out in either case. Entries are added, but
> + * never deleted.
> + *
> + * Since labels are hanging around anyway it doesn't
> + * hurt to maintain a secid for those awkward situations
> + * where kernel components that ought to use LSM independent
> + * interfaces don't. The secid should go away when all of
> + * these components have been repaired.
> + *
> + * If there is a cipso value associated with the label it
> + * gets stored here, too. This will most likely be rare as
> + * the cipso direct mapping in used internally.
> + */
> +struct smack_known {
> + struct smack_known *smk_next;
> + char smk_known[SMK_LABELLEN];
> + u32 smk_secid;
> + struct smack_cipso *smk_cipso;
> + spinlock_t smk_cipsolock;
> +};
> +
> +/*
> + * Mount options
> + */
> +#define SMK_FSDEFAULT "smackfsdef="
> +#define SMK_FSFLOOR "smackfsfloor="
> +#define SMK_FSHAT "smackfshat="
> +#define SMK_FSROOT "smackfsroot="
> +
> +/*
> + * xattr names
> + */
> +#define XATTR_SMACK_SUFFIX "SMACK64"
> +#define XATTR_SMACK_IPIN "SMACK64IPIN"
> +#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
> +#define XATTR_SMACK_PACKET "SMACK64PACKET"
> +#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
> +
> +/*
> + * smackfs macic number
> + */
> +#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
> +
> +/*
> + * A limit on the number of entries in the lists
> + * makes some of the list administration easier.
> + */
> +#define SMACK_LIST_MAX 10000
> +
> +/*
> + * CIPSO defaults.
> + */
> +#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
> +#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */
> +#define SMACK_CIPSO_MAXCAT 63 /* Bigger gets harder */
> +
> +/*
> + * Just to make the common cases easier to deal with
> + */
> +#define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
> +#define MAY_ANYREAD (MAY_READ | MAY_EXEC)
> +#define MAY_ANYWRITE (MAY_WRITE | MAY_APPEND)
> +#define MAY_READWRITE (MAY_READ | MAY_WRITE)
> +#define MAY_NOT 0
> +
> +/*
> + * There are not enough CAP bits available to make this
> + * real, so Casey borrowed the capability that looks to
> + * him like it has the best balance of similarity amd
> + * low use.
> + */
> +#define CAP_MAC_OVERRIDE CAP_LINUX_IMMUTABLE
We're basically inevitably going to be switching to 64-bit caps
"any day now". Should we just go ahead and do it here? Now
maybe we should use a less contraversial name than 'mac override'
like 'CAP_MAC_POLICY_ADMIN' :), but I guess CAP_MAC_OVERRIDE
is honest.
(I had started a 64-bit caps patch, but then got stuck trying to
decide whether something needed to be done about
task_capability_lock...)
Well, I guess you wouldn't want to bog down your patch to
that, but would you take your own bit once it was available,
or are you happy just using CAP_LINUX_IMMUTABLE?
> +
> +/*
> + * These functions are in smackfs.c
> + */
> +void smk_cipso_doi(void);
> +
> +/*
> + * These functions are in smack_lsm.c
> + */
> +struct inode_smack *new_inode_smack(char *);
> +
> +/*
> + * These functions are in smack_access.c
> + */
> +int smk_access(char *, char *, int);
> +int smk_curacc(char *, u32);
> +int smack_to_cipso(const char *, struct smack_cipso *);
> +void smack_from_cipso(u32, char *, char *);
> +char *smack_from_secid(const u32);
> +char *smk_import(const char *, int);
> +struct smack_known *smk_import_entry(const char *, int);
> +u32 smack_to_secid(const char *);
> +
> +/*
> + * Stricly for CIPSO level manipulation.
> + * Set the category bit number in a smack label sized buffer.
> + */
> +static inline void smack_catset_bit(int cat, char *catsetp)
> +{
> + char *cp = (char *)catsetp;
> +
> + if (cat > SMK_LABELLEN * 8)
> + return;
> +
> + cp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
> +}
> +
> +/*
> + * Present a pointer to the smack label in an inode blob.
> + */
> +static inline char *smk_of_inode(const struct inode *isp)
> +{
> + struct inode_smack *sip = isp->i_security;
> + return sip->smk_inode;
> +}
> +
> +#endif /* _SECURITY_SMACK_H */
> diff -uprN -X linux-2.6.23-rc8-base/Documentation/dontdiff linux-2.6.23-rc8-base/security/smack/smack_lsm.c linux-2.6.23-rc8-smack/security/smack/smack_lsm.c
> --- linux-2.6.23-rc8-base/security/smack/smack_lsm.c 1969-12-31 16:00:00.000000000 -0800
> +++ linux-2.6.23-rc8-smack/security/smack/smack_lsm.c 2007-09-25 15:30:38.000000000 -0700
> @@ -0,0 +1,2685 @@
> +/*
> + * Simplified MAC Kernel (smack) security module
> + *
> + * This file contains the smack hook function implementations.
> + *
> + * Author:
> + * Casey Schaufler <[email protected]>
> + *
> + * Copyright (C) 2007 Casey Schaufler <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2,
> + * as published by the Free Software Foundation.
> + */
> +
> +#include <linux/xattr.h>
> +#include <linux/pagemap.h>
> +#include <linux/mount.h>
> +#include <linux/stat.h>
> +#include <linux/ext2_fs.h>
> +#include <linux/kd.h>
> +#include <asm/ioctls.h>
> +#include <linux/tcp.h>
> +#include <linux/udp.h>
> +#include <linux/mutex.h>
> +#include <net/netlabel.h>
> +#include <net/cipso_ipv4.h>
> +
> +#include "smack.h"
> +
> +/*
> + * I hope these are the hokeyist lines of code in the module. Casey.
> + */
> +#define DEVPTS_SUPER_MAGIC 0x1cd1
> +#define SOCKFS_MAGIC 0x534F434B
> +#define PIPEFS_MAGIC 0x50495045
> +#define TMPFS_MAGIC 0x01021994
> +
> +/*
> + * These are in smack_access.c
> + */
> +extern struct smack_known smack_known_unset;
> +extern struct smack_known smack_known_huh;
> +extern struct smack_known smack_known_hat;
> +extern struct smack_known smack_known_star;
> +extern struct smack_known smack_known_floor;
> +extern struct smack_known smack_known_invalid;
> +
> +/*
> + * These are maintained in smackfs.c
> + */
> +extern char *smack_net_ambient;
> +extern int smack_net_nltype;
> +extern int smack_cipso_direct;
> +
> +/**
> + * smk_fetch - Fetch the smack label from a file.
> + * @ip: a pointer to the inode
> + * @dp: a pointer to the dentry
> + *
> + * Returns a pointer to the master list entry for the Smack label
> + * or NULL if there was no label to fetch.
> + */
> +static char *smk_fetch(struct inode *ip, struct dentry *dp)
> +{
> + int rc;
> + char in[SMK_LABELLEN];
> +
> + if (ip->i_op->getxattr == NULL)
> + return NULL;
> +
> + rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, in, SMK_LABELLEN);
> + if (rc < 0)
> + return NULL;
> +
> + return smk_import(in, rc);
> +}
> +
> +/**
> + * new_inode_smack - allocate an inode security blob
> + * @smack: a pointer to the Smack label to use in the blob
> + *
> + * Returns the new blob or NULL if there's no memory available
> + */
> +struct inode_smack *new_inode_smack(char *smack)
> +{
> + struct inode_smack *isp;
> +
> + isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL);
> + if (isp == NULL)
> + return NULL;
> +
> + isp->smk_inode = smack;
> + isp->smk_flags = 0;
> + mutex_init(&isp->smk_lock);
> +
> + return isp;
> +}
> +
> +/*
> + * LSM hooks.
> + * We he, that is fun!
> + */
> +
> +/**
> + * smack_ptrace - Smack approval on ptrace
> + * @ptp: parent task pointer
> + * @ctp: child task pointer
> + *
> + * Returns 0 if access is OK, an error code otherwise
> + *
> + * Do the capability checks, and require read and write.
> + */
> +static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp)
> +{
> + int rc;
> +
> + rc = cap_ptrace(ptp, ctp);
> + if (rc != 0)
> + return rc;
> +
> + rc = smk_access(ptp->security, ctp->security, MAY_READWRITE);
> + if (rc != 0 && __capable(ptp, CAP_MAC_OVERRIDE))
> + return 0;
> +
> + return rc;
> +}
> +
> +/**
> + * smack_syslog - Smack approval on syslog
> + * @type: message type
> + *
> + * Require that the task has the floor label
> + *
> + * Returns 0 on success, error code otherwise.
> + */
> +static int smack_syslog(int type)
> +{
> + int rc;
> + char *sp = current->security;
> +
> + rc = cap_syslog(type);
> + if (rc != 0)
> + return rc;
> +
> + if (__capable(current, CAP_MAC_OVERRIDE))
> + return 0;
> +
> + if (sp != smack_known_floor.smk_known)
> + rc = -EACCES;
> +
> + return rc;
> +}
> +
> +/**
> + * smack_task_alloc_security - "allocate" a task blob
> + * @tsk: the task in need of a blob
> + *
> + * Smack isn't using copies of blobs. Everyone
> + * points to an immutible list. No alloc required.
> + * No data copy required.
> + *
> + * Always returns 0
> + */
> +static int smack_task_alloc_security(struct task_struct *tsk)
> +{
> + tsk->security = current->security;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_task_free_security - "free" a task blob
> + * @task: the task with the blob
> + *
> + * Smack isn't using copies of blobs. Everyone
> + * points to an immutible list. The blobs never go away.
> + * There is no leak here.
> + */
> +static void smack_task_free_security(struct task_struct *task)
> +{
> + task->security = NULL;
> +}
> +
> +/**
> + * smack_task_setpgid - Smack check on setting pgid
> + * @p: the task object
> + * @pgid: unused
> + *
> + * Return 0 if write access is permitted
> + */
> +static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
> +{
> + return smk_curacc(p->security, MAY_WRITE);
> +}
> +
> +/**
> + * smack_task_setnice - Smack check on setting nice
> + * @p: the task object
> + * @nice: unused
> + *
> + * Return 0 if write access is permitted
> + */
> +static int smack_task_setnice(struct task_struct *p, int nice)
> +{
> + return smk_curacc(p->security, MAY_WRITE);
> +}
> +
> +/**
> + * smack_task_setioprio - Smack check on setting ioprio
> + * @p: the task object
> + * @ioprio: unused
> + *
> + * Return 0 if write access is permitted
> + */
> +static int smack_task_setioprio(struct task_struct *p, int ioprio)
> +{
> + return smk_curacc(p->security, MAY_WRITE);
> +}
> +
> +/**
> + * smack_task_getioprio - Smack check on reading ioprio
> + * @p: the task object
> + *
> + * Return 0 if read access is permitted
> + */
> +static int smack_task_getioprio(struct task_struct *p)
> +{
> + return smk_curacc(p->security, MAY_READ);
> +}
> +
> +/**
> + * smack_task_setscheduler - Smack check on setting scheduler
> + * @p: the task object
> + * @policy: unused
> + * @lp: unused
> + *
> + * Return 0 if read access is permitted
> + */
> +static int smack_task_setscheduler(struct task_struct *p, int policy,
> + struct sched_param *lp)
> +{
> + return smk_curacc(p->security, MAY_WRITE);
> +}
> +
> +/**
> + * smack_task_getscheduler - Smack check on reading scheduler
> + * @p: the task object
> + *
> + * Return 0 if read access is permitted
> + */
> +static int smack_task_getscheduler(struct task_struct *p)
> +{
> + return smk_curacc(p->security, MAY_READ);
> +}
> +
> +/**
> + * smack_task_movememory - Smack check on moving memory
> + * @p: the task object
> + *
> + * Return 0 if write access is permitted
> + */
> +static int smack_task_movememory(struct task_struct *p)
> +{
> + return smk_curacc(p->security, MAY_WRITE);
> +}
> +
> +/**
> + * smack_task_kill - Samck check on signal delivery
> + * @p: the task object
> + * @info: unused
> + * @sig: unused
> + * @secid: identifies the smack to use in lieu of current's
> + *
> + * Return 0 if write access is permitted
> + *
> + * The secid behavior is an artifact of an SELinux hack
> + * in the USB code. Someday it may go away.
> + */
> +static int smack_task_kill(struct task_struct *p, struct siginfo *info,
> + int sig, u32 secid)
> +{
> + /*
> + * Sending a signal requires that the sender
> + * can write the receiver.
> + */
> + if (secid == 0)
> + return smk_curacc(p->security, MAY_WRITE);
> + /*
> + * If the secid isn't 0 we're dealing with some USB IO
> + * specific behavior. This is not clean. For one thing
> + * we can't take privilege into account.
> + */
> + return smk_access(smack_from_secid(secid), p->security, MAY_WRITE);
> +}
> +
> +/*
> + * Superblock Hooks.
> + */
> +
> +/**
> + * smack_sb_alloc_security - allocate a superblock blob
> + * @sb: the superblock getting the blob
> + *
> + * Returns 0 on success or -ENOMEM on error.
> + */
> +static int smack_sb_alloc_security(struct super_block *sb)
> +{
> + struct superblock_smack *sbsp;
> +
> + sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
> +
> + if (sbsp == NULL)
> + return -ENOMEM;
> +
> + sbsp->smk_root = smack_known_floor.smk_known;
> + sbsp->smk_default = smack_known_floor.smk_known;
> + sbsp->smk_floor = smack_known_floor.smk_known;
> + sbsp->smk_hat = smack_known_hat.smk_known;
> + sbsp->smk_initialized = 0;
> +
> + sb->s_security = sbsp;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_sb_free_security - free a superblock blob
> + * @sb: the superblock getting the blob
> + *
> + */
> +static void smack_sb_free_security(struct super_block *sb)
> +{
> + kfree(sb->s_security);
> + sb->s_security = NULL;
> +}
> +
> +/**
> + * smack_sb_copy_data - copy mount options data for processing
> + * @type: file system type
> + * @orig: where to start
> + * @smackopts
> + *
> + * Returns 0 on success or -ENOMEM on error.
> + *
> + * Copy the Smack specific mount options out of the mount
> + * options list.
> + */
> +static int smack_sb_copy_data(struct file_system_type *type, void *orig,
> + void *smackopts)
> +{
> + char *cp, *commap, *otheropts, *dp;
> +
> + /* Binary mount data: just copy */
> + if (type->fs_flags & FS_BINARY_MOUNTDATA) {
> + copy_page(smackopts, orig);
> + return 0;
> + }
> +
> + otheropts = (char *)get_zeroed_page(GFP_KERNEL);
> + if (otheropts == NULL)
> + return -ENOMEM;
> +
> + for (cp = orig, commap = orig; commap != NULL; cp = commap + 1) {
> + if (strstr(cp, SMK_FSDEFAULT) == cp)
> + dp = smackopts;
> + else if (strstr(cp, SMK_FSFLOOR) == cp)
> + dp = smackopts;
> + else if (strstr(cp, SMK_FSHAT) == cp)
> + dp = smackopts;
> + else if (strstr(cp, SMK_FSROOT) == cp)
> + dp = smackopts;
> + else
> + dp = otheropts;
> +
> + commap = strchr(cp, ',');
> + if (commap != NULL)
> + *commap = '\0';
> +
> + if (*dp != '\0')
> + strcat(dp, ",");
> + strcat(dp, cp);
> + }
> +
> + strcpy(orig, otheropts);
> + free_page((unsigned long)otheropts);
> +
> + return 0;
> +}
> +
> +/**
> + * smack_sb_kern_mount - Smack specific mount processing
> + * @sb: the file system superblock
> + * @data: the smack mount options
> + *
> + * Returns 0 on success, an error code on failure
> + */
> +static int smack_sb_kern_mount(struct super_block *sb, void *data)
> +{
> + int rc;
> + struct dentry *root = sb->s_root;
> + struct inode *inode = root->d_inode;
> + struct superblock_smack *sp = sb->s_security;
> + struct inode_smack *isp;
> + char *op;
> + char *commap;
> + char *nsp;
> +
> + if (sp == NULL) {
> + rc = smack_sb_alloc_security(sb);
> + if (rc != 0)
> + return rc;
> + }
> + if (sp->smk_initialized != 0)
> + return 0;
> + if (inode == NULL)
> + return 0;
> +
> + sp->smk_initialized = 1;
> +
> + for (op = data; op != NULL; op = commap) {
> + commap = strchr(op, ',');
> + if (commap != NULL)
> + *commap++ = '\0';
> +
> + if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
> + op += strlen(SMK_FSHAT);
> + nsp = smk_import(op, 0);
> + if (nsp != NULL)
> + sp->smk_hat = nsp;
> + } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
> + op += strlen(SMK_FSFLOOR);
> + nsp = smk_import(op, 0);
> + if (nsp != NULL)
> + sp->smk_floor = nsp;
> + } else if (strncmp(op,SMK_FSDEFAULT,strlen(SMK_FSDEFAULT))==0) {
> + op += strlen(SMK_FSDEFAULT);
> + nsp = smk_import(op, 0);
> + if (nsp != NULL)
> + sp->smk_default = nsp;
> + } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
> + op += strlen(SMK_FSROOT);
> + nsp = smk_import(op, 0);
> + if (nsp != NULL)
> + sp->smk_root = nsp;
> + }
> + }
> +
> + /*
> + * Initialize the root inode.
> + */
> + isp = inode->i_security;
> + if (isp == NULL)
> + inode->i_security = new_inode_smack(sp->smk_root);
> + else
> + isp->smk_inode = sp->smk_root;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_sb_statfs - Smack check on statfs
> + * @dentry: identifies the file system in question
> + *
> + * Returns 0 if current can read the floor of the filesystem,
> + * and error code otherwise
> + */
> +static int smack_sb_statfs(struct dentry *dentry)
> +{
> + struct superblock_smack *sbp;
> +
> + if (dentry == NULL || dentry->d_sb == NULL ||
> + dentry->d_sb->s_security == NULL)
> + return 0;
> +
> + sbp = dentry->d_sb->s_security;
> +
> + return smk_curacc(sbp->smk_floor, MAY_READ);
> +}
> +
> +/**
> + * smack_sb_mount - Smack check for mounting
> + * @dev_name: unused
> + * @nd: mount point
> + * @type: unused
> + * @flags: unused
> + * @data: unused
> + *
> + * Returns 0 if current can write the floor of the filesystem
> + * being mounted on, an error code otherwise.
> + */
> +static int smack_sb_mount(char *dev_name, struct nameidata *nd,
> + char *type, unsigned long flags, void *data)
> +{
> + struct superblock_smack *sbp;
> +
> + if (nd == NULL || nd->mnt == NULL || nd->mnt->mnt_sb == NULL ||
> + nd->mnt->mnt_sb->s_security == NULL)
> + return 0;
> +
> + sbp = nd->mnt->mnt_sb->s_security;
> +
> + return smk_curacc(sbp->smk_floor, MAY_WRITE);
> +}
> +
> +/**
> + * smack_sb_umount - Smack check for unmounting
> + * @mnt: file system to unmount
> + * @flags: unused
> + *
> + * Returns 0 if current can write the floor of the filesystem
> + * being unmounted, an error code otherwise.
> + */
> +static int smack_sb_umount(struct vfsmount *mnt, int flags)
> +{
> + struct superblock_smack *sbp;
> +
> + sbp = mnt->mnt_sb->s_security;
> +
> + return smk_curacc(sbp->smk_floor, MAY_WRITE);
> +}
> +
> +/*
> + * Inode hooks
> + */
> +
> +/**
> + * smack_inode_alloc_security - allocate an inode blob
> + * @inode - the inode in need of a blob
> + *
> + * Returns 0 if it gets a blob, -ENOMEM otherwise
> + */
> +static int smack_inode_alloc_security(struct inode *inode)
> +{
> + inode->i_security = new_inode_smack(current->security);
> + if (inode->i_security == NULL)
> + return -ENOMEM;
> + return 0;
> +}
> +
> +/**
> + * smack_inode_free_security - free an inode blob
> + * @inode - the inode with a blob
> + *
> + * Clears the blob pointer in inode
> + */
> +static void smack_inode_free_security(struct inode *inode)
> +{
> + kfree(inode->i_security);
> + inode->i_security = NULL;
> +}
> +
> +/**
> + * smack_inode_init_security - copy out the smack from an inode
> + * @inode: the inode
> + * @dir: unused
> + * @name: where to put the attribute name
> + * @value: where to put the attribute value
> + * @len: where to put the length of the attribute
> + *
> + * Returns 0 if it all works out, -ENOMEM if there's no memory
> + */
> +static int smack_inode_init_security(struct inode *inode, struct inode *dir,
> + char **name, void **value, size_t *len)
> +{
> + char *isp = smk_of_inode(inode);
> +
> + if (name) {
> + *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
> + if (*name == NULL)
> + return -ENOMEM;
> + }
> +
> + if (value) {
> + *value = kstrdup(isp, GFP_KERNEL);
> + if (*value == NULL)
> + return -ENOMEM;
> + }
> +
> + if (len)
> + *len = strlen(isp) + 1;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_inode_link - Smack check on link
> + * @old_dentry: unused
> + * @dir: the directory with the entry to change
> + * @new_dentry: unused
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
> + struct dentry *new_dentry)
> +{
> + return smk_curacc(smk_of_inode(dir), MAY_WRITE);
> +}
> +
> +/**
> + * smack_inode_symlink - Smack check on symlink
> + * @dir: the directory to add the entry to
> + * @dentry: unused
> + * @name: unused
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_symlink(struct inode *dir, struct dentry *dentry,
> + const char *name)
> +{
> + return smk_curacc(smk_of_inode(dir), MAY_WRITE);
> +}
> +
> +/**
> + * smack_inode_mknod - Smack check on mknod
> + * @dir: the directory to add the entry to
> + * @dentry: unused
> + * @mode: unused
> + * @dev: unused
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_mknod(struct inode *dir, struct dentry *dentry,
> + int mode, dev_t dev)
> +{
> + return smk_curacc(smk_of_inode(dir), MAY_WRITE);
> +}
> +
> +/**
> + * smack_inode_rename - Smack check on rename
> + * @old_inode: the old directory
> + * @old_dentry: unused
> + * @new_inode: the new directory
> + * @new_dentry: unused
> + *
> + * Read and write access is required on both the old and
> + * new directories.
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_rename(struct inode *old_inode,
> + struct dentry *old_dentry,
> + struct inode *new_inode,
> + struct dentry *new_dentry)
> +{
> + int rc;
> +
> + rc = smk_curacc(smk_of_inode(old_inode), MAY_READWRITE);
> + if (rc == 0)
> + rc = smk_curacc(smk_of_inode(new_inode), MAY_READWRITE);
> + return rc;
> +}
> +
> +/**
> + * smack_inode_readlink - Smack check on readlink
> + * @dentry: the symlink
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_readlink(struct dentry *dentry)
> +{
> + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
> +}
> +
> +/**
> + * smack_inode_follow_link - Smack check on following a symlink
> + * @dentry: the symlink
> + * @nameidata: unused
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_follow_link(struct dentry *dentry,
> + struct nameidata *nameidata)
> +{
> + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
> +}
> +
> +/**
> + * smack_inode_permission - Smack version of permission()
> + * @inode: the inode in question
> + * @mask: the access requested
> + * @nd: unused
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_permission(struct inode *inode, int mask,
> + struct nameidata *nd)
> +{
> + /*
> + * No permission to check. Existence test. Yup, it's there.
> + */
> + if (mask == 0)
> + return 0;
> +
> + return smk_curacc(smk_of_inode(inode), mask);
> +}
> +
> +/**
> + * smack_inode_setattr - Smack check for setting attributes
> + * @dentry: the object
> + * @iattr: unused
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
> +{
> + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
> +}
> +
> +/**
> + * smack_inode_getattr - Smack check for getting attributes
> + * @mnt: unused
> + * @dentry: the object
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
> +{
> + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
> +}
> +
> +/**
> + * smack_inode_setxattr - Smack check for setting xattrs
> + * @dentry: the object
> + * @name: passed to the cap call
> + * @value: passed to the cap call
> + * @size: passed to the cap call
> + * @flags: passed to the cap call
> + *
> + * Check with cap_inode_setxattr to see if the capability
> + * scheme approves, then check the Smack access
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_setxattr(struct dentry *dentry, char *name,
> + void *value, size_t size, int flags)
> +{
> + int rc;
> +
> + if (strcmp(name, XATTR_NAME_SMACK) == 0 &&
> + !__capable(current, CAP_MAC_OVERRIDE))
> + return -EPERM;
> +
> + rc = cap_inode_setxattr(dentry, name, value, size, flags);
> + if (rc == 0)
> + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
> +
> + return rc;
> +}
> +
> +/**
> + * smack_inode_post_setxattr - Apply the Smack update approved above
> + * @dentry: object
> + * @name: attribute name
> + * @value: attribute value
> + * @size: attribute size
> + * @flags: unused
> + *
> + * Set the pointer in the inode blob to the entry found
> + * in the master label list.
> + */
> +static void smack_inode_post_setxattr(struct dentry *dentry, char *name,
> + void *value, size_t size, int flags)
> +{
> + struct inode_smack *isp;
> + char *nsp;
> +
> + /*
> + * Not SMACK
> + */
> + if (strcmp(name, XATTR_NAME_SMACK))
> + return;
> +
> + if (size >= SMK_LABELLEN)
> + return;
> +
> + isp = dentry->d_inode->i_security;
> +
> + /*
> + * No locking is done here. This is a pointer
> + * assignment.
> + */
> + nsp = smk_import(value, size);
> + if (nsp != NULL)
> + isp->smk_inode = nsp;
> + else
> + isp->smk_inode = smack_known_invalid.smk_known;
> +
> + return;
> +}
> +
> +/*
> + * smack_inode_getxattr - Smack check on getxattr
> + * @dentry: the object
> + * @name: unused
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_getxattr(struct dentry *dentry, char *name)
> +{
> + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
> +}
> +
> +/*
> + * smack_inode_listxattr - Smack check on listxattr
> + * @dentry: the object
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_listxattr(struct dentry *dentry)
> +{
> + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
> +}
> +
> +/*
> + * smack_inode_removexattr - Smack check on removexattr
> + * @dentry: the object
> + * @name: name of the attribute
> + *
> + * Removing the Smack attribute requires CAP_MAC_OVERRIDE
> + *
> + * Returns 0 if access is permitted, an error code otherwise
> + */
> +static int smack_inode_removexattr(struct dentry *dentry, char *name)
> +{
> + int rc;
> +
> + if (strcmp(name, XATTR_NAME_SMACK) == 0 &&
> + !__capable(current, CAP_MAC_OVERRIDE))
> + return -EPERM;
> +
> + rc = cap_inode_removexattr(dentry, name);
> + if (rc == 0)
> + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
> +
> + return rc;
> +}
> +
> +/**
> + * smack_inode_getsecurity - get smack xattrs
> + * @inode: the object
> + * @name: attribute name
> + * @buffer: where to put the result
> + * @size: size of the buffer
> + * @err: unused
> + *
> + * Returns the size of the attribute or an error code
> + */
> +static int smack_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
> +{
> + struct socket_smack *ssp;
> + struct socket *sock;
> + struct super_block *sbp;
> + struct inode *ip = (struct inode *)inode;
> + char *bsp = buffer;
> + char *isp;
> +
> + if (size < SMK_LABELLEN || name == NULL || bsp == NULL ||
> + inode == NULL || inode->i_security == NULL)
> + return 0;
> +
> + if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
> + isp = smk_of_inode(inode);
> + strncpy(buffer, isp, SMK_LABELLEN);
> + return strlen(isp) + 1;
> + }
> +
> + /*
> + * The rest of the Smack xattrs are only on sockets.
> + */
> + sbp = ip->i_sb;
> + if (sbp->s_magic != SOCKFS_MAGIC)
> + return -EOPNOTSUPP;
> +
> + sock = SOCKET_I(ip);
> + if (sock == NULL)
> + return -EOPNOTSUPP;
> +
> + ssp = sock->sk->sk_security;
> +
> + /*
> + * Should the packet attribute be unavailable return the error.
> + * This can happen if packets come in too fast.
> + */
> + if (strcmp(name, XATTR_SMACK_PACKET) == 0) {
> + if (ssp->smk_packet[0] == '\0')
> + return -ENODATA;
> + isp = ssp->smk_packet;
> + }
> + else if (strcmp(name, XATTR_SMACK_IPIN) == 0)
> + isp = ssp->smk_in;
> + else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
> + isp = ssp->smk_out;
> + else
> + return -EOPNOTSUPP;
> +
> + strncpy(buffer, isp, SMK_LABELLEN);
> + return strlen(isp) + 1;
> +}
> +
> +/**
> + * smack_inode_setsecurity - set smack xattrs
> + * @inode: the object
> + * @name: attribute name
> + * @value: attribute value
> + * @size: size of the attribute
> + * @flags: unused
> + *
> + * Sets the named attribute in the appropriate blob
> + *
> + * Returns 0 on success, or an error code
> + */
> +static int smack_inode_setsecurity(struct inode *inode, const char *name,
> + const void *value, size_t size, int flags)
> +{
> + char *sp;
> + struct inode_smack *nsp = (struct inode_smack *)inode->i_security;
> + struct socket_smack *ssp;
> + struct socket *sock;
> +
> + if (value == NULL || size > SMK_LABELLEN)
> + return -EACCES;
> +
> + sp = smk_import(value, size);
> + if (sp == NULL)
> + return -EINVAL;
> +
> + if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
> + mutex_lock(&nsp->smk_lock);
> + nsp->smk_inode = sp;
> + mutex_unlock(&nsp->smk_lock);
> + return 0;
> + }
> + /*
> + * The rest of the Smack xattrs are only on sockets.
> + */
> + if (inode->i_sb->s_magic != SOCKFS_MAGIC)
> + return -EOPNOTSUPP;
> +
> + sock = SOCKET_I(inode);
> + if (sock == NULL)
> + return -EOPNOTSUPP;
> +
> + ssp = sock->sk->sk_security;
> +
> + if (strcmp(name, XATTR_SMACK_PACKET) == 0) {
> + memset(ssp->smk_packet, '\0', SMK_LABELLEN);
> + strncpy(ssp->smk_packet, sp, SMK_LABELLEN);
> + }
> + else if (strcmp(name, XATTR_SMACK_IPIN) == 0)
> + ssp->smk_in = sp;
> + else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
> + ssp->smk_out = sp;
> + else
> + return -EOPNOTSUPP;
> + return 0;
> +}
> +
> +/**
> + * smack_inode_listsecurity - list the Smack attributes
> + * @inode: the object
> + * @buffer: where they go
> + * @buffer_size: size of buffer
> + *
> + * Returns 0 on success, -EINVAL otherwise
> + */
> +static int smack_inode_listsecurity(struct inode *inode, char *buffer,
> + size_t buffer_size)
> +{
> + int len = strlen(XATTR_NAME_SMACK);
> +
> + if (buffer != NULL && len <= buffer_size) {
> + memcpy(buffer, XATTR_NAME_SMACK, len);
> + return len;
> + }
> + return -EINVAL;
> +}
> +
> +/**
> + * smack_d_instantiate - Make sure the blob is correct on an inode
> + * @opt_dentry: unused
> + * @inode: the object
> + *
> + * Set the inode's security blob if it hasn't been done already.
> + */
> +static void smack_d_instantiate (struct dentry *opt_dentry, struct inode *inode)
> +{
> + struct super_block *sbp;
> + struct superblock_smack *sbsp;
> + struct inode_smack *isp;
> + char *csp = current->security;
> + char *fetched;
> + char *final;
> + struct dentry *dp;
> +
> + if (inode == NULL)
> + return;
> +
> + if (inode->i_security == NULL)
> + inode->i_security =
> + new_inode_smack(smack_known_unset.smk_known);
> +
> + isp = inode->i_security;
> +
> + mutex_lock(&isp->smk_lock);
> + /*
> + * If the inode is already instantiated
> + * take the quick way out
> + */
> + if (isp->smk_flags & SMK_INODE_INSTANT)
> + goto unlockandout;
> +
> + sbp = inode->i_sb;
> + sbsp = sbp->s_security;
> + /*
> + * We're going to use the superblock default label
> + * if there's no label on the file.
> + */
> + final = sbsp->smk_default;
> +
> + /*
> + * This is pretty hackish.
> + * Casey says that we shouldn't have to do
> + * file system specific code, but it does help
> + * with keeping it simple.
> + */
> + switch (sbp->s_magic) {
> + case SMACK_MAGIC:
> + /*
> + * Casey says that it's a little embarassing
> + * that the smack file system doesn't do
> + * extended attributes.
> + */
> + final = smack_known_star.smk_known;
> + break;
> + case PIPEFS_MAGIC:
> + /*
> + * Casey says pipes are easy (?)
> + */
> + final = smack_known_star.smk_known;
> + break;
> + case DEVPTS_SUPER_MAGIC:
> + /*
> + * devpts seems content with the label of the task.
> + * Programs that change smack have to treat the
> + * pty with respect.
> + */
> + final = csp;
> + break;
> + case SOCKFS_MAGIC:
> + /*
> + * Casey says sockets get the smack of the task.
> + */
> + final = csp;
> + break;
> + case PROC_SUPER_MAGIC:
> + /*
> + * Casey says procfs appears not to care.
> + * The superblock default suffices.
> + */
> + break;
> + case TMPFS_MAGIC:
> + /*
> + * Device labels should come from the filesystem,
> + * but watch out, because they're volitile,
> + * getting recreated on every reboot.
> + */
> + final = smack_known_star.smk_known;
> + /*
> + * No break.
> + *
> + * If a smack value has been set we want to use it,
> + * but since tmpfs isn't giving us the opportunity
> + * to set mount options simulate setting the
> + * superblock default.
> + */
> + default:
> + /*
> + * This isn't an understood special case.
> + * Get the value from the xattr.
> + *
> + * No xattr support means, alas, no SMACK label.
> + * Use the aforeapplied default.
> + * It would be curious if the label of the task
> + * does not match that assigned.
> + */
> + if (inode->i_op->getxattr == NULL)
> + break;
> + /*
> + * Get the dentry for xattr.
> + */
> + if (opt_dentry == NULL) {
> + dp = d_find_alias(inode);
> + if (dp == NULL)
> + break;
> + } else {
> + dp = dget(opt_dentry);
> + if (dp == NULL)
> + break;
> + }
> +
> + fetched = smk_fetch(inode, dp);
> + if (fetched != NULL)
> + final = fetched;
> +
> + dput(dp);
> + break;
> + }
> +
> + if (final == NULL)
> + isp->smk_inode = csp;
> + else
> + isp->smk_inode = final;
> +
> + isp->smk_flags |= SMK_INODE_INSTANT;
> +
> +unlockandout:
> + mutex_unlock(&isp->smk_lock);
> + return;
> +}
> +
> +/*
> + * File Hooks
> + */
> +
> +/**
> + * smack_file_alloc_security - assign a file security blob
> + * @file: the object
> + *
> + * The security blob for a file is a pointer to the master
> + * label list, so no allocation is done.
> + *
> + * Returns 0
> + */
> +static int smack_file_alloc_security(struct file *file)
> +{
> + file->f_security = current->security;
> + return 0;
> +}
> +
> +/**
> + * smack_file_free_security - clear a file security blob
> + * @file: the object
> + *
> + * The security blob for a file is a pointer to the master
> + * label list, so no memory is freed.
> + */
> +static void smack_file_free_security(struct file *file)
> +{
> + file->f_security = NULL;
> +}
> +
> +/**
> + * smack_file_permission - Smack check on file operations
> + * @file: unused
> + * @mask: unused
> + *
> + * Returns 0
> + *
> + * Should access checks be done on each read or write?
> + * UNICOS and SELinux say yes.
> + * Trusted Solaris, Trusted Irix, and just about everyone else says no.
> + *
> + * I'll say no for now. Smack does not do the frequent
> + * label changing that SELinux does.
> + */
> +static int smack_file_permission(struct file *file, int mask)
> +{
> + return 0;
> +}
> +
> +/**
> + * smack_file_ioctl - Smack check on ioctls
> + * @file: the object
> + * @cmd: what to do
> + * @arg: unused
> + *
> + * Relies heavily on the correct use of the ioctl command conventions.
> + *
> + * Returns 0 if allowed, error code otherwise
> + */
> +static int smack_file_ioctl(struct file *file, unsigned int cmd,
> + unsigned long arg)
> +{
> + int rc = 0;
> +
> + if (_IOC_DIR(cmd) & _IOC_WRITE)
> + rc = smk_curacc(file->f_security, MAY_WRITE);
> +
> + if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
> + rc = smk_curacc(file->f_security, MAY_READ);
> +
> + return rc;
> +}
> +
> +/**
> + * smack_file_lock - Smack check on file locking
> + * @file: the object
> + * @cmd unused
> + *
> + * Returns 0 if current has write access, error code otherwise
> + */
> +static int smack_file_lock(struct file *file, unsigned int cmd)
> +{
> + return smk_curacc(file->f_security, MAY_WRITE);
> +}
> +
> +/**
> + * smack_file_fcntl - Smack check on fcntl
> + * @file: the object
> + * @cmd: what action to check
> + * @arg: unused
> + *
> + * Returns 0 if current has access, error code otherwise
> + */
> +static int smack_file_fcntl(struct file *file, unsigned int cmd,
> + unsigned long arg)
> +{
> + int rc;
> +
> + switch (cmd) {
> + case F_DUPFD:
> + case F_GETFD:
> + case F_GETFL:
> + case F_GETLK:
> + case F_GETOWN:
> + case F_GETSIG:
> + rc = smk_curacc(file->f_security, MAY_READ);
> + break;
> + case F_SETFD:
> + case F_SETFL:
> + case F_SETLK:
> + case F_SETLKW:
> + case F_SETOWN:
> + case F_SETSIG:
> + rc = smk_curacc(file->f_security, MAY_WRITE);
> + break;
> + default:
> + rc = smk_curacc(file->f_security, MAY_READWRITE);
> + }
> +
> + return rc;
> +}
> +
> +/**
> + * smack_file_send_sigiotask - Smack on sigio
> + * @tsk: The target task
> + * @fown: the object the signal come from
> + * @signum: unused
> + *
> + * Allow a privileged task to get signals even if it shouldn't
> + *
> + * Returns 0 if a subject with the object's smack could
> + * write to the task, an error code otherwise.
> + */
> +static int smack_file_send_sigiotask(struct task_struct *tsk,
> + struct fown_struct *fown, int signum)
> +{
> + struct file *file;
> + int rc;
> +
> + /*
> + * struct fown_struct is never outside the context of a struct file
> + */
> + file = (struct file *)((long)fown - offsetof(struct file,f_owner));
> + rc = smk_access(file->f_security, tsk->security, MAY_WRITE);
> + if (rc != 0 && __capable(tsk, CAP_MAC_OVERRIDE))
> + return 0;
> + return rc;
> +}
> +
> +/**
> + * smack_file_receive - Smack file receive check
> + * @file: the object
> + *
> + * Returns 0 if current has access, error code otherwise
> + */
> +static int smack_file_receive(struct file *file)
> +{
> + int may = 0;
> +
> + /*
> + * This code relies on bitmasks.
> + */
> + if (file->f_mode & FMODE_READ)
> + may = MAY_READ;
> + if (file->f_mode & FMODE_WRITE)
> + may |= MAY_WRITE;
> +
> + return smk_curacc(file->f_security, may);
> +}
> +
> +/*
> + * Socket hooks.
> + */
> +
> +/**
> + * smack_sk_alloc_security - Allocate a socket blob
> + * @sk: the socket
> + * @family: unused
> + * @priority: memory allocation priority
> + *
> + * Assign Smack pointers to current except for smk_packet which
> + * is not a pointer but the real thing.
> + *
> + * Returns 0 on success, -ENOMEM is there's no memory
> + */
> +static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
> +{
> + char *csp = current->security;
> + struct socket_smack *ssp;
> +
> + ssp = kzalloc(sizeof(struct socket_smack), priority);
> + if (ssp == NULL)
> + return -ENOMEM;
> +
> + ssp->smk_in = csp;
> + ssp->smk_out = csp;
> + memset(ssp->smk_packet, '\0', SMK_LABELLEN);
> + strcpy(ssp->smk_packet, smack_known_invalid.smk_known);
> + ssp->smk_depth = 0;
> +
> + sk->sk_security = ssp;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_sk_free_security - Free a socket blob
> + * @sk: the socket
> + *
> + * Clears the blob pointer
> + */
> +static void smack_sk_free_security(struct sock *sk)
> +{
> + kfree(sk->sk_security);
> + sk->sk_security = NULL;
> +}
> +
> +/**
> + * smack_set_catset - convert a capset to netlabel mls categories
> + * @catset: the Smack categories
> + * @sap: where to put the netlabel categories
> + *
> + * Allocates and fills mls_cat
> + */
> +static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap)
> +{
> + unsigned char *cp;
> + unsigned char m;
> + int cat;
> + int rc;
> +
> + if (catset == 0)
> + return;
> +
> + sap->flags |= NETLBL_SECATTR_MLS_CAT;
> + sap->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
> + sap->mls_cat->startbit = 0;
> +
> + for (cat = 1, cp = catset; *cp != 0; cp++)
> + for (m = 0x80; m != 0; m >>= 1, cat++) {
> + if ((m & *cp) == 0)
> + continue;
> + rc = netlbl_secattr_catmap_setbit(sap->mls_cat, cat,
> + GFP_ATOMIC);
> + }
> +}
> +
> +/**
> + * smack_to_secattr - fill a secattr from a smack value
> + * @smack: the smack value
> + * @nlsp: where the result goes
> + *
> + * Casey says that CIPSO is good enough for now.
> + * It can be used to effect.
> + * It can also be abused to effect when necessary.
> + * Appologies to the TSIG group in general and GW in particular.
> + */
> +static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
> +{
> + struct smack_cipso cipso;
> + int rc;
> +
> + switch (smack_net_nltype) {
> + case NETLBL_NLTYPE_CIPSOV4:
> + nlsp->domain = NULL;
> + nlsp->flags = NETLBL_SECATTR_DOMAIN;
> + nlsp->flags |= NETLBL_SECATTR_MLS_LVL;
> +
> + rc = smack_to_cipso(smack, &cipso);
> + if (rc == 0) {
> + nlsp->mls_lvl = cipso.smk_level;
> + smack_set_catset(cipso.smk_catset, nlsp);
> + } else {
> + nlsp->mls_lvl = smack_cipso_direct;
> + smack_set_catset(smack, nlsp);
> + }
> + break;
> + default:
> + break;
> + }
> +}
> +
> +/**
> + * smack_netlabel - Set the secattr on a socket
> + * @sk: the socket
> + *
> + * Convert the outbound smack value (smk_out) to a
> + * secattr and attach it to the socket.
> + *
> + * Returns 0 on success or an error code
> + */
> +static int smack_netlabel(struct sock *sk)
> +{
> + static int initialized;
> + struct socket_smack *ssp = sk->sk_security;
> + struct netlbl_lsm_secattr secattr;
> + int rc;
> +
> + if (!initialized) {
> + smk_cipso_doi();
> + initialized = 1;
> + }
> +
> + netlbl_secattr_init(&secattr);
> + smack_to_secattr(ssp->smk_out, &secattr);
> + if (secattr.flags != NETLBL_SECATTR_NONE)
> + rc = netlbl_sock_setattr(sk, &secattr);
> + else
> + rc = -EINVAL;
> +
> + netlbl_secattr_destroy(&secattr);
> + return rc;
> +}
> +
> +/**
> + * smack_socket_post_create - finish socket setup
> + * @sock: the socket
> + * @family: protocol family
> + * @type: unused
> + * @protocol: unused
> + * @kern: indicates kern vs task socket
> + *
> + * Sets the security blob on the socket's inode.
> + * Sets the secattr value for outgoing packets.
> + *
> + * Returns 0 on success, and error code otherwise
> + */
> +static int smack_socket_post_create(struct socket *sock, int family,
> + int type, int protocol, int kern)
> +{
> + struct inode_smack *isp;
> +
> + isp = SOCK_INODE(sock)->i_security;
> +
> + if (isp == NULL) {
> + if (kern)
> + isp = new_inode_smack(smack_known_floor.smk_known);
> + else
> + isp = new_inode_smack(current->security);
> + SOCK_INODE(sock)->i_security = isp;
> + }
> +
> + if (family != PF_INET)
> + return 0;
> +
> + /*
> + * Set the outbound netlbl.
> + */
> + return smack_netlabel(sock->sk);
> +}
> +
> +/**
> + * smack_inode_create - Smack check on inode creation
> + * @dir: containing directory object
> + * @dentry: unused
> + * @mode: unused
> + *
> + * Returns 0 if current can write the containing directory,
> + * error code otherwise
> + */
> +static int smack_inode_create(struct inode *dir, struct dentry *dentry,
> + int mode)
> +{
> + return smk_curacc(smk_of_inode(dir), MAY_WRITE);
> +}
> +
> +/**
> + * smack_inode_unlink - Smack check on inode deletion
> + * @dir: containing directory object
> + * @dentry: file to unlink
> + *
> + * Returns 0 if current can write the containing directory
> + * and the object, error code otherwise
> + */
> +static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
> +{
> + struct inode *ip = dentry->d_inode;
> + int rc;
> +
> + /*
> + * You need write access to the thing you're unlinking
> + */
> + rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
> + if (rc == 0)
> + /*
> + * You also need write access to the containing directory
> + */
> + rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
> +
> + return rc;
> +}
> +
> +/**
> + * smack_inode_mkdir - Smack check on directory creation
> + * @dir: containing directory object
> + * @dentry: unused
> + * @mode: unused
> + *
> + * Returns 0 if current can write the containing directory,
> + * error code otherwise
> + */
> +static int smack_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
> +{
> + return smk_curacc(smk_of_inode(dir), MAY_WRITE);
> +}
> +
> +/**
> + * smack_inode_rmdir - Smack check on directory deletion
> + * @dir: containing directory object
> + * @dentry: directory to unlink
> + *
> + * Returns 0 if current can write the containing directory
> + * and the directory, error code otherwise
> + */
> +static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
> +{
> + struct inode *ip = dentry->d_inode;
> + int rc;
> +
> + /*
> + * You need write access to the thing you're removing
> + */
> + rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
> + if (rc == 0)
> + /*
> + * You also need write access to the containing directory
> + */
> + rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
> +
> + return rc;
> +}
> +
> +/**
> + * smack_file_set_fowner - set the file security blob value
> + * @file: object in question
> + *
> + * Returns 0
> + * Further research may be required on this one.
> + */
> +static int smack_file_set_fowner(struct file *file)
> +{
> + file->f_security = current->security;
> + return 0;
> +}
> +
> +/**
> + * smack_task_getpgid - Smack access check for getpgid
> + * @p: the object task
> + *
> + * Returns 0 if current can read the object task, error code otherwise
> + */
> +static int smack_task_getpgid(struct task_struct *p)
> +{
> + return smk_curacc(p->security, MAY_READ);
> +}
> +
> +/**
> + * smack_task_getsid - Smack access check for getsid
> + * @p: the object task
> + *
> + * Returns 0 if current can read the object task, error code otherwise
> + */
> +static int smack_task_getsid(struct task_struct *p)
> +{
> + return smk_curacc(p->security, MAY_READ);
> +}
> +
> +/**
> + * smack_task_getsecid - get the secid of the task
> + * @p: the object task
> + * @secid: where to put the result
> + *
> + * Sets the secid to contain a u32 version of the smack label.
> + */
> +static void smack_task_getsecid(struct task_struct *p, u32 *secid)
> +{
> + *secid = smack_to_secid(p->security);
> +}
> +
> +/**
> + * smack_flags_to_may - convert S_ to MAY_ values
> + * @flags: the S_ value
> + *
> + * Returns the equivalent MAY_ value
> + */
> +static int smack_flags_to_may(int flags)
> +{
> + int may = 0;
> +
> + if (flags & S_IRUGO)
> + may |= MAY_READ;
> + if (flags & S_IWUGO)
> + may |= MAY_WRITE;
> + if (flags & S_IXUGO)
> + may |= MAY_EXEC;
> +
> + return may;
> +}
> +
> +/**
> + * smack_msg_msg_alloc_security - Set the security blob for msg_msg
> + * @msg: the object
> + *
> + * Returns 0
> + */
> +static int smack_msg_msg_alloc_security(struct msg_msg *msg)
> +{
> + msg->security = current->security;
> + return 0;
> +}
> +
> +/**
> + * smack_msg_msg_free_security - Clear the security blob for msg_msg
> + * @msg: the object
> + *
> + * Clears the blob pointer
> + */
> +static void smack_msg_msg_free_security(struct msg_msg *msg)
> +{
> + msg->security = NULL;
> +}
> +
> +/**
> + * smack_of_shm - the smack pointer for the shm
> + * @shp: the object
> + *
> + * Returns a pointer to the smack value
> + */
> +static char *smack_of_shm(struct shmid_kernel *shp)
> +{
> + if (shp == NULL)
> + return NULL;
> +
> + return (char *)shp->shm_perm.security;
> +}
> +
> +/**
> + * smack_shm_alloc_security - Set the security blob for shm
> + * @shp: the object
> + *
> + * Returns 0
> + */
> +static int smack_shm_alloc_security(struct shmid_kernel *shp)
> +{
> + struct kern_ipc_perm *isp = &shp->shm_perm;
> +
> + isp->security = current->security;
> + return 0;
> +}
> +
> +/**
> + * smack_shm_free_security - Clear the security blob for shm
> + * @shp: the object
> + *
> + * Clears the blob pointer
> + */
> +static void smack_shm_free_security(struct shmid_kernel *shp)
> +{
> + struct kern_ipc_perm *isp = &shp->shm_perm;
> +
> + isp->security = NULL;
> +}
> +
> +/**
> + * smack_shm_associate - Smack access check for shm
> + * @shp: the object
> + * @shmflg: access requested
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
> +{
> + char *ssp = smack_of_shm(shp);
> + int may;
> +
> + if (ssp == NULL)
> + return 0;
> +
> + may = smack_flags_to_may(shmflg);
> + return smk_curacc(ssp, may);
> +}
> +
> +/**
> + * smack_shm_shmctl - Smack access check for shm
> + * @shp: the object
> + * @cmd: what it wants to do
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
> +{
> + char *ssp = smack_of_shm(shp);
> + int may;
> +
> + if (ssp == NULL)
> + return 0;
> +
> + switch(cmd) {
> + case IPC_STAT:
> + case SHM_STAT:
> + may = MAY_READ;
> + break;
> + case IPC_SET:
> + case SHM_LOCK:
> + case SHM_UNLOCK:
> + case IPC_RMID:
> + may = MAY_READWRITE;
> + break;
> + case IPC_INFO:
> + case SHM_INFO:
> + /*
> + * System level information.
> + */
> + return 0;
> + default:
> + return -EINVAL;
> + }
> +
> + return smk_curacc(ssp, may);
> +}
> +
> +/**
> + * smack_shm_shmat - Smack access for shmat
> + * @shp: the object
> + * @shmaddr: unused
> + * @shmflg: access requested
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
> + int shmflg)
> +{
> + char *ssp = smack_of_shm(shp);
> + int may;
> +
> + if (ssp == NULL)
> + return 0;
> +
> + may = smack_flags_to_may(shmflg);
> + return smk_curacc(ssp, may);
> +}
> +
> +/**
> + * smack_of_sem - the smack pointer for the sem
> + * @sma: the object
> + *
> + * Returns a pointer to the smack value
> + */
> +static char *smack_of_sem(struct sem_array *sma)
> +{
> + if (sma == NULL)
> + return NULL;
> +
> + return (char *)sma->sem_perm.security;
> +}
> +
> +/**
> + * smack_sem_alloc_security - Set the security blob for sem
> + * @sma: the object
> + *
> + * Returns 0
> + */
> +static int smack_sem_alloc_security(struct sem_array *sma)
> +{
> + struct kern_ipc_perm *isp = &sma->sem_perm;
> +
> + isp->security = current->security;
> + return 0;
> +}
> +
> +/**
> + * smack_sem_free_security - Clear the security blob for sem
> + * @sma: the object
> + *
> + * Clears the blob pointer
> + */
> +static void smack_sem_free_security(struct sem_array *sma)
> +{
> + struct kern_ipc_perm *isp = &sma->sem_perm;
> +
> + isp->security = NULL;
> +}
> +
> +/**
> + * smack_sem_associate - Smack access check for sem
> + * @sma: the object
> + * @semflg: access requested
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_sem_associate(struct sem_array *sma, int semflg)
> +{
> + char *ssp = smack_of_sem(sma);
> + int may;
> +
> + if (ssp == NULL)
> + return 0;
> +
> + may = smack_flags_to_may(semflg);
> + return smk_curacc(ssp, may);
> +}
> +
> +/**
> + * smack_sem_shmctl - Smack access check for sem
> + * @sma: the object
> + * @cmd: what it wants to do
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_sem_semctl(struct sem_array *sma, int cmd)
> +{
> + char *ssp = smack_of_sem(sma);
> + int may;
> +
> + if (ssp == NULL)
> + return 0;
> +
> + switch(cmd) {
> + case GETPID:
> + case GETNCNT:
> + case GETZCNT:
> + case GETVAL:
> + case GETALL:
> + case IPC_STAT:
> + case SEM_STAT:
> + may = MAY_READ;
> + break;
> + case SETVAL:
> + case SETALL:
> + case IPC_RMID:
> + case IPC_SET:
> + may = MAY_READWRITE;
> + break;
> + case IPC_INFO:
> + case SEM_INFO:
> + /*
> + * System level information
> + */
> + return 0;
> + default:
> + return -EINVAL;
> + }
> +
> + return smk_curacc(ssp, may);
> +}
> +
> +/**
> + * smack_sem_semop - Smack checks of semaphore operations
> + * @sma: the object
> + * @sops: unused
> + * @nsops: unused
> + * @alter: unused
> + *
> + * Treated as read and write in all cases.
> + *
> + * Returns 0 if access is allowed, error code otherwise
> + */
> +static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, unsigned nsops, int alter)
> +{
> + char *ssp = smack_of_sem(sma);
> +
> + if (ssp == NULL)
> + return 0;
> +
> + return smk_curacc(ssp, MAY_READWRITE);
> +}
> +
> +/**
> + * smack_msg_alloc_security - Set the security blob for msg
> + * @msq: the object
> + *
> + * Returns 0
> + */
> +static int smack_msg_queue_alloc_security(struct msg_queue *msq)
> +{
> + struct kern_ipc_perm *kisp = &msq->q_perm;
> +
> + kisp->security = current->security;
> + return 0;
> +}
> +
> +/**
> + * smack_msg_free_security - Clear the security blob for msg
> + * @msq: the object
> + *
> + * Clears the blob pointer
> + */
> +static void smack_msg_queue_free_security(struct msg_queue *msq)
> +{
> + struct kern_ipc_perm *kisp = &msq->q_perm;
> +
> + kisp->security = NULL;
> +}
> +
> +/**
> + * smack_of_msq - the smack pointer for the msq
> + * @msq: the object
> + *
> + * Returns a pointer to the smack value
> + */
> +static char *smack_of_msq(struct msg_queue *msq)
> +{
> + if (msq == NULL)
> + return NULL;
> +
> + return (char *)msq->q_perm.security;
> +}
> +
> +/**
> + * smack_msg_queue_associate - Smack access check for msg_queue
> + * @msq: the object
> + * @msqflg: access requested
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
> +{
> + char *msp = smack_of_msq(msq);
> + int may;
> +
> + if (msp == NULL)
> + return 0;
> +
> + may = smack_flags_to_may(msqflg);
> + return smk_curacc(msp, may);
> +}
> +
> +/**
> + * smack_msg_queue_msgctl - Smack access check for msg_queue
> + * @msq: the object
> + * @cmd: what it wants to do
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
> +{
> + char *msp = smack_of_msq(msq);
> + int may;
> +
> + if (msp == NULL)
> + return 0;
> +
> + switch(cmd) {
> + case IPC_STAT:
> + case MSG_STAT:
> + may = MAY_READ;
> + break;
> + case IPC_SET:
> + case IPC_RMID:
> + may = MAY_READWRITE;
> + break;
> + case IPC_INFO:
> + case MSG_INFO:
> + /*
> + * System level information
> + */
> + return 0;
> + default:
> + return -EINVAL;
> + }
> +
> + return smk_curacc(msp, may);
> +}
> +
> +/**
> + * smack_msg_queue_msgsnd - Smack access check for msg_queue
> + * @msq: the object
> + * @msg: unused
> + * @msqflg: access requested
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
> + int msqflg)
> +{
> + char *msp = smack_of_msq(msq);
> + int rc;
> +
> + if (msp == NULL)
> + return 0;
> +
> + rc = smack_flags_to_may(msqflg);
> + return smk_curacc(msp, rc);
> +}
> +
> +/**
> + * smack_msg_queue_msgsnd - Smack access check for msg_queue
> + * @msq: the object
> + * @msg: unused
> + * @target: unused
> + * @type: unused
> + * @mode: unused
> + *
> + * Returns 0 if current has read and write access, error code otherwise
> + */
> +static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
> + struct task_struct *target, long type, int mode)
> +{
> + char *msp = smack_of_msq(msq);
> +
> + if (msp == NULL)
> + return 0;
> +
> + return smk_curacc(msp, MAY_READWRITE);
> +}
> +
> +/**
> + * smack_ipc_permission - Smack access for ipc_permission()
> + * @ipp: the object permissions
> + * @flag: access requested
> + *
> + * Returns 0 if current has read and write access, error code otherwise
> + */
> +static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
> +{
> + char *isp = ipp->security;
> + int may;
> +
> + may = smack_flags_to_may(flag);
> + return smk_curacc(isp, may);
> +}
> +
> +/**
> + * smack_task_to_inode - copy task smack into the inode blob
> + * @p: task to copy from
> + * inode: inode to copy to
> + *
> + * Sets the smack pointer in the inode security blob
> + */
> +static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
> +{
> + struct inode_smack *isp = inode->i_security;
> + isp->smk_inode = p->security;
> +}
> +
> +/**
> + * smack_task_wait - Smack access check for waiting
> + * @p: task to wait for
> + *
> + * Returns 0 if current can wait for p, error code otherwise
> + */
> +static int smack_task_wait(struct task_struct *p)
> +{
> + int rc;
> +
> + rc = smk_access(current->security, p->security, MAY_WRITE);
> + if (rc == 0)
> + return 0;
> +
> + /*
> + * Allow the operation to succeed if either task
> + * has privilege to perform operations that might
> + * account for the smack labels having gotten to
> + * be different in the first place.
> + *
> + * This breaks the strict subjet/object access
> + * control ideal, taking the object's privilege
> + * state into account in the decision as well as
> + * the smack value.
> + */
> + if (__capable(current, CAP_MAC_OVERRIDE) ||
> + __capable(p, CAP_MAC_OVERRIDE))
> + return 0;
> +
> + return rc;
> +}
> +
> +/**
> + * smack_getprocattr - Smack process attribute access
> + * @p: the object task
> + * @name: the name of the attribute in /proc/.../attr
> + * @value: where to put the result
> + *
> + * Places a copy of the task Smack into value
> + *
> + * Returns the length of the smack label or an error code
> + */
> +static int smack_getprocattr(struct task_struct *p, char *name, char **value)
> +{
> + char *cp;
> + int slen;
> +
> + if (strcmp(name, "current") != 0)
> + return -EINVAL;
> +
> + cp = kstrdup(current->security, GFP_KERNEL);
> + if (cp == NULL)
> + return -ENOMEM;
> +
> + slen = strlen(cp);
> + *value = cp;
> + return slen;
> +}
> +
> +/**
> + * smack_setprocattr - Smack process attribute setting
> + * @p: the object task
> + * @name: the name of the attribute in /proc/.../attr
> + * @value: the value to set
> + * @size: the size of the value
> + *
> + * Sets the Smack value of the task. Only setting self
> + * is permitted and only with privilege
> + *
> + * Returns the length of the smack label or an error code
> + */
> +static int smack_setprocattr(struct task_struct *p, char *name,
> + void *value, size_t size)
> +{
> + char *newsmack;
> +
> + if (!__capable(p, CAP_MAC_OVERRIDE))
> + return -EPERM;
> +
> + /*
> + * Changing another process' Smack value is too dangerous
> + * and supports no sane use case.
> + */
> + if (p != current)
> + return -EPERM;
> +
> + if (value == NULL || size == 0 || size >= SMK_LABELLEN)
> + return -EINVAL;
> +
> + if (strcmp(name, "current") != 0)
> + return -EINVAL;
> +
> + newsmack = smk_import(value, size);
> + if (newsmack == NULL)
> + return -EINVAL;
> +
> + p->security = newsmack;
> + return size;
> +}
> +
> +/**
> + * smack_unix_stream_connect - Smack access on UDS
> + * @sock: one socket
> + * @other: the other socket
> + * @newsk: unused
> + *
> + * Return 0 if a subject with the smack of sock could access
> + * an object with the smack of other, otherwise an error code
> + */
> +static int smack_unix_stream_connect(struct socket *sock,
> + struct socket *other, struct sock *newsk)
> +{
> + struct inode *sp = SOCK_INODE(sock);
> + struct inode *op = SOCK_INODE(other);
> +
> + return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE);
> +}
> +
> +/**
> + * smack_unix_may_send - Smack access on UDS
> + * @sock: one socket
> + * @other: the other socket
> + *
> + * Return 0 if a subject with the smack of sock could access
> + * an object with the smack of other, otherwise an error code
> + */
> +static int smack_unix_may_send(struct socket *sock, struct socket *other)
> +{
> + struct inode *sp = SOCK_INODE(sock);
> + struct inode *op = SOCK_INODE(other);
> +
> + return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
> +}
> +
> +/**
> + * smack_from_secattr - Convert a netlabel mls_lvl/mls_cat pair to smack
> + * @sap: netlabel secattr
> + * @sip: where to put the result
> + *
> + * Copies a smack label into sip
> + */
> +static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
> +{
> + char smack[SMK_LABELLEN];
> + int pcat;
> +
> + if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
> + /*
> + * If there are flags but no level netlabel isn't
> + * behaving the way we expect it to.
> + *
> + * Without guidance regarding the smack value
> + * for the packet fall back on the network
> + * ambient value.
> + */
> + strncpy(sip, smack_net_ambient, SMK_MAXLEN);
> + return;
> + }
> + /*
> + * Get the categories, if any
> + */
> + memset(smack, '\0', SMK_LABELLEN);
> + if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
> + for (pcat = -1;;) {
> + pcat = netlbl_secattr_catmap_walk(sap->mls_cat, pcat+1);
> + if (pcat < 0)
> + break;
> + smack_catset_bit(pcat, smack);
> + }
> + /*
> + * If it is CIPSO using smack direct mapping
> + * we are already done. WeeHee.
> + */
> + if (sap->mls_lvl == smack_cipso_direct) {
> + memcpy(sip, smack, SMK_MAXLEN);
> + return;
> + }
> + /*
> + * Look it up in the supplied table if it is not a direct mapping.
> + */
> + smack_from_cipso(sap->mls_lvl, smack, sip);
> + return;
> +}
> +
> +static int smack_socket_recvmsg(struct socket *sock, struct msghdr *msg,
> + int size, int flags)
> +{
> + struct socket_smack *ssp = sock->sk->sk_security;
> +
> + /*
> + * If the depth is 0 no packets are queued.
> + * If the depth is > 1 the "current" has been overwritten.
> + */
> +
> + if (ssp->smk_depth != 1)
> + ssp->smk_packet[0] = '\0';
> + if (ssp->smk_depth != 0)
> + ssp->smk_depth--;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_socket_sock_rcv_skb - Smack packet delivery access check
> + * @sk: socket
> + * @skb: packet
> + *
> + * Returns 0 if the packet should be delivered, an error code otherwise
> + */
> +static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
> +{
> + struct netlbl_lsm_secattr secattr;
> + struct socket_smack *ssp = sk->sk_security;
> + char smack[SMK_LABELLEN];
> + int rc;
> +
> + if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
> + return 0;
> +
> + /*
> + * Translate what netlabel gave us.
> + */
> + memset(smack, '\0', SMK_LABELLEN);
> + netlbl_secattr_init(&secattr);
> + rc = netlbl_skbuff_getattr(skb, &secattr);
> + if (rc == 0)
> + smack_from_secattr(&secattr, smack);
> + else
> + strncpy(smack, smack_net_ambient, SMK_MAXLEN);
> + netlbl_secattr_destroy(&secattr);
> + /*
> + * Receiving a packet requires that the other end
> + * be able to write here. Read access is not required.
> + * This is the simplist possible security model
> + * for networking.
> + */
> + rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
> + if (rc != 0)
> + return rc;
> +
> + /*
> + * If recv was called and there were no outstanding packets
> + * this is the "current" Smack value to make available.
> + */
> + if (ssp->smk_depth == 0)
> + strcpy(ssp->smk_packet, smack);
> + ssp->smk_depth++;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_sock_graft - graft access state between two sockets
> + * @sk: fresh sock
> + * @parent: donor socket
> + *
> + * Sets the netlabel socket state on sk from parent
> + */
> +static void smack_sock_graft(struct sock *sk, struct socket *parent)
> +{
> + struct socket_smack *ssp;
> + struct netlbl_lsm_secattr secattr;
> + char smack[SMK_LABELLEN];
> + int rc;
> +
> + if (sk == NULL || parent == NULL || parent->sk == NULL)
> + return;
> +
> + if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
> + return;
> +
> + ssp = parent->sk->sk_security;
> +
> + memset(smack, '\0', SMK_LABELLEN);
> + netlbl_secattr_init(&secattr);
> + rc = netlbl_sock_getattr(sk, &secattr);
> + if (rc == 0)
> + smack_from_secattr(&secattr, smack);
> + else
> + strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
> + netlbl_secattr_destroy(&secattr);
> +
> + netlbl_secattr_init(&secattr);
> +
> + smack_to_secattr(smack, &secattr);
> + if (secattr.flags != NETLBL_SECATTR_NONE)
> + rc = netlbl_sock_setattr(parent->sk, &secattr);
> + netlbl_secattr_destroy(&secattr);
> +}
> +
> +/**
> + * smack_inet_conn_request - Smack access check on connect
> + * @sk: socket involved
> + * @skb: packet
> + * @req: unused
> + *
> + * Returns 0 if a task with the packet label could write to
> + * the socket, otherwise an error code
> + */
> +static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
> + struct request_sock *req)
> +{
> + struct netlbl_lsm_secattr skb_secattr;
> + struct socket_smack *ssp = sk->sk_security;
> + char smack[SMK_LABELLEN];
> + int rc;
> +
> + if (skb == NULL)
> + return -EACCES;
> +
> + memset(smack, '\0', SMK_LABELLEN);
> + netlbl_secattr_init(&skb_secattr);
> + rc = netlbl_skbuff_getattr(skb, &skb_secattr);
> + if (rc == 0)
> + smack_from_secattr(&skb_secattr, smack);
> + else
> + strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
> + netlbl_secattr_destroy(&skb_secattr);
> + /*
> + * Receiving a packet requires that the other end
> + * be able to write here. Read access is not required.
> + */
> + return smk_access(smack, ssp->smk_in, MAY_WRITE);
> +}
> +
> +/*
> + * Key management security hooks
> + *
> + * Casey has not tested key support very heavily.
> + * The permission check is most likely too restrictive.
> + * If you care about keys please have a look.
> + */
> +#ifdef CONFIG_KEYS
> +
> +/**
> + * smack_key_alloc - Set the key security blob
> + * @key: object
> + * @tsk: the task associated with the key
> + * @flags: unused
> + *
> + * No allocation required
> + *
> + * Returns 0
> + */
> +static int smack_key_alloc(struct key *key, struct task_struct *tsk,
> + unsigned long flags)
> +{
> + key->security = tsk->security;
> + return 0;
> +}
> +
> +/**
> + * smack_key_free - Clear the key security blob
> + * @key: the object
> + *
> + * Clear the blob pointer
> + */
> +static void smack_key_free(struct key *key)
> +{
> + key->security = NULL;
> +}
> +
> +/*
> + * smack_key_permission - Smack access on a key
> + * @key_ref: gets to the object
> + * @context: task involved
> + * @perm: unused
> + *
> + * Return 0 if the task has read and write to the object,
> + * an error code otherwise
> + */
> +static int smack_key_permission(key_ref_t key_ref,
> + struct task_struct *context, key_perm_t perm)
> +{
> + struct key *keyp;
> +
> + keyp = key_ref_to_ptr(key_ref);
> + if (keyp == NULL)
> + return -EINVAL;
> + /*
> + * If the key hasn't been initialized give it access so that
> + * it may do so.
> + */
> + if (keyp->security == NULL)
> + return 0;
> + /*
> + * This should not occur
> + */
> + if (context->security == NULL)
> + return -EACCES;
> +
> + return smk_access(context->security, keyp->security, MAY_READWRITE);
> +}
> +#endif /* CONFIG_KEYS */
> +
> +static struct security_operations smack_ops = {
> + .ptrace = smack_ptrace,
> + .capget = cap_capget,
> + .capset_check = cap_capset_check,
> + .capset_set = cap_capset_set,
> + .capable = cap_capable,
> + /* .acct No hook required */
> + /* .sysctl No hook required */
> + /* .quotactl No hook required */
> + /* .quota_on No hook required */
> + .syslog = smack_syslog,
> + .settime = cap_settime,
> + .vm_enough_memory = cap_vm_enough_memory,
> +
> + /* .bprm_alloc_security No hook required */
> + /* .bprm_free_security No hook required */
> + .bprm_apply_creds = cap_bprm_apply_creds,
> + /* .bprm_post_apply_creds No hook required */
> + .bprm_set_security = cap_bprm_set_security,
> + /* .bprm_check_security No hook required */
> + .bprm_secureexec = cap_bprm_secureexec,
> +
> + .sb_alloc_security = smack_sb_alloc_security,
> + .sb_free_security = smack_sb_free_security,
> + .sb_copy_data = smack_sb_copy_data,
> + .sb_kern_mount = smack_sb_kern_mount,
> + .sb_statfs = smack_sb_statfs,
> + .sb_mount = smack_sb_mount,
> + /* .sb_check_sb No hook required */
> + .sb_umount = smack_sb_umount,
> + /* .sb_umount_close No hook required */
> + /* .sb_umount_busy No hook required */
> + /* .sb_post_remount No hook required */
> + /* .sb_post_mountroot No hook required */
> + /* .sb_post_addmount No hook required */
> + /* .sb_pivotroot No hook required */
> + /* .sb_post_pivotroot No hook required */
> +
> + .inode_alloc_security = smack_inode_alloc_security,
> + .inode_free_security = smack_inode_free_security,
> + .inode_init_security = smack_inode_init_security,
> + .inode_create = smack_inode_create,
> + .inode_link = smack_inode_link,
> + .inode_unlink = smack_inode_unlink,
> + .inode_symlink = smack_inode_symlink,
> + .inode_mkdir = smack_inode_mkdir,
> + .inode_rmdir = smack_inode_rmdir,
> + .inode_mknod = smack_inode_mknod,
> + .inode_rename = smack_inode_rename,
> + .inode_readlink = smack_inode_readlink,
> + .inode_follow_link = smack_inode_follow_link,
> + .inode_permission = smack_inode_permission,
> + .inode_setattr = smack_inode_setattr,
> + .inode_getattr = smack_inode_getattr,
> + /* .inode_delete No hook required */
> + .inode_setxattr = smack_inode_setxattr,
> + .inode_post_setxattr = smack_inode_post_setxattr,
> + .inode_getxattr = smack_inode_getxattr,
> + .inode_listxattr = smack_inode_listxattr,
> + .inode_removexattr = smack_inode_removexattr,
> + /* .inode_xattr_getsuffix No hook required */
> + .inode_getsecurity = smack_inode_getsecurity,
> + .inode_setsecurity = smack_inode_setsecurity,
> + .inode_listsecurity = smack_inode_listsecurity,
> +
> + .file_permission = smack_file_permission,
> + .file_alloc_security = smack_file_alloc_security,
> + .file_free_security = smack_file_free_security,
> + .file_ioctl = smack_file_ioctl,
> + /* .file_mmap No hook required */
> + /* .file_mprotect No hook required */
> + .file_lock = smack_file_lock,
> + .file_fcntl = smack_file_fcntl,
> + .file_set_fowner = smack_file_set_fowner,
> + .file_send_sigiotask = smack_file_send_sigiotask,
> + .file_receive = smack_file_receive,
> +
> + /* .task_create No hook required */
> + .task_alloc_security = smack_task_alloc_security,
> + .task_free_security = smack_task_free_security,
> + /* .task_setuid No hook required */
> + .task_post_setuid = cap_task_post_setuid,
> + /* .task_setgid No hook required */
> + .task_setpgid = smack_task_setpgid,
> + .task_getpgid = smack_task_getpgid,
> + .task_getsid = smack_task_getsid,
> + .task_getsecid = smack_task_getsecid,
> + /* .task_setgroups No hook required */
> + .task_setnice = smack_task_setnice,
> + .task_setioprio = smack_task_setioprio,
> + .task_getioprio = smack_task_getioprio,
> + /* .task_setrlimit No hook required */
> + .task_setscheduler = smack_task_setscheduler,
> + .task_getscheduler = smack_task_getscheduler,
> + .task_movememory = smack_task_movememory,
> + .task_kill = smack_task_kill,
> + .task_wait = smack_task_wait,
> + /* .task_prctl No hook required */
> + .task_reparent_to_init = cap_task_reparent_to_init,
> + .task_to_inode = smack_task_to_inode,
> +
> + .ipc_permission = smack_ipc_permission,
> +
> + .msg_msg_alloc_security = smack_msg_msg_alloc_security,
> + .msg_msg_free_security = smack_msg_msg_free_security,
> +
> + .msg_queue_alloc_security = smack_msg_queue_alloc_security,
> + .msg_queue_free_security = smack_msg_queue_free_security,
> + .msg_queue_associate = smack_msg_queue_associate,
> + .msg_queue_msgctl = smack_msg_queue_msgctl,
> + .msg_queue_msgsnd = smack_msg_queue_msgsnd,
> + .msg_queue_msgrcv = smack_msg_queue_msgrcv,
> +
> + .shm_alloc_security = smack_shm_alloc_security,
> + .shm_free_security = smack_shm_free_security,
> + .shm_associate = smack_shm_associate,
> + .shm_shmctl = smack_shm_shmctl,
> + .shm_shmat = smack_shm_shmat,
> +
> + .sem_alloc_security = smack_sem_alloc_security,
> + .sem_free_security = smack_sem_free_security,
> + .sem_associate = smack_sem_associate,
> + .sem_semctl = smack_sem_semctl,
> + .sem_semop = smack_sem_semop,
> +
> + .netlink_send = cap_netlink_send,
> + .netlink_recv = cap_netlink_recv,
> +
> + /* .register_security No hook required */
> + /* .unregister_security No hook required */
> +
> + .d_instantiate = smack_d_instantiate,
> +
> + .getprocattr = smack_getprocattr,
> + .setprocattr = smack_setprocattr,
> + /* .secid_to_secctx No hook required */
> + /* .release_secctx No hook required */
> +
> + .unix_stream_connect = smack_unix_stream_connect,
> + .unix_may_send = smack_unix_may_send,
> +
> + /* .socket_create No hook required */
> + .socket_post_create = smack_socket_post_create,
> + /* .socket_bind No hook required */
> + /* .socket_connect No hook required */
> + /* .socket_listen No hook required */
> + /* .socket_accept No hook required */
> + /* .socket_post_accept No hook required */
> + /* .socket_sendmsg No hook required */
> + .socket_recvmsg = smack_socket_recvmsg,
> + /* .socket_getsockname No hook required */
> + /* .socket_getpeername No hook required */
> + /* .socket_getsockopt No hook required */
> + /* .socket_setsockopt No hook required */
> + /* .socket_shutdown No hook required */
> + .socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
> + /* .socket_getpeersec_stream No hook required */
> + /* .socket_getpeersec_dgram No hook required */
> + .sk_alloc_security = smack_sk_alloc_security,
> + .sk_free_security = smack_sk_free_security,
> + /* .sk_clone_security No hook required */
> + /* .sk_getsecid No hook required */
> + .sock_graft = smack_sock_graft,
> + .inet_conn_request = smack_inet_conn_request,
> + /* .inet_csk_clone No hook required */
> + /* .inet_conn_established No hook required */
> +
> + /* .req_classify_flow No hook required */
> + /* .xfrm_policy_alloc_security no xfrm for smack */
> + /* .xfrm_policy_clone_security no xfrm for smack */
> + /* .xfrm_policy_free_security no xfrm for smack */
> + /* .xfrm_policy_delete_security no xfrm for smack */
> + /* .xfrm_state_alloc_security no xfrm for smack */
> + /* .xfrm_state_free_security no xfrm for smack */
> + /* .xfrm_state_delete_security no xfrm for smack */
> + /* .xfrm_policy_lookup no xfrm for smack */
> + /* .xfrm_state_pol_flow_match no xfrm for smack */
> + /* .xfrm_decode_session no xfrm for smack */
> +
> + /* key management security hooks */
> +#ifdef CONFIG_KEYS
> + .key_alloc = smack_key_alloc,
> + .key_free = smack_key_free,
> + .key_permission = smack_key_permission,
> +#endif /* CONFIG_KEYS */
> +
> +};
> +
> +DEFINE_MUTEX(smack_list_lock);
> +DEFINE_MUTEX(smack_known_lock);
> +
> +/**
> + * smack_init - initialize the smack system
> + *
> + * Returns 0
> + */
> +static __init int smack_init(void)
> +{
> + printk(KERN_INFO "Smack: Initializing.\n");
> +
> + /*
> + * Set the security state for the initial task.
> + */
> + current->security = &smack_known_floor.smk_known;
> +
> + /*
> + * Initialize locks
> + */
> + spin_lock_init(&smack_known_unset.smk_cipsolock);
> + spin_lock_init(&smack_known_huh.smk_cipsolock);
> + spin_lock_init(&smack_known_hat.smk_cipsolock);
> + spin_lock_init(&smack_known_star.smk_cipsolock);
> + spin_lock_init(&smack_known_floor.smk_cipsolock);
> + spin_lock_init(&smack_known_invalid.smk_cipsolock);
> +
> + mutex_init(&smack_known_lock);
> + mutex_init(&smack_list_lock);
> +
> + /*
> + * Register with LSM
> + */
> + if (register_security(&smack_ops))
> + panic("smack: Unable to register with kernel.\n");
> +
> + return 0;
> +}
> +
> +/*
> + * Smack requires early initialization in order to label
> + * all processes and objects when they are created.
> + */
> +security_initcall(smack_init);
> +
--- "Serge E. Hallyn" <[email protected]> wrote:
> ...
> > +A process can see the smack label it is running with by
> > +reading /proc/self/attr/current. A privileged process can
> > +set the process smack by writing there.
>
> Ok, so to control smack label transitions, basically you would
> run with CAP_MAC_OVERRIDE (see my note later) so that you're
> allowed to change your smack label by writing to
> /proc/self/attr/current, then you drop CAP_MAC_OVERRIDE, then you're
> no longer able to change your label? I.e. no inherent label changing
> rules through smack itself?
That is correct. Smack task labels do not change spontaniously.
> Just making sure I have that right. If I do, then I think at least
> defining the word 'privileged' above, given that this is mac,
> would help.
Good idea.
> ...
> > --- linux-2.6.23-rc8-base/security/smack/Kconfig 1969-12-31
> 16:00:00.000000000 -0800
> > +++ linux-2.6.23-rc8-smack/security/smack/Kconfig 2007-09-25
> 15:30:38.000000000 -0700
> > @@ -0,0 +1,10 @@
> > +config SECURITY_SMACK
> > + bool "Simplified Mandatory Access Control Kernel Support"
> > + depends on NETLABEL && SECURITY_NETWORK
> > + default n
> > + help
> > + This selects the Simplified Mandatory Access Control Kernel.
> > + Smack is useful for sensitivity, integrity, and a variety
> > + of other mandatory security schemes.
> > + If you are unsure how to answer this question, answer N.
>
> Might point out that no other modules must be compiled in along with
> smack, and that smack will do posix capabilities.
Also a good idea.
> ...
> > +/**
> > + * smk_write_load - write() for /smack/load
> > + * @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_load(struct file *file, const char __user *buf,
> > + size_t count, loff_t *ppos)
> > +{
> > + struct smack_rule rule;
> > + ssize_t rc = count;
> > + char *data = NULL;
> > + char subjectstr[SMK_LABELLEN];
> > + char objectstr[SMK_LABELLEN];
> > + char modestr[8];
> > + char *cp;
> > +
> > +
> > + if (!capable(CAP_MAC_OVERRIDE))
> > + return -EPERM;
> > + /*
> > + * No partial writes.
> > + */
> > + if (*ppos != 0)
> > + return -EINVAL;
> > +
> > + /*
> > + * 80 characters per line ought to be enough.
> > + */
> > + if (count > SMACK_LIST_MAX * 80)
> > + return -ENOMEM;
> > +
> > + data = kzalloc(count + 1, GFP_KERNEL);
> > + if (data == NULL)
> > + return -ENOMEM;
> > +
> > + if (copy_from_user(data, buf, count) != 0) {
> > + kfree(data);
> > + return -EFAULT;
> > + }
> > +
> > + *(data + count) = '\0';
> > +
> > + for (cp = data - 1; cp != NULL; cp = strchr(cp + 1, '\n')) {
> > + if (*++cp == '\0')
> > + break;
> > + if (sscanf(cp, "%23s %23s %7s\n", subjectstr, objectstr,
> > + modestr) != 3) {
> > + printk("%s:%d bad scan\n", __func__, __LINE__);
> > + break;
> > + }
> > + rule.smk_subject = smk_import(subjectstr, 0);
> > + if (rule.smk_subject == NULL)
> > + break;
> > + rule.smk_object = smk_import(objectstr, 0);
> > + if (rule.smk_object == NULL)
> > + break;
> > + rule.smk_access = 0;
> > + if (strpbrk(modestr, "rR") != NULL)
> > + rule.smk_access |= MAY_READ;
> > + if (strpbrk(modestr, "wW") != NULL)
> > + rule.smk_access |= MAY_WRITE;
> > + if (strpbrk(modestr, "xX") != NULL)
> > + rule.smk_access |= MAY_EXEC;
> > + if (strpbrk(modestr, "aA") != NULL)
> > + rule.smk_access |= MAY_APPEND;
> > + smk_set_access(&rule);
> > + printk("%s:%d rule %s %s 0x%x\n", __func__, __LINE__,
> > + (char *)rule.smk_subject, (char *)rule.smk_object,
> > + rule.smk_access);
>
> Are you sure this isn't something you'd like to really audit?
>
> (Sorry if that's been asked before)
There is work required to audit, SELinux, and LSM that will be
required before Smack or any other module can really use audit
properly. Smack using audit would be nice, but there are already
interesting cases that don't require it. I have fixing up audit
on my todo list, and have made some proposals. It will require
a group effort between audit, SELinux, Smack, and LSM.
> ...
> > +#define CAP_MAC_OVERRIDE CAP_LINUX_IMMUTABLE
>
> We're basically inevitably going to be switching to 64-bit caps
> "any day now". Should we just go ahead and do it here? Now
> maybe we should use a less contraversial name than 'mac override'
> like 'CAP_MAC_POLICY_ADMIN' :), but I guess CAP_MAC_OVERRIDE
> is honest.
>
> (I had started a 64-bit caps patch, but then got stuck trying to
> decide whether something needed to be done about
> task_capability_lock...)
>
> Well, I guess you wouldn't want to bog down your patch to
> that, but would you take your own bit once it was available,
> or are you happy just using CAP_LINUX_IMMUTABLE?
I would be delighted to have a bit of my very own. The granularity
advocates might suggest I use more than one.
Thank you for the comments.
Casey Schaufler
[email protected]
On Sun, 30 Sep 2007, Andrew Morton wrote:
> So with the information which I presently have available to me, I'm
> thinking that this should go into 2.6.24.
I think the decision to merge Smack is something that needs to be
considered in the wider context of overall security architecture.
Smack itself looks fine. It seems like clean code with interesting ideas,
and appears to be based upon sound principles.
Merging Smack, however, would lock the kernel into the LSM API.
Presently, as SELinux is the only in-tree user, LSM can still be removed.
LSM's weak semantics and pervasive deep hooking of the kernel means that
we'll have to continue dealing with several unpleasant issues, such as the
abuse of the API by out of tree vendors, with a proliferation of
binary/proprietary modules which typically maladapt the API for arbitrary
purposes and/or use dangerous techniques. We will continue to waste
resources maintaining this capability for them.
On a broader scale, we'll miss the potential of Linux having a coherent,
semantically strong security architecture. I have written about this in
some detail before: http://lwn.net/Articles/240019/
Briefly, SELinux is a security architecture. It provides an extremely
high degree of flexibility, in terms of both the types of security models
implemented, and security policy for those models. It allows controlled
composition of different security models, with a common policy language
framework, allowing the entire system to be analyzed. The same ideas and
even code can be reused beyond the kernel as post-DAC security is extended
into databases, the desktop, distributed applications etc. It is a
framework which provides a structured, coherent view of the security of
the OS (and ultimately, the entire distributed environment).
If LSM remains, security will never be a first class citizen of the
kernel. Application developers will see multiple security schemes, and
either burn themselves trying to support them, or more likely, ignore
them.
Core kernel developers will continue to not have enough information to
understand what the LSM hooks in their code are supposed to be doing,
leading to long term maintenance issues and potential security problems.
LSM will remain a magnet for bad ideas. There's a reason we don't have
pluggable network stacks, and we are lucky to have had a unified
networking framework maintained by people who know to say no to things
like STREAMS and TOE. I would question whether this quality of
maintainership would exist if the networking core was simply a bunch of
deep hooks into which people dumped arbitrary custom stacks.
LSM will prevent us from making systemic improvements to security, as
there will be no common security architecture. Things like Netfilter
would not have been viable with a kernel which simply provided a bunch of
hooks for networking stacks and an assortment of implementations.
Much of this we have learned from the experience of LSM, and I think it
has been valuable for that, but I think we need to consider now whether we
are going to continue down this track in a permanent manner.
- James
--
James Morris
<[email protected]>
On Mon, 1 Oct 2007, James Morris wrote:
>
> Merging Smack, however, would lock the kernel into the LSM API.
> Presently, as SELinux is the only in-tree user, LSM can still be removed.
Hell f*cking NO!
You security people are insane. I'm tired of this "only my version is
correct" crap. The whole and only point of LSM was to get away from that.
And anybody who claims that there is "consensus" on SELinux is just in
denial.
People are arguing against other peoples security on totally bogus points.
First it was AppArmor, now this.
I guess I have to merge AppArmor and SMACK just to get this *disease* off
the table. You're acting like a string theorist, claiming that t here is
no other viable theory out there. Stop it. It's been going on for too damn
long.
Linus
--- James Morris <[email protected]> wrote:
> On Sun, 30 Sep 2007, Andrew Morton wrote:
>
> > So with the information which I presently have available to me, I'm
> > thinking that this should go into 2.6.24.
>
> I think the decision to merge Smack is something that needs to be
> considered in the wider context of overall security architecture.
Please recall the reason that we have LSM. It is so that Linus
does not have to listen to the arguments over security architecture.
> Smack itself looks fine. It seems like clean code with interesting ideas,
> and appears to be based upon sound principles.
Thank you.
> Merging Smack, however, would lock the kernel into the LSM API.
> Presently, as SELinux is the only in-tree user, LSM can still be removed.
Ah, the nut of the issue. What follows then is the argument that
SELinux should be the official security architecture of Linux.
I disagree (like you hadn't figured that out) with this position.
> LSM's weak semantics and pervasive deep hooking of the kernel means that
> we'll have to continue dealing with several unpleasant issues, such as the
> abuse of the API by out of tree vendors,
Pulling LSM might slow a small set of abusers, but it wouldn't solve the
problem, what with well documented VFS and driver layers available.
> with a proliferation of
> binary/proprietary modules which typically maladapt the API for arbitrary
> purposes and/or use dangerous techniques. We will continue to waste
> resources maintaining this capability for them.
HeHe. I recall the response to some Tivoli developers when they
made a request not to long ago. I seriously doubt that they feel
the community is putting out much for them.
> On a broader scale, we'll miss the potential of Linux having a coherent,
> semantically strong security architecture. I have written about this in
> some detail before: http://lwn.net/Articles/240019/
Here our opinions diverge strongly. My position is that the
security architecture of SELinux is excessive in it's sophistication.
> Briefly, SELinux is a security architecture. It provides an extremely
> high degree of flexibility, in terms of both the types of security models
> implemented, and security policy for those models. It allows controlled
> composition of different security models, with a common policy language
> framework, allowing the entire system to be analyzed. The same ideas and
> even code can be reused beyond the kernel as post-DAC security is extended
> into databases, the desktop, distributed applications etc. It is a
> framework which provides a structured, coherent view of the security of
> the OS (and ultimately, the entire distributed environment).
None of which is new or unique to SELinux.
> If LSM remains, security will never be a first class citizen of the
> kernel. Application developers will see multiple security schemes, and
> either burn themselves trying to support them, or more likely, ignore
> them.
What is the #1 SELinux FAQ?
"How do I turn it off?"
I'd suggest that application and system developers are perfectly
capable of making rational decisions regarding the security model
that is appropriate to their environments.
> Core kernel developers will continue to not have enough information to
> understand what the LSM hooks in their code are supposed to be doing,
> leading to long term maintenance issues and potential security problems.
Is that hypothetical, or do you have examples?
> LSM will remain a magnet for bad ideas.
Thanks a lot.
> There's a reason we don't have
> pluggable network stacks, and we are lucky to have had a unified
> networking framework maintained by people who know to say no to things
> like STREAMS and TOE. I would question whether this quality of
> maintainership would exist if the networking core was simply a bunch of
> deep hooks into which people dumped arbitrary custom stacks.
The counter argument is of course VFS and the driver interface.
I think that the file systems work pretty well. Except for the
flakey ones.
> LSM will prevent us from making systemic improvements to security, as
> there will be no common security architecture. Things like Netfilter
> would not have been viable with a kernel which simply provided a bunch of
> hooks for networking stacks and an assortment of implementations.
Unless you consider Smack a systemic improvement to security like I do.
> Much of this we have learned from the experience of LSM, and I think it
> has been valuable for that, but I think we need to consider now whether we
> are going to continue down this track in a permanent manner.
Why so defensive? SELinux is a fine implementation of Type Enforcement
and if you like that sort of thing I'm all for you using it. Accept that
it may not be for everyone. I certainly don't expect Smack on everyone's
machine.
Casey Schaufler
[email protected]
On Mon, 2007-10-01 at 08:07 -0700, Linus Torvalds wrote:
>
> On Mon, 1 Oct 2007, James Morris wrote:
> >
> > Merging Smack, however, would lock the kernel into the LSM API.
> > Presently, as SELinux is the only in-tree user, LSM can still be removed.
>
> Hell f*cking NO!
>
> You security people are insane. I'm tired of this "only my version is
> correct" crap. The whole and only point of LSM was to get away from that.
>
> And anybody who claims that there is "consensus" on SELinux is just in
> denial.
>
> People are arguing against other peoples security on totally bogus points.
> First it was AppArmor, now this.
>
> I guess I have to merge AppArmor and SMACK just to get this *disease* off
> the table. You're acting like a string theorist, claiming that t here is
> no other viable theory out there. Stop it. It's been going on for too damn
> long.
You argued against pluggable schedulers, right? Why is security
different?
Do you really want to encourage people to roll their own security module
rather than working toward a common security architecture and a single
balanced solution (which doesn't necessarily mean SELinux, mind you, but
certainly could draw from parts of it)? As with pluggable schedulers,
the LSM approach prevents cross pollination and forces users to make
poor choices.
Some have suggested that security modules are no different than
filesystem implementations, but filesystem implementations at least are
constrained by their need to present a common API and must conform with
and leverage the VFS infrastructure. Different security modules present
very different interfaces and behaviors from one another and LSM doesn't
provide the same kind of common functionality and well-defined semantics
as the VFS. The result of merging many wildly different security
modules will be chaos for application developers and users, likely
leading them to ignore everything but the least common denominator.
It almost makes more sense to merge no security modules at all than to
have LSM and many different security modules.
If Smack is mergeable despite likely being nothing more than a strict
subset of SELinux (MAC, label-based, should be easily emulated on top of
SELinux or via fairly simple extension to it to make such emulation
simpler or more optimal), then what isn't mergeable as a separate
security module?
--
Stephen Smalley
National Security Agency
On Mon, 1 Oct 2007, Stephen Smalley wrote:
>
> You argued against pluggable schedulers, right? Why is security
> different?
Schedulers can be objectively tested. There's this thing called
"performance", that can generally be quantified on a load basis.
Yes, you can have crazy ideas in both schedulers and security. Yes, you
can simplify both for a particular load. Yes, you can make mistakes in
both. But the *discussion* on security seems to never get down to real
numbers.
So the difference between them is simple: one is "hard science". The other
one is "people wanking around with their opinions".
If you guys had been able to argue on hard data and be in agreement, LSM
wouldn't have been needed in the first place.
BUT THAT WAS NOT THE CASE.
And perhaps more importantly:
BUT THAT IS *STILL* NOT THE CASE!
Sorry for the shouting, but I'm serious about this.
> Do you really want to encourage people to roll their own security module
> rather than working toward a common security architecture and a single
> balanced solution (which doesn't necessarily mean SELinux, mind you, but
> certainly could draw from parts of it)? As with pluggable schedulers,
> the LSM approach prevents cross pollination and forces users to make
> poor choices.
Another difference is that when it comes to schedulers, I feel like I
actually can make an informed decision. Which means that I'm perfectly
happy to just make that decision, and take the flak that I get for it. And
I do (both decide, and get flak). That's my job.
In contrast, when it comes to security, I see people making IDIOTIC
arguments, and I absolutely *know* that those arguments are pure and utter
crap, and at the same time, I see that those people are supposed to be
"experts".
For example, you security guys still debate "inodes" vs "pathnames", as if
that was an either-or issue.
Quite frankly, I'm not a security person, but I can tell a bad argument
from a good one. And an argument that says "inodes _or_ pathnames" is so
full of shit that it's not even funny. And a person who says that it has
to be one or the other is incompetent.
Yet that is *still* the level of disagreement I see.
So LSM stays in. No ifs, buts, maybes or anything else.
When I see the security people making sane arguments and agreeing on
something, that will change. Quite frankly, I expect hell to freeze over
before that happens, and pigs will be nesting in trees. But hey, I can
hope.
> If Smack is mergeable despite likely being nothing more than a strict
> subset of SELinux (MAC, label-based, should be easily emulated on top of
> SELinux or via fairly simple extension to it to make such emulation
> simpler or more optimal), then what isn't mergeable as a separate
> security module?
I'm simply not interested in this discussion. If you cannot understand the
*meta*discussion above (which has nothing to do with SMACK or SELinux per
se), I cannot help you.
The biggest reason for me to merge SMACK (and AppArmor) would not be those
particular security modules in themselves, but to inject a sense of
reality in people. Right now, I see discussions about removign LSM because
"SELinux is everything". THAT IS A PROBLEM.
Linus
--- Stephen Smalley <[email protected]> wrote:
> On Mon, 2007-10-01 at 08:07 -0700, Linus Torvalds wrote:
> >
> > On Mon, 1 Oct 2007, James Morris wrote:
> > >
> > > Merging Smack, however, would lock the kernel into the LSM API.
> > > Presently, as SELinux is the only in-tree user, LSM can still be removed.
> >
> > Hell f*cking NO!
> >
> > You security people are insane.
I don't know if the field attracts the insane, or if being
in the field drives one there, but I'm not going to deny that
we have our share of high grade loonies.
> > I'm tired of this "only my version is
> > correct" crap. The whole and only point of LSM was to get away from that.
> >
> > And anybody who claims that there is "consensus" on SELinux is just in
> > denial.
> >
> > People are arguing against other peoples security on totally bogus points.
> > First it was AppArmor, now this.
> >
> > I guess I have to merge AppArmor and SMACK just to get this *disease* off
> > the table. You're acting like a string theorist, claiming that t here is
> > no other viable theory out there. Stop it. It's been going on for too damn
> > long.
>
I'm pulling the whole arguement about when is pluggable good
and when is it bad, as everybody seems inclined to use it to
support thier own position.
> If Smack is mergeable despite likely being nothing more than a strict
> subset of SELinux
Hogwash.
> (MAC, label-based,
Yes.
> should be easily emulated on top of SELinux
Sure, and I can emulate a rubber doorstop with Michealangeo's David,
that doesn't make it a good idea. And I keep seeing "should", not
"is". Emphatic assertion is not evidence.
> or via fairly simple extension to it to make such emulation
> simpler or more optimal),
Making SELinux bigger would not make it suit the typical Smack use
better. Smack is simplified, that's a major point.
> then what isn't mergeable as a separate security module?
Personally, I care about what I produced can do, and the uses to
which it will be put. I am not convinced that SELinux can do many
of the things that Smack can, and I know that a system that can
only be used effectivly by Security Professionals is not for everyone.
Smack has a different focus than SELinux. I see no need for hostility.
If SELinux wants to incorporate Smack features, that's OK with me,
but it won't make SELinux simpler. Heaven knows I have leaned heavily
on the implementation example of SELinux.
Casey Schaufler
[email protected]
On Mon, Oct 01, 2007 at 09:04:44AM -0700, Linus Torvalds wrote:
> For example, you security guys still debate "inodes" vs "pathnames", as if
> that was an either-or issue.
>
> Quite frankly, I'm not a security person, but I can tell a bad argument
> from a good one. And an argument that says "inodes _or_ pathnames" is so
> full of shit that it's not even funny. And a person who says that it has
> to be one or the other is incompetent.
Not so much incompetent as religious fundamentalist. Which is worse.
OG.
On Mon, Oct 01, 2007 at 11:40:39AM -0400, Stephen Smalley wrote:
> You argued against pluggable schedulers, right? Why is security
> different?
>
> Do you really want to encourage people to roll their own security module
> rather than working toward a common security architecture and a single
> balanced solution (which doesn't necessarily mean SELinux, mind you, but
> certainly could draw from parts of it)? As with pluggable schedulers,
> the LSM approach prevents cross pollination and forces users to make
> poor choices.
Something should be pluggable, and some things not. We have multiple
filesystems in the tree; but we only have one scheduler and one TCP/IP
stack.
I'm going to argue that security is more like filesystems than
scheduling. The real problem with security is that there are no "hard
numbers", as Linus puts it. Instead, there are different sets of
requirements in terms of what is a valid threat model --- which will
very depending on the environment and how the servers are deployed,
and what the capabilities are of the adversary trying to penetrate
said system --- and how end users are willing to compromise between
security and convenience. This is much like filesystems, where one of
the reasons why people chose different filesystems is because they
have differing requirements and operational environments, and some
filesystems are better suited for certain requirements and
environments than others.
In some environments, say if you are creating a system that will
handle classified data for the U.S. government, there are formal
requirements that your employer, the NSA, sign off on the solution.
This allows the NSA to force the application programmers and end users
to make the tradeoff tilt very much against convenience in favor of
security. And given the threat models and capabilities of the
adversaries involved, that's probably appropriate.
But that's not necessarily appropriate for all users. SELINUX is so
horrible to use, that after wasting a large amount of time enabling it
and then watching all of my applications die a horrible death since
they didn't have the appropriate hand-crafted security policy, caused
me to swear off of it. For me, given my threat model and how much my
time is worth, life is too short for SELinux.
And I can tell you that certain ISV's, when faced with users
complaining that their commericial application which costs ten times
as much as their Linux distribution doesn't work when SELinux is
enabled, simply tells their customers to disable SELinux.
I've often thought that one of the reasons why SELinux folks argue so
strenuously against AppArmor is because since configuring it to
support new applications is so much easier than SELinux, that on an
even playing ground, in many commercial environments that dwarf the
NSA-mandated security pain of the federal sector, there is fear that
AppArmor would be much more popular with customers than SELinux. Yes,
AppArmor protects against fewer threats; but if the choice is to go
without SELinux because it's too painful to configure SELinux policy,
surely some protection is better than none.
> Some have suggested that security modules are no different than
> filesystem implementations, but filesystem implementations at least are
> constrained by their need to present a common API and must conform with
> and leverage the VFS infrastructure. Different security modules present
> very different interfaces and behaviors from one another and LSM doesn't
> provide the same kind of common functionality and well-defined semantics
> as the VFS. The result of merging many wildly different security
> modules will be chaos for application developers and users, likely
> leading them to ignore everything but the least common denominator.
> It almost makes more sense to merge no security modules at all than to
> have LSM and many different security modules.
Look, the reality is that the common interface for application is
system calls returning EPERM. If you have to rewrite applications to
use a security module, or force application writers to create a
complicated SELinux policy, application writers will simply balk. It
Just Won't Happen. Commercial applications like Oracle, DB2,
Websphere, BEA Application Server, Tivoli Storage Manager, and so on
work on multiple OS's, and not just Linux. If the application
developers are forced to use a Linux-specific API, most of them will
just walk away; it's much simpler and cheaper to tell users to disable
SELinux. And in the commercial world, we don't have the "big stick"
the NSA has in the federal/defense space to force application writers
to pay attention to SELinux.
The situation is just the same with filesystems. The common API is
POSIX. As filesystem writers, we often kvetch about how limiting
certain filesystem interfaces created 30 years ago might be, but the
reality is, very few applications will use extended interfaces, and so
if we broke readdir() and told application writers that they had to
use this wonderful new read_directory() API that was so much better
than the old readdir() interface, they would laugh at us and ignore
us. Why do security people think they have the ability to dictate to
application writers that they use specialized API's or write arcane
security policies?
- Ted
--- Andi Kleen <[email protected]> wrote:
> Anyways; if someone wants to cripple their security for some
> performance this way they can surely do this; but i don't think we should
> offer it as a default configuration option (just as we don't have a
> CONFIG_NULL_LSM even though there are undoubtedly systems that don't
> care about permission checking[1])
>
> -Andi
>
> [1] I bet I gave the linux-tiny crowd an idea now ;-)
You would need authoritative LSM hooks for this. The current LSM
additional restrictions model does not provide for this.
Casey Schaufler
[email protected]
On Sep 30 2007 01:16, Andrew Morton wrote:
>>
>> Documentation/Smack.txt | 104 +
>> security/Kconfig | 1
>> security/Makefile | 2
>> security/smack/Kconfig | 10
>> security/smack/Makefile | 9
>> security/smack/smack.h | 207 ++
>> security/smack/smack_access.c | 345 ++++
>> security/smack/smack_lsm.c | 2685 ++++++++++++++++++++++++++++++++
>> security/smack/smackfs.c | 1201 ++++++++++++++
>> 9 files changed, 4564 insertions(+)
>
>My major non-technical concern is that Casey Schaufler might get hit by a
>bus. If this happens, we can remove the feature in three minutes (that
>diffstat again), but that may not be feasible if people have come to rely
>upon the feature.
>
>otoh, if a significant number of people are using smack, presumably someone
>else would step up to maintain smack post-bus. The risk seems acceptable
>to me.
I bet that the number of people submitting patches / possibly maintaining it
is hyperbelic to the code size. Everyone that runs away from selinux's
code size and/or "complexity" is a potential smack/aa user/contributor.
>Is smack useful without a patched ls, sshd and init.d? What is the status
>of getting those userspace patches merged? ie: do you know who to send the
>diffs to, and are they likely to take them?
As long as one does not need to recompile userspace (like it is the case with
libselinux), it wins.
* Christoph Hellwig <[email protected]> [2007-10-02 10:14]:
> On Sun, Sep 30, 2007 at 01:16:18AM -0700, Andrew Morton wrote:
> > reviewed the August thread from your version 1 submission and the message I
> > take away is that the code has been well-received and looks good when
> > considered on its own merits, but selinux could probably be configured to
> > do something sufficiently similar.
> >
> > I'd have trouble declaring that "but" to be a reason to not merge smack.
> > I'm more thinking "let's merge it and see if people use it".
>
> I'm not sure this was discussed on the list, but as long as Casey doesn't
> get rid of the magic symlinks (smackfs_follow_link), there's a clear NACK
> from the VFS perspective.
Any rationale for this NACK?
Caseys patch doesn't add something crazy like "make symlinks depend on
environment variables"; also, we already have something similar in-tree:
/proc/self.
Thomas
Linus Torvalds wrote:
>
> On Mon, 1 Oct 2007, Stephen Smalley wrote:
>> You argued against pluggable schedulers, right? Why is security
>> different?
>
> Schedulers can be objectively tested. There's this thing called
> "performance", that can generally be quantified on a load basis.
>
> Yes, you can have crazy ideas in both schedulers and security. Yes, you
> can simplify both for a particular load. Yes, you can make mistakes in
> both. But the *discussion* on security seems to never get down to real
> numbers.
>
And yet you can make the exact same case for schedulers as security, you
can quantify the behavior, but if your only choice is A it doesn't help
to know that B is better.
You say "performance" as if it had universal meaning. In truth people
want to optimize for total tps (servers), or responsiveness on the human
scale (mail, dns, nntp servers), or perceived smoothness (with many
threads updating a display to slow with load rather than start visibly
jumping the motion from one to another), or very short term response
(-rt patches). People want very different behavior under the same load,
and that is what *they* call "performance," namely best delivery of
what's important. The numbers are "hard science" but the choice of which
numbers are important is still "people wanking around with their opinions".
--
Bill Davidsen <[email protected]>
"We have more to fear from the bungling of the incompetent than from
the machinations of the wicked." - from Slashdot
On Tue, 2 Oct 2007, Bill Davidsen wrote:
>
> And yet you can make the exact same case for schedulers as security, you can
> quantify the behavior, but if your only choice is A it doesn't help to know
> that B is better.
You snipped a key part of the argument. Namely:
Another difference is that when it comes to schedulers, I feel like I
actually can make an informed decision. Which means that I'm perfectly
happy to just make that decision, and take the flak that I get for it. And
I do (both decide, and get flak). That's my job.
which you seem to not have read or understood (neither did apparently
anybody on slashdot).
> You say "performance" as if it had universal meaning.
Blah. Bogus and pointless argument removed.
When it comes to schedulers, "performance" *is* pretty damn well-defined,
and has effectively universal meaning.
The arguments that "servers" have a different profile than "desktop" is
pure and utter garbage, and is perpetuated by people who don't know what
they are talking about. The whole notion of "server" and "desktop"
scheduling being different is nothing but crap.
I don't know who came up with it, or why people continue to feed the
insane ideas. Why do people think that servers don't care about latency?
Why do people believe that desktop doesn't have multiple processors or
through-put intensive loads? Why are people continuing this *idiotic*
scheduler discussion?
Really - not only is the whole "desktop scheduler" argument totally bogus
to begin with (and only brought up by people who either don't know
anything about it, or who just want to argue, regardless of whether the
argumen is valid or not), quite frankly, when you say that it's the "same
issue" as with security models, you're simply FULL OF SH*T.
The issue with LSM is that security people simply cannot even agree on the
model. It has nothing to do with performance. It's about management, and
it's about totally different models. Have you even *looked* at the
differences between AppArmor and SELinux? Did you look at SMACK? They are
all done by people who are interested in security, but have totally
different notions of what "security" even *IS*ALL*ABOUT.
In contrast, anybody who claims that the CPU scheduler doesn't know what
it's all about is just tripping. And anybody who claims that desktop
workloads are so radically different from server workloads (or that the
hardware is so different) is just totally out to lunch.
So next time, think five minutes before you start your argument.
Linus
On Tue, 2 Oct 2007, Linus Torvalds wrote:
>
> I don't know who came up with it, or why people continue to feed the
> insane ideas. Why do people think that servers don't care about latency?
> Why do people believe that desktop doesn't have multiple processors or
> through-put intensive loads? Why are people continuing this *idiotic*
> scheduler discussion?
Btw, one thing that is true: while both servers and desktop cares about
latency, it's often easier to *see* the issues on the desktop (or hear
them: audio skipping).
But that doesn't mean that the server people wouldn't care, and it doesn't
mean that scheduling would be "fundamentally different" on servers or the
desktop.
In contrast, security really *is* fundamentally different in different
situations. For example, I find SELinux to be so irrelevant to my usage
that I don't use it at all. I just don't have any other users on my
machine, so the security I care about is in firewalls etc. And that really
*is* fundamentally different from a system that has shell access to its
users. Which in turn is fundamentally different from one that has some
legal reasons why it needs to have a particular kind of security. Which in
turn is fundamentally different from ....
You get the idea.
It boils down to: "scheduling is scheduling", and doesn't really change
apart from the kind of decisions that are required by any scheduler (ie RT
vs non-RT etc). Everybody wants the same thing in the end: low latency for
loads where that matters, high bandwidth for loads where that matters.
It's not a "one user has only one kind of load". Not at all.
Security, on the other hand, very much does depend on the circumstances
and the wishes of the users (or policy-makers). And if we had one module
that everybody would be happy with, I'd not make it pluggable either. But
as it is, we _know_ that's not the case.
Linus
On Tue, 02 Oct 2007 17:02:13 -0400
Bill Davidsen <[email protected]> wrote:
> Linus Torvalds wrote:
> >
> > On Mon, 1 Oct 2007, Stephen Smalley wrote:
> >> You argued against pluggable schedulers, right? Why is security
> >> different?
> >
> > Schedulers can be objectively tested. There's this thing called
> > "performance", that can generally be quantified on a load basis.
> >
> > Yes, you can have crazy ideas in both schedulers and security. Yes, you
> > can simplify both for a particular load. Yes, you can make mistakes in
> > both. But the *discussion* on security seems to never get down to real
> > numbers.
> >
> And yet you can make the exact same case for schedulers as security, you
> can quantify the behavior, but if your only choice is A it doesn't help
> to know that B is better.
To be fair the discussion on security does get down to real set theory
but at that point most people's eyes (mine included) glaze over somewhat.
You can reasonably quantify the behaviour and correctness of a security
model based upon mathematical principles - if anything its *easier* that
schedulers which are so much based on "feeling right".
Smack seems a perfectly good simple LSM module, its clean, its based upon
credible security models and sound theory (unlike AppArmor). I don't see
why it shouldn't go in.
Alan
> situations. For example, I find SELinux to be so irrelevant to my usage
> that I don't use it at all. I just don't have any other users on my
> machine
That you know about...
The value of SELinux (or indeed any system compartmentalising access and
limiting damage) comes into play when you get breakage - eg via a web
browser exploit.
Yes SELinux is much more relevant to servers, and really comes into its
own when its used to write custom rulesets and enforce corporate policy
("No you can't run that screensaver that arrived by email").
Alan
On Wed, 3 Oct 2007, Alan Cox wrote:
>
> Smack seems a perfectly good simple LSM module, its clean, its based upon
> credible security models and sound theory (unlike AppArmor).
The problem with SELinux isn't the theory. It's the practice.
IOW, it's too hard to use.
Apparently Ubuntu is giving up on it too, for that reason.
And what some people seem to have trouble admitting is that theory counts
for nothing, if the practice isn't there.
So quite frankly, the SELinux people would look at whole lot smarter if
they didn't blather on about "theory".
Linus
Linus Torvalds wrote:
> On Tue, 2 Oct 2007, Bill Davidsen wrote:
>
>> And yet you can make the exact same case for schedulers as security, you can
>> quantify the behavior, but if your only choice is A it doesn't help to know
>> that B is better.
>>
>
> You snipped a key part of the argument. Namely:
>
> Another difference is that when it comes to schedulers, I feel like I
> actually can make an informed decision. Which means that I'm perfectly
> happy to just make that decision, and take the flak that I get for it. And
> I do (both decide, and get flak). That's my job.
>
> which you seem to not have read or understood (neither did apparently
> anybody on slashdot).
>
Actually I had quoted that, made a reply, and decided that my reply was
too close to a flame and deleted the quote and the nasty reply, because
I couldn't find a nice way to say what I wanted. Oh well, I tried to
keep to a higher level, but... on this topic you seem to be off on an
ego trip. You are not the decider, George Bush is the decider, and the
only time he's not wrong he didn't understand the question. I checked
the schedule, it's not you week to be God.
There are sensible people you respect on other topics, who have the
opinion that there is room for behaviors other than CFS, and who have
created a pluggable scheduler framework which they are trying to hand
you on a platter. And you won't even consider that they might be right,
because you believe there can be one scheduler which is close to optimal
for all loads.
>> You say "performance" as if it had universal meaning.
>>
>
> Blah. Bogus and pointless argument removed.
>
> When it comes to schedulers, "performance" *is* pretty damn well-defined,
> and has effectively universal meaning.
>
> The arguments that "servers" have a different profile than "desktop" is
> pure and utter garbage, and is perpetuated by people who don't know what
> they are talking about. The whole notion of "server" and "desktop"
> scheduling being different is nothing but crap.
>
Unfortunately not so, I've been looking at schedulers since MULTICS, and
desktops since the 70s (MP/M), and networked servers since I was the
ARPAnet technical administrator at GE's Corporate R&D Center. And on
desktops response is (and should be king), while on a server, like nntp
or mail, I will happily go from 1ms to 10sec for a message to pass
through the system if only I can pass 30% more messages per hour,
because in virtually all cases transit time in that range is not an
issue. Same thing for DNS, LDAP, etc, only smaller time range. If my
goal is <10ms, I will not sacrifice capacity to do it.
> I don't know who came up with it, or why people continue to feed the
> insane ideas. Why do people think that servers don't care about latency?
>
Because people who run servers for a living, and have to live with
limited hardware capacity realize that latency isn't the only issue to
be addressed, and that the policy for degradation of latency vs.
throughput may be very different on one server than another or a desktop.
> Why do people believe that desktop doesn't have multiple processors or
> through-put intensive loads? Why are people continuing this *idiotic*
> scheduler discussion?
>
Because people can't get you to understand that one size doesn't fit all
(and I doubt I've broken through).
> Really - not only is the whole "desktop scheduler" argument totally bogus
> to begin with (and only brought up by people who either don't know
> anything about it, or who just want to argue, regardless of whether the
> argumen is valid or not), quite frankly, when you say that it's the "same
> issue" as with security models, you're simply FULL OF SH*T.
>
The real issue is that you can't imagine that people who don't share
your opinion are not only wrong but don't understand the problem. You
may be right, but when you say anyone who disagrees is wrong by
definition, then you have lost sight of productive technical
differences. When your arguments drop to personal attacks and rants it's
time to look at your technical values.
> The issue with LSM is that security people simply cannot even agree on the
> model. It has nothing to do with performance. It's about management, and
> it's about totally different models. Have you even *looked* at the
> differences between AppArmor and SELinux? Did you look at SMACK? They are
> all done by people who are interested in security, but have totally
> different notions of what "security" even *IS*ALL*ABOUT.
>
Exactly, and I'm not the only one who doubts that more than one model
would be useful. I'm sorry you can't see that about CPU schedulers as well.
> In contrast, anybody who claims that the CPU scheduler doesn't know what
> it's all about is just tripping. And anybody who claims that desktop
> workloads are so radically different from server workloads (or that the
> hardware is so different) is just totally out to lunch.
>
> So next time, think five minutes before you start your argument.
>
I don't disagree with you lightly, in this case I think I have a better
superficial understanding of schedulers than you do of how production
servers are used.
--
bill davidsen <[email protected]>
CTO TMR Associates, Inc
Doing interesting things with small computers since 1979
On Tue, 2 Oct 2007, Bill Davidsen wrote:
>
> Unfortunately not so, I've been looking at schedulers since MULTICS, and
> desktops since the 70s (MP/M), and networked servers since I was the ARPAnet
> technical administrator at GE's Corporate R&D Center. And on desktops response
> is (and should be king), while on a server, like nntp or mail, I will happily
> go from 1ms to 10sec for a message to pass through the system if only I can
> pass 30% more messages per hour, because in virtually all cases transit time
> in that range is not an issue. Same thing for DNS, LDAP, etc, only smaller
> time range. If my goal is <10ms, I will not sacrifice capacity to do it.
Bill, that's a *tuning* issue, not a scheduler logic issue.
You can do that today. The scheduler has always had (well, *almost*
always: I think the really really original one didn't) had tuning knobs.
It in no way excuses any "pluggable scheduler", because IT DOES NOT CHANGE
THE PROBLEM.
[ Side note: not only doesn't it change the problem, but a good scheduler
tunes itself rather naturally for most things. In particular, for things
that really are CPU-limited, the scheduler should be able to notice
that, and will not aim for latency to the same degree.
In fact, what is really important is that the scheduler notice that some
programs are latency-critical AT THE SAME TIME as other programs sharing
that CPU are not, which very much implies that you absolutely MUST NOT
have a scheduler that done one or the other: it needs to know about
*both* behaviors at the same time.
IOW, it is very much *not* about multiple different "pluggable modules",
because the scheduler must be able to work *across* these kinds of
barriers. ]
So for example, with the current scheduler, you can actually set things
like scheduler latency. Exactly so you can tune things. However, I
actually would argue that you generally shouldn't need to, and if you
really do need to, and it's a huge deal for a real load (and not just a
few percent for a benchmark), we should consider that a scheduler problem.
So your "argument" is nonsense. You're arguing for something else than
what you _claim_ to be arguing for. What you state that you want actually
has nothing what-so-ever to do with pluggable schedulers, quite the
reverse!
It's also totally incorrect to state that this is somehow intrisicly a
feature of a "server load". Many server loads have very real latency
constraints. No, not the traditional UNIX loads of SMPT and NNTP, but in
many loads the latency guarantees are a rather important part of it, and
you'll have benchmarks that literally test how high the load can be until
latency reaches some intolerable value - ie latency ends up being the
critical part.
There's also a meta-development issue here: I can state with total
conviction that historically, if we had had a "server scheduler" and a
"desktop scheduler", we'd have been in much worse shape than we are now.
Not only are a lot of the loads the same or at least similar (and aiming
for _one_ scheduler - especially one that auto-tunes itself at least to to
some degree - gets you lots of good testing), but the hardware situation
changes.
For example, even just five years ago, there would have been people who
thought that multiprocessing is a server load - and they'd have been
largely right at the time. Would you have wanted a "server" (SMP, screw
latency) scheduler, a "workstation" (SMP but low-latency) scheduler and a
"desktop" (UP) scheduler for the different cases?
Because yes, SMP does impact the scheduler a lot... The locking, the
migration between CPU's, the CPU affinity.. Things that gamers five years
ago would have felt was just totally screwing them over and making the
scheduler slower and more complex "for no gain".
See? Pluggable things are generally a *bad* thing. You should generally
aim for *never* being pluggable if you can at all avoid it, because it not
only fragments the developer base over totally different code bases, it
generates unmaintainable decisions as the problem space evolves.
To get back to security: I didn't want pluggable security because I
thought that was a technically good solution. No, the reason Linux has LSM
(and yes, I was the one who pushed hard for the whole thing, even if I
didn't actually write any of it) was because the problem wasn't technical
to begin with.
It was social/political and administrative.
See? Another fundamental difference between schedulers and security
modules.
> > I don't know who came up with it, or why people continue to feed the insane
> > ideas. Why do people think that servers don't care about latency?
>
> Because people who run servers for a living, and have to live with limited
> hardware capacity realize that latency isn't the only issue to be addressed,
> and that the policy for degradation of latency vs. throughput may be very
> different on one server than another or a desktop.
Quite frankly a lot of other people run servers for a living too, and
their main issue is often latency. And no, they don't do NNTP or SMTP,
they do strange java things around databases with thousands of threads.
Should they use a "desktop" scheduler? Because clearly their loads have
nothing what-so-ever in common with yours?
Or can you possibly admit that it's really the exact same problem?
Really: tell me what the difference is between "desktop" and "server"
scheduling. There is absolutely *none*.
Yes, there are differences in tuning, but those have nothing to do with
the basic algorithm. They have to do with goals and trade-offs, and most
of the time we should aim for those things to auto-tune (we do have the
things in /proc/sys/kernel/, but I really hope very few people use them
other than for testing or for some extreme benchmarking - at least I
don't personally consider them meant primarily for "production" use).
> > Why do people believe that desktop doesn't have multiple processors or
> > through-put intensive loads? Why are people continuing this *idiotic*
> > scheduler discussion?
>
> Because people can't get you to understand that one size doesn't fit all (and
> I doubt I've broken through).
I understand the "one size" argument, I just disagree vehemently about it
having anything to do with a pluggable scheduler. The scheduler does have
tuning, most of it 100% automatic (that's what the "fairness" thing is all
about!), and none of it needs - or would even remotely be helped by -
pluggability.
Take a really simple example: you have fifty programs all wanting to run
on the same machine at the same time. There simply *needs* to be some
single scheduler that picks which one to run. At some point, you have to
make the decision. And no, they are not all "throughput" or all
"latency", and you cannot make your decision based on a "global pluggable
scheduler policy".
Some of the processes may be purely about throughput, some may be purely
about latency, and some may change over their lifetime.
Not very amenable to "pluggable" things, is it? Especially since the
thing that eventually needs to give the CPU time to *somebody* simply
needs to understand all these different needs at some level anyway. It
always ends up having to be *something* that decides, and it can
absolutely never ignore the other "somethings". So a set of independent
pluggable modules simply wouldn't work.
See?
(Sure you could make a multi-level scheduler with different pluggable ones
for different levels, but that really doesn't work very well, since even
in a multi-level one, you do want to have some generic notion of "this one
cares about latency" and "this process is about throughput", so then the
pluggable stuff wouldn't add any advantage _anyway_ - the top-level
decision would have all the complexities of the one "perfect" scheduler
you want in the first place!)
In contrast, look at fifty programs that all want to run on the same
machine at the same time, but we have security issues. Now, security
pretty much by definition cuts _across_ those programs, with the whole
point generally being to make one machine secure, so almost always you'd
generally want to have "a security model" for the whole machine (or at
least virtual machine) - it's just that the policies may be totally
different in different circumstances and across different machines.
But even if you were to *not* want to have one single policy, but have
different policies for different processes, it at least still makes
some conceptual sense, in ways it does not to try to have independent
schedulers. For schedulers, at some point, it just hits the hardware
resource: the CPU needs to be given to *one* of them. For a security
policy, it's all software choices - you don't need to limit yourself to
one choice at any time.
So a pluggable module makes more sense there anyway.
But no, that's not really why we have LSM. I'd have *much* preferred to
have one unified security module setup that we could all agree on, and no
pluggable security modules. It was not to be - and the reason we have LSM
is not because "it makes more sense than a CPU scheduler", but simply
because "people didn't actually get anything done at all, because they
just argued about what to do".
In the CPU schedulers, Ingo still gets work done, even though people argue
about it. So we haven't needed to go to the extreme of an "LSM for CPU
schedulers", because the arguments don't actually hold up the work.
And THAT is what matters in the end.
Linus
Linus Torvalds wrote:
> Security, on the other hand, very much does depend on the circumstances
> and the wishes of the users (or policy-makers). And if we had one module
> that everybody would be happy with, I'd not make it pluggable either. But
> as it is, we _know_ that's not the case.
>
And you claim you are not a security expert :-)
Crispin
--
Crispin Cowan, Ph.D. http://crispincowan.com/~crispin/
Itanium. Vista. GPLv3. Complexity at work
On Wed, Oct 03, 2007 at 01:12:46AM +0100, Alan Cox wrote:
>
> The value of SELinux (or indeed any system compartmentalising access and
> limiting damage) comes into play when you get breakage - eg via a web
> browser exploit.
well, being sick of the number of times one has to upgrade the browser
for exploits, I addressed it in a different way.
I ran firefox setuid to a different (not my main user), uid+gid, gave
my main account that gid as a supplemental group, and gave that uid
access to the X magic cookie.
... which only changes the nature of any exploit that might occur - any
injected code would have to go via X to attack my main account.
DF
On 10/04/2007 06:56 PM, Derek Fawcus wrote:
>
> I ran firefox setuid to a different (not my main user), uid+gid, gave
> my main account that gid as a supplemental group, and gave that uid
> access to the X magic cookie.
You need to use runxas to get any kind of real security.
On Thu, Oct 04, 2007 at 07:18:47PM -0400, Chuck Ebbert wrote:
> > I ran firefox setuid to a different (not my main user), uid+gid, gave
> > my main account that gid as a supplemental group, and gave that uid
> > access to the X magic cookie.
>
> You need to use runxas to get any kind of real security.
Interesting script - sad how everyone reinvents equivalent things.
I had been experimenting with running the whole lot under Xnest,
with two extra users - one for the Xnest which had the main X
cookie, and another for the browser. But found that it was just
too awkward (since I use multiple browser windows as well a tabs).
So I ended up trading a small security gain vs usablity.
The other thing I started playing with was the NX version of Xnest,
since it allows for a rootless server...
DF
Linus Torvalds <[email protected]> writes:
> To get back to security: I didn't want pluggable security because I
> thought that was a technically good solution. No, the reason Linux has LSM
> (and yes, I was the one who pushed hard for the whole thing, even if I
> didn't actually write any of it) was because the problem wasn't technical
> to begin with.
>
> It was social/political and administrative.
>
> See? Another fundamental difference between schedulers and security
> modules.
>
> But no, that's not really why we have LSM. I'd have *much* preferred to
> have one unified security module setup that we could all agree on, and no
> pluggable security modules. It was not to be - and the reason we have LSM
> is not because "it makes more sense than a CPU scheduler", but simply
> because "people didn't actually get anything done at all, because they
> just argued about what to do".
>
> In the CPU schedulers, Ingo still gets work done, even though people argue
> about it. So we haven't needed to go to the extreme of an "LSM for CPU
> schedulers", because the arguments don't actually hold up the work.
>
> And THAT is what matters in the end.
Sounds good.
I want to inject some fresh ideas into this discussion from a completely
different viewpoint, who knows I might get lucky and make things
better.
All you can do with the LSM is return -EPERM when the normal unix
permissions would not have allowed an operation. I don't see where
there is any magic or mystery in that, or any need for deep
understanding.
What we want from the LSM is the ability to say -EPERM when we can
clearly articulate that we want to disallow something.
SElinux is not all encompassing or it is generally incomprehensible I
don't know which. Or someone long ago would have said a better
way to implement containers was with a selinux ruleset, here is a
selinux ruleset that does that. Although it is completely possible to
implement all of the isolation with the existing LSM hooks as Serge
showed.
It is a legitimate criticism of the LSM that we are not improving our
in-kernel abstractions to allow better concepts to base decisions
upon when to return -EPERM. My first dealing with selinux and the lsm
was when I fixed a security issue in /proc fixed the abstractions we
were using and the default selinux security policy had a fit. If
don't have good concepts in /proc/pid/xxx which is heavily used it
would not surprise me at all if there are lots of other places in the
kernel where our abstractions holes that have not yet been shorn up.
We also have in the kernel another parallel security mechanism (for
what is generally a different class of operations) that has been quite
successful, and different groups get along quite well, and ordinary
mortals can understand it. The linux firewalling code.
The linux firewalling codes has hooks all throughout the networking
stack, just like the LSM has hooks all throughout the rest of linux
kernel. There is a difference however. The linux firewalling code in
addition to hooks has tables behind those hooks that it consults.
There is generic code to walk those tables and consult with different
kernel modules to decide if we should drop a packet. Each of those
kernel modules provides a different capability that can be used to
generate a firewall.
Meanwhile composition of a policy using code from different clients
of the LSM hooks is impossible, and thus cooperation or wider use of
the LSM hooks is difficult.
So I propose that if people want to work towards a one true linux
solution for additional security checks, then they should look towards
the linux firewalling code. It works and it seems to very nicely
allow cooperations between different groups. For the people who will
scream mixing security models causes problems, the answer is simple
recommend users don't set up their policies that way.
I know we can't solve human problems with technical measures but
perhaps a technical suggestion can open the way to the solution to
some human problems.
I'm not yet annoyed enough to go implement an iptables like interface
to the LSM enhancing it with more generic mechanism to make the
problem simpler, but I'm getting there. Perhaps next time I'm bored.
Eric
On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
> What we want from the LSM is the ability to say -EPERM when we can
> clearly articulate that we want to disallow something.
This sort of depends on perspective; typically with security
infrastructure you actually want "... the ability to return success
when we can clearly articulate that we want to *ALLOW* something".
File permissions work this way; we don't have a list of forbidden
users attached to each file, we have an owner, a group, and a mode
representing positive permissions. With that said in certain high-
risk environments you need something even stronger that cannot be
changed by the "owner" of the file, if we don't entirely trust them,
> SElinux is not all encompassing or it is generally incomprehensible
> I don't know which. Or someone long ago would have said a better
> way to implement containers was with a selinux ruleset, here is a
> selinux ruleset that does that. Although it is completely possible
> to implement all of the isolation with the existing LSM hooks as
> Serge showed.
The difference between SELinux and containers is that SELinux (and
LSM as a whole) returns -EPERM to operations outside the scope of the
subject, whereas containers return -ENOENT (because it's not even in
the same namespace).
> We also have in the kernel another parallel security mechanism (for
> what is generally a different class of operations) that has been
> quite successful, and different groups get along quite well, and
> ordinary mortals can understand it. The linux firewalling code.
Well, I wouldn't go so far as the "ordinary mortals can understand
it" part; it's still pretty high on the obtuse-o-meter.
> The linux firewalling codes has hooks all throughout the networking
> stack, just like the LSM has hooks all throughout the rest of linux
> kernel. There is a difference however. The linux firewalling code
> in addition to hooks has tables behind those hooks that it
> consults. There is generic code to walk those tables and consult
> with different kernel modules to decide if we should drop a
> packet. Each of those kernel modules provides a different
> capability that can be used to generate a firewall.
This is almost *EXACTLY* what SELinux provides as an LSM module. The
one difference is that with SELinux some compromises and restrictions
have been made so that (theoretically) the resulting policy can be
exhaustively analyzed to *prove* what it allows and disallows. It
may be that SELinux should be split into 2 parts, one that provides
the underlying table-matching and the other that uses it to provide
the provability guarantees. Here's a direct comparison:
netfilter:
(A) Each packet has src, dst, port, etc that can be matched
(B) Table of rules applied sequentially (MATCH => ACTION)
(C) Rules may alter the properties of packets as they are routed/
bridged/etc
selinux:
(A) Each object has user, role, and type that can be matched
(B) Table of rules searched by object parameters (MATCH => allow/
auditallow/transition)
(C) Rules may alter the properties of objects through transition
rules.
If there are areas where people are confused about SELinux, think it
may be improved, etc, we would be *GLAD* to hear it. I'm currently
struggling to find the time between a hundred other things to finish
a script I offered to Casey Schaufler a month and a half ago which
generated an SELinux policy based on a SMACK ruleset.
> So I propose that if people want to work towards a one true linux
> solution for additional security checks, then they should look
> towards the linux firewalling code. It works and it seems to very
> nicely allow cooperations between different groups. For the people
> who will scream mixing security models causes problems, the answer
> is simple recommend users don't set up their policies that way.
Actually the one thing which really frustrates me about the Linux
firewalling code is that you cannot selectively apply various
transformation phases, they are automatically applied for you. I
have had a couple very-transparent-routing-firewalling-bridging
scenarios where I wished I could run the bridging phase, compare-and-
change the result, and then run the bridging phase again to forward
the packet elsewhere. For example if I was to set up a diverted
ethernet port I would need to apply the bridging code, compare the
destination port against the selected diverted port and change the
MAC address, then reapply the bridging code. To mirror you would
also need a phase which could create multiple clones of packets and
conditionalize rules based on which of the copies it was.
> I'm not yet annoyed enough to go implement an iptables like
> interface to the LSM enhancing it with more generic mechanism to
> make the problem simpler, but I'm getting there. Perhaps next time
> I'm bored.
I think a fair amount of what we need is already done in SELinux, and
efforts would be better spent in figuring out what seems too
complicated in SELinux and making it simpler. Probably a fair amount
of that just means better tools.
Cheers,
Kyle Moffett
Kyle Moffett <[email protected]> writes:
> On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
>> What we want from the LSM is the ability to say -EPERM when we can clearly
>> articulate that we want to disallow something.
>
> This sort of depends on perspective; typically with security infrastructure you
> actually want "... the ability to return success when we can clearly articulate
> that we want to *ALLOW* something". File permissions work this way; we don't
> have a list of forbidden users attached to each file, we have an owner, a
> group, and a mode representing positive permissions. With that said in certain
> high-
> risk environments you need something even stronger that cannot be changed by the
> "owner" of the file, if we don't entirely trust them,
Yes. However last I looked at the LSM hooks we first do the normal unix
permission checks. Then we run the hook. So it can only increase the
number of times we say -EPERM.
>> SElinux is not all encompassing or it is generally incomprehensible I don't
>> know which. Or someone long ago would have said a better way to implement
>> containers was with a selinux ruleset, here is a selinux ruleset that does
>> that. Although it is completely possible to implement all of the isolation
>> with the existing LSM hooks as Serge showed.
>
> The difference between SELinux and containers is that SELinux (and LSM as a
> whole) returns -EPERM to operations outside the scope of the subject, whereas
> containers return -ENOENT (because it's not even in the same namespace).
Yes. However if you look at what the first implementations were. Especially
something like linux-vserver. All they provided was isolation. So perhaps
you would not see every process ps but they all had unique pid values.
I'm pretty certain Serge at least prototyped a simplified version
of that using the LSM hooks. Is there something I'm not remember in
those hooks that allows hiding of information like processes?
Yes. Currently with containers we are taking that one step farther as
that solves a wider set of problems.
>> We also have in the kernel another parallel security mechanism (for what is
>> generally a different class of operations) that has been quite successful,
>> and different groups get along quite well, and ordinary mortals can
>> understand it. The linux firewalling code.
>
> Well, I wouldn't go so far as the "ordinary mortals can understand it" part;
> it's still pretty high on the obtuse-o-meter.
True. Probably a more accurate statement is:`unix command line power
users can and do handle it after reading the docs. That's not quite
ordinary mortals but it feels like it some days. It might all be
perception...
>> The linux firewalling codes has hooks all throughout the networking stack,
>> just like the LSM has hooks all throughout the rest of linux kernel. There
>> is a difference however. The linux firewalling code in addition to hooks has
>> tables behind those hooks that it consults. There is generic code to walk
>> those tables and consult with different kernel modules to decide if we should
>> drop a packet. Each of those kernel modules provides a different capability
>> that can be used to generate a firewall.
>
> This is almost *EXACTLY* what SELinux provides as an LSM module. The one
> difference is that with SELinux some compromises and restrictions have been
> made so that (theoretically) the resulting policy can be exhaustively analyzed
> to *prove* what it allows and disallows. It may be that SELinux should be
> split into 2 parts, one that provides the underlying table-matching and the
> other that uses it to provide the provability guarantees. Here's a direct
> comparison:
>
> netfilter:
> (A) Each packet has src, dst, port, etc that can be matched
> (B) Table of rules applied sequentially (MATCH => ACTION)
> (C) Rules may alter the properties of packets as they are routed/
> bridged/etc
>
> selinux:
> (A) Each object has user, role, and type that can be matched
> (B) Table of rules searched by object parameters (MATCH => allow/
> auditallow/transition)
> (C) Rules may alter the properties of objects through transition rules.
Ok. There is something here.
However in a generic setup, at least role would be an extended match
criteria provided by the selinux module. It would not be a core
attribute. It would need to depend on some extra functionality being
compiled in.
>> I'm not yet annoyed enough to go implement an iptables like interface to the
>> LSM enhancing it with more generic mechanism to make the problem simpler, but
>> I'm getting there. Perhaps next time I'm bored.
>
> I think a fair amount of what we need is already done in SELinux, and efforts
> would be better spent in figuring out what seems too complicated in SELinux and
> making it simpler. Probably a fair amount of that just means better tools.
How about thinking of it another way.
Perform the split up you talked about above and move the table
matching into the LSM hooks.
Use something like the iptables action and match to module mapping
code so we can have multiple modules compiled in and useable at the
same time with the LSM hooks.
I think it is firmly established that selling SElinux to everyone is
politically untenable. However enhancing the LSM (even if it is
mostly selinux code movement down a layer) I think can be sold.
If I could run Serge's isolation code and selinux rules at the same
time that would be interesting.
My impression is that selinux is one monolithic blob that doesn't
allow me to incrementally add matching or action features that I
find interesting.
Eric
On Oct 05, 2007, at 00:45:17, Eric W. Biederman wrote:
> Kyle Moffett <[email protected]> writes:
>
>> On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
>>> SElinux is not all encompassing or it is generally
>>> incomprehensible I don't know which. Or someone long ago would
>>> have said a better way to implement containers was with a
>>> selinux ruleset, here is a selinux ruleset that does that.
>>> Although it is completely possible to implement all of the
>>> isolation with the existing LSM hooks as Serge showed.
>>
>> The difference between SELinux and containers is that SELinux (and
>> LSM as a whole) returns -EPERM to operations outside the scope of
>> the subject, whereas containers return -ENOENT (because it's not
>> even in the same namespace).
>
> Yes. However if you look at what the first implementations were.
> Especially something like linux-vserver. All they provided was
> isolation. So perhaps you would not see every process ps but they
> all had unique pid values.
>
> I'm pretty certain Serge at least prototyped a simplified version
> of that using the LSM hooks. Is there something I'm not remember
> in those hooks that allows hiding of information like processes?
>
> Yes. Currently with containers we are taking that one step farther
> as that solves a wider set of problems.
IMHO, containers have a subtly different purpose from LSM even though
both are about information hiding. Basically a container is
information hiding primarily for administrative reasons; either as a
convenience to help prevent errors or as a way of describing
administrative boundaries. For example, even in an environment where
all sysadmins are trusted employees, a few head-honcho sysadmins
would get root container access, and all others would get access to
specific containers as a way of preventing "oops" errors. Basically
a container is about "full access inside this box and no access
outside".
By contrast, LSM is more strictly about providing *limited* access to
resources. For an accounting business all client records would
grouped and associated together, however those which have passed this
year's review are read-only except by specific staff and others may
have information restricted to some subset of the employees.
So containers are exclusive subsets of "the system" while LSM should
be about non-exclusive information restriction.
>>> We also have in the kernel another parallel security mechanism
>>> (for what is generally a different class of operations) that has
>>> been quite successful, and different groups get along quite
>>> well, and ordinary mortals can understand it. The linux
>>> firewalling code.
>>
>> Well, I wouldn't go so far as the "ordinary mortals can understand
>> it" part; it's still pretty high on the obtuse-o-meter.
>
> True. Probably a more accurate statement is:`unix command line
> power users can and do handle it after reading the docs. That's
> not quite ordinary mortals but it feels like it some days. It
> might all be perception...
I have seen more *wrong* iptables firewalls than I've seen correct
ones. Securing TCP/IP traffic properly requires either a lot of
training/experience or a good out-of-the-box system like Shorewall
which structures the necessary restrictions for you based on an
abstract description of the desired functionality. For instance what
percentage of admins do you think could correctly set up their
netfilter firewalls to log christmas-tree packets, smurfs, etc
without the help of some external tool? Hell, I don't trust myself
to reliably do it without a lot of reading of docs and testing, and
I've been doing netfilter firewalls for a while.
The bottom line is that with iptables it is *CRITICAL* to have a good
set of interface tools to take the users' "My system is set up
like..." description in some form and turn it into the necessary set
of efficient security rules. The *exact* same issue applies to
SELinux, with 2 major additional problems:
1) Half the tools are still somewhat beta-ish and under heavy
development. Furthermore the semi-official reference policy is
nowhere near comprehensive and pretty ugly to read (go back to the
point about the tools being beta-ish).
2) If you break your system description or translation tools then
instead of just your network dying your entire *system* dies.
>>> The linux firewalling codes has hooks all throughout the
>>> networking stack, just like the LSM has hooks all throughout the
>>> rest of linux kernel. There is a difference however. The linux
>>> firewalling code in addition to hooks has tables behind those
>>> hooks that it consults. There is generic code to walk those
>>> tables and consult with different kernel modules to decide if we
>>> should drop a packet. Each of those kernel modules provides a
>>> different capability that can be used to generate a firewall.
>>
>> This is almost *EXACTLY* what SELinux provides as an LSM module.
>> The one difference is that with SELinux some compromises and
>> restrictions have been made so that (theoretically) the resulting
>> policy can be exhaustively analyzed to *prove* what it allows and
>> disallows. It may be that SELinux should be split into 2 parts,
>> one that provides the underlying table-matching and the other
>> that uses it to provide the provability guarantees. Here's a
>> direct comparison:
>>
>> netfilter:
>> (A) Each packet has src, dst, port, etc that can be matched
>> (B) Table of rules applied sequentially (MATCH => ACTION)
>> (C) Rules may alter the properties of packets as they are routed/
>> bridged/etc
>>
>> selinux:
>> (A) Each object has user, role, and type that can be matched
>> (B) Table of rules searched by object parameters (MATCH => allow/
>> auditallow/transition)
>> (C) Rules may alter the properties of objects through transition
>> rules.
>
> Ok. There is something here.
>
> However in a generic setup, at least role would be an extended
> match criteria provided by the selinux module. It would not be a
> core attribute. It would need to depend on some extra
> functionality being compiled in.
Now see I think *THAT* is where Casey should be going with his SMACK
code. Don't add another LSM, start looking at SELinux and figuring
out what parts he does not need and how they can be parameterized out
at build time for smaller systems.
On the other hand, the "user" and "role" fields in SELinux are
already fairly flexible. The one constant is that user=>role and
role=>type must both be allowed for a label to be valid. Other than
that, the constraints specify what must be true for a transition to
be allowed. For example the standard strict reference policy
includes this bit:
constrain process transition (
(u1 == u2) or
(t1 == can_change_process_identity and t2 == process_user_target) or
(t1 == cron_source_domain and (t2 == cron_job_domain or u2 ==
system_u)) or
(t1 == can_system_change and u2 == system_u) or
(t1 == process_uncond_exempt)
);
Basically all constraints on a particular access vector must be
satisfied for that to be allowed (in addition to other things). For
the above example, a process running exec() may only change its user
if one of the following:
* It's a login-like program and is starting a user entrypoint
* It's a cron-like program and is starting a user or system cronjob
* It's a process allowed to start system processes (admin runs
initscripts)
* It's unconditionally exempt
By creating types and assigning meaningful attributes to those types
you may restrict the changing of the "user" and "role" however you
would like, including not at all.
Really SELinux is just a fairly elaborate security state-machine.
Each process on the system is in a given "state", defined by its
label, and "state transitions" are only allowed based on the rules
defined in the database. Since there are 4 extremely common security
models that people like to combine there are 4 fields in each SELinux
label:
(A) User: User A may not poke user B's processes/data, even if
they happen to be running in the same UNIX UID
(B) Role: Users may only perform operations for the role they are
currently logged in as
(C) Type-enforcement: An apache process may only read files that
it needs to operate correctly
(D) Multi-level: Top-secret data can't magically become
unclassified
Perhaps the thing to do would be to make it possible to compile out
the portions which people don't want. That would certainly satisfy
Casey, he would build only the "Type-enforcement" portion or only the
"Multi-level" portion and be able to do exactly the same things he
does now with a bit finer granularity of operations. By defining the
lists of operations he cares about for "r" (read), "w" (write),
"x" (exec), "a" (append), and requires-capabilities, you can just
give those permissions directly in a simplified SELinux-type policy.
>>> I'm not yet annoyed enough to go implement an iptables like
>>> interface to the LSM enhancing it with more generic mechanism to
>>> make the problem simpler, but I'm getting there. Perhaps next
>>> time I'm bored.
>>
>> I think a fair amount of what we need is already done in SELinux,
>> and efforts would be better spent in figuring out what seems too
>> complicated in SELinux and making it simpler. Probably a fair
>> amount of that just means better tools.
>
> How about thinking of it another way.
>
> Perform the split up you talked about above and move the table
> matching into the LSM hooks.
>
> Use something like the iptables action and match to module mapping
> code so we can have multiple modules compiled in and useable at the
> same time with the LSM hooks.
>
> I think it is firmly established that selling SElinux to everyone
> is politically untenable. However enhancing the LSM (even if it is
> mostly selinux code movement down a layer) I think can be sold.
>
> If I could run Serge's isolation code and selinux rules at the same
> time that would be interesting.
>
> My impression is that selinux is one monolithic blob that doesn't
> allow me to incrementally add matching or action features that I
> find interesting.
Well the major problem here is the performance one. As anybody who
has tried to do a thousand-linear-rule IPtables set will quickly tell
you, it makes performance go all to hell. Good iptables frontends
like shorewall build little subchains to keep the fast-path as
efficient as possible but regardless the search is a linear rule-
traversal (IE: O(N) where N is the number of rules you had to test).
In order to get good enough performance out of SELinux they had to
*start* with an O(log(N) rule traversal which means that execution-
order-style rules are impossible, so you *MUST* limit the fields and
prevent any overlap between rules. For example, in SELinux nobody
writes "deny" rules because the interpretation-order is undefined.
Instead you only write "allow" rules for the things you actually want
to allow. The one exception is "neverallow" rules which are verified
at compile time as sanity checks and never actually loaded in the
kernel.
Cheers,
Kyle Moffett
--- Kyle Moffett <[email protected]> wrote:
> On Oct 05, 2007, at 00:45:17, Eric W. Biederman wrote:
> > Kyle Moffett <[email protected]> writes:
> >
> >> On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
> >>> SElinux is not all encompassing or it is generally
> >>> incomprehensible I don't know which. Or someone long ago would
> >>> have said a better way to implement containers was with a
> >>> selinux ruleset, here is a selinux ruleset that does that.
> >>> Although it is completely possible to implement all of the
> >>> isolation with the existing LSM hooks as Serge showed.
> >>
> >> The difference between SELinux and containers is that SELinux (and
> >> LSM as a whole) returns -EPERM to operations outside the scope of
> >> the subject, whereas containers return -ENOENT (because it's not
> >> even in the same namespace).
> >
> > Yes. However if you look at what the first implementations were.
> > Especially something like linux-vserver. All they provided was
> > isolation. So perhaps you would not see every process ps but they
> > all had unique pid values.
> >
> > I'm pretty certain Serge at least prototyped a simplified version
> > of that using the LSM hooks. Is there something I'm not remember
> > in those hooks that allows hiding of information like processes?
> >
> > Yes. Currently with containers we are taking that one step farther
> > as that solves a wider set of problems.
>
> IMHO, containers have a subtly different purpose from LSM even though
> both are about information hiding. Basically a container is
> information hiding primarily for administrative reasons; either as a
> convenience to help prevent errors or as a way of describing
> administrative boundaries. For example, even in an environment where
> all sysadmins are trusted employees, a few head-honcho sysadmins
> would get root container access, and all others would get access to
> specific containers as a way of preventing "oops" errors. Basically
> a container is about "full access inside this box and no access
> outside".
>
> By contrast, LSM is more strictly about providing *limited* access to
> resources. For an accounting business all client records would
> grouped and associated together, however those which have passed this
> year's review are read-only except by specific staff and others may
> have information restricted to some subset of the employees.
>
> So containers are exclusive subsets of "the system" while LSM should
> be about non-exclusive information restriction.
Yes. Isolation is a much simpler problem than access control.
> >>> We also have in the kernel another parallel security mechanism
> >>> (for what is generally a different class of operations) that has
> >>> been quite successful, and different groups get along quite
> >>> well, and ordinary mortals can understand it. The linux
> >>> firewalling code.
> >>
> >> Well, I wouldn't go so far as the "ordinary mortals can understand
> >> it" part; it's still pretty high on the obtuse-o-meter.
> >
> > True. Probably a more accurate statement is:`unix command line
> > power users can and do handle it after reading the docs. That's
> > not quite ordinary mortals but it feels like it some days. It
> > might all be perception...
>
> I have seen more *wrong* iptables firewalls than I've seen correct
> ones. Securing TCP/IP traffic properly requires either a lot of
> training/experience or a good out-of-the-box system like Shorewall
> which structures the necessary restrictions for you based on an
> abstract description of the desired functionality. For instance what
> percentage of admins do you think could correctly set up their
> netfilter firewalls to log christmas-tree packets, smurfs, etc
> without the help of some external tool? Hell, I don't trust myself
> to reliably do it without a lot of reading of docs and testing, and
> I've been doing netfilter firewalls for a while.
>
> The bottom line is that with iptables it is *CRITICAL* to have a good
> set of interface tools to take the users' "My system is set up
> like..." description in some form and turn it into the necessary set
> of efficient security rules. The *exact* same issue applies to
> SELinux, with 2 major additional problems:
>
> 1) Half the tools are still somewhat beta-ish and under heavy
> development. Furthermore the semi-official reference policy is
> nowhere near comprehensive and pretty ugly to read (go back to the
> point about the tools being beta-ish).
>
> 2) If you break your system description or translation tools then
> instead of just your network dying your entire *system* dies.
>
>
> >>> The linux firewalling codes has hooks all throughout the
> >>> networking stack, just like the LSM has hooks all throughout the
> >>> rest of linux kernel. There is a difference however. The linux
> >>> firewalling code in addition to hooks has tables behind those
> >>> hooks that it consults. There is generic code to walk those
> >>> tables and consult with different kernel modules to decide if we
> >>> should drop a packet. Each of those kernel modules provides a
> >>> different capability that can be used to generate a firewall.
> >>
> >> This is almost *EXACTLY* what SELinux provides as an LSM module.
> >> The one difference is that with SELinux some compromises and
> >> restrictions have been made so that (theoretically) the resulting
> >> policy can be exhaustively analyzed to *prove* what it allows and
> >> disallows. It may be that SELinux should be split into 2 parts,
> >> one that provides the underlying table-matching and the other
> >> that uses it to provide the provability guarantees. Here's a
> >> direct comparison:
> >>
> >> netfilter:
> >> (A) Each packet has src, dst, port, etc that can be matched
> >> (B) Table of rules applied sequentially (MATCH => ACTION)
> >> (C) Rules may alter the properties of packets as they are routed/
> >> bridged/etc
> >>
> >> selinux:
> >> (A) Each object has user, role, and type that can be matched
> >> (B) Table of rules searched by object parameters (MATCH => allow/
> >> auditallow/transition)
> >> (C) Rules may alter the properties of objects through transition
> >> rules.
> >
> > Ok. There is something here.
> >
> > However in a generic setup, at least role would be an extended
> > match criteria provided by the selinux module. It would not be a
> > core attribute. It would need to depend on some extra
> > functionality being compiled in.
>
> Now see I think *THAT* is where Casey should be going with his SMACK
> code. Don't add another LSM, start looking at SELinux and figuring
> out what parts he does not need and how they can be parameterized out
> at build time for smaller systems.
Good suggestion. In fact, that is exactly how I approached my
first two attempts at the problem. What you get if you take that
route is an imposing infrastructure that has virually nothing
to do and that adds no value to the solution. Programming to the
LSM interface, on the other hand, allowed me to drastically reduce
the size and complexity of the implementation.
> On the other hand, the "user" and "role" fields in SELinux are
> already fairly flexible. The one constant is that user=>role and
> role=>type must both be allowed for a label to be valid. Other than
> that, the constraints specify what must be true for a transition to
> be allowed. For example the standard strict reference policy
> includes this bit:
>
> constrain process transition (
> (u1 == u2) or
> (t1 == can_change_process_identity and t2 == process_user_target) or
> (t1 == cron_source_domain and (t2 == cron_job_domain or u2 ==
> system_u)) or
> (t1 == can_system_change and u2 == system_u) or
> (t1 == process_uncond_exempt)
> );
>
> Basically all constraints on a particular access vector must be
> satisfied for that to be allowed (in addition to other things). For
> the above example, a process running exec() may only change its user
> if one of the following:
>
> * It's a login-like program and is starting a user entrypoint
> * It's a cron-like program and is starting a user or system cronjob
> * It's a process allowed to start system processes (admin runs
> initscripts)
> * It's unconditionally exempt
>
> By creating types and assigning meaningful attributes to those types
> you may restrict the changing of the "user" and "role" however you
> would like, including not at all.
>
> Really SELinux is just a fairly elaborate security state-machine.
> Each process on the system is in a given "state", defined by its
> label, and "state transitions" are only allowed based on the rules
> defined in the database. Since there are 4 extremely common security
> models that people like to combine there are 4 fields in each SELinux
> label:
> (A) User: User A may not poke user B's processes/data, even if
> they happen to be running in the same UNIX UID
> (B) Role: Users may only perform operations for the role they are
> currently logged in as
> (C) Type-enforcement: An apache process may only read files that
> it needs to operate correctly
> (D) Multi-level: Top-secret data can't magically become
> unclassified
>
> Perhaps the thing to do would be to make it possible to compile out
> the portions which people don't want. That would certainly satisfy
> Casey, he would build only the "Type-enforcement" portion or only the
> "Multi-level" portion and be able to do exactly the same things he
> does now with a bit finer granularity of operations. By defining the
> lists of operations he cares about for "r" (read), "w" (write),
> "x" (exec), "a" (append), and requires-capabilities, you can just
> give those permissions directly in a simplified SELinux-type policy.
But Kyle, it's already possible to compile out the part I don't
want. I configure SELinux off and away I go.
Smack is not a subset of SELinux, it behaves differently. SELinux
has a policy that is program behavior oriented, Smack is strictly
subjet/object oriented. Your 4 components (A-D) are meaningless to
Smack.
> >>> I'm not yet annoyed enough to go implement an iptables like
> >>> interface to the LSM enhancing it with more generic mechanism to
> >>> make the problem simpler, but I'm getting there. Perhaps next
> >>> time I'm bored.
> >>
> >> I think a fair amount of what we need is already done in SELinux,
> >> and efforts would be better spent in figuring out what seems too
> >> complicated in SELinux and making it simpler.
The granularity and consequently the size of the policy specificiation
result in policies that are too complicated. Tieing the policy to the
expected behavior of specific applications adds to the complexity.
SELinux is designed to increase in complexity as it evolves. Making
it simpler would conflict with the design goal of finer granularity.
> >> Probably a fair amount of that just means better tools.
Now what kind of tools are you talking about? Static analysis?
Data flow diagrammers for Java?
> > How about thinking of it another way.
> >
> > Perform the split up you talked about above and move the table
> > matching into the LSM hooks.
> >
> > Use something like the iptables action and match to module mapping
> > code so we can have multiple modules compiled in and useable at the
> > same time with the LSM hooks.
> >
> > I think it is firmly established that selling SElinux to everyone
> > is politically untenable. However enhancing the LSM (even if it is
> > mostly selinux code movement down a layer) I think can be sold.
That would be silly. Smack uses a significantly smaller set of hooks
than SELinux requires and still does interesting things. We went through
the "replace LSM with the SELinux interface" exercise a couple years
ago, I would hate to have to regurgitate all those discussions.
> > If I could run Serge's isolation code and selinux rules at the same
> > time that would be interesting.
> >
> > My impression is that selinux is one monolithic blob that doesn't
> > allow me to incrementally add matching or action features that I
> > find interesting.
>
> Well the major problem here is the performance one. As anybody who
> has tried to do a thousand-linear-rule IPtables set will quickly tell
> you, it makes performance go all to hell. Good iptables frontends
> like shorewall build little subchains to keep the fast-path as
> efficient as possible but regardless the search is a linear rule-
> traversal (IE: O(N) where N is the number of rules you had to test).
> In order to get good enough performance out of SELinux they had to
> *start* with an O(log(N) rule traversal which means that execution-
> order-style rules are impossible, so you *MUST* limit the fields and
> prevent any overlap between rules. For example, in SELinux nobody
> writes "deny" rules because the interpretation-order is undefined.
> Instead you only write "allow" rules for the things you actually want
> to allow. The one exception is "neverallow" rules which are verified
> at compile time as sanity checks and never actually loaded in the
> kernel.
>
> Cheers,
> Kyle Moffett
>
>
>
Casey Schaufler
[email protected]
On Fri, 2007-10-05 at 09:27 -0700, Casey Schaufler wrote:
> --- Kyle Moffett <[email protected]> wrote:
>
> > On Oct 05, 2007, at 00:45:17, Eric W. Biederman wrote:
> > > Kyle Moffett <[email protected]> writes:
> > >
> > >> On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
> > >>> SElinux is not all encompassing or it is generally
> > >>> incomprehensible I don't know which. Or someone long ago would
> > >>> have said a better way to implement containers was with a
> > >>> selinux ruleset, here is a selinux ruleset that does that.
> > >>> Although it is completely possible to implement all of the
> > >>> isolation with the existing LSM hooks as Serge showed.
> > >>
> > >> The difference between SELinux and containers is that SELinux (and
> > >> LSM as a whole) returns -EPERM to operations outside the scope of
> > >> the subject, whereas containers return -ENOENT (because it's not
> > >> even in the same namespace).
> > >
> > > Yes. However if you look at what the first implementations were.
> > > Especially something like linux-vserver. All they provided was
> > > isolation. So perhaps you would not see every process ps but they
> > > all had unique pid values.
> > >
> > > I'm pretty certain Serge at least prototyped a simplified version
> > > of that using the LSM hooks. Is there something I'm not remember
> > > in those hooks that allows hiding of information like processes?
> > >
> > > Yes. Currently with containers we are taking that one step farther
> > > as that solves a wider set of problems.
> >
> > IMHO, containers have a subtly different purpose from LSM even though
> > both are about information hiding. Basically a container is
> > information hiding primarily for administrative reasons; either as a
> > convenience to help prevent errors or as a way of describing
> > administrative boundaries. For example, even in an environment where
> > all sysadmins are trusted employees, a few head-honcho sysadmins
> > would get root container access, and all others would get access to
> > specific containers as a way of preventing "oops" errors. Basically
> > a container is about "full access inside this box and no access
> > outside".
> >
> > By contrast, LSM is more strictly about providing *limited* access to
> > resources. For an accounting business all client records would
> > grouped and associated together, however those which have passed this
> > year's review are read-only except by specific staff and others may
> > have information restricted to some subset of the employees.
> >
> > So containers are exclusive subsets of "the system" while LSM should
> > be about non-exclusive information restriction.
>
> Yes. Isolation is a much simpler problem than access control.
>
> > >>> We also have in the kernel another parallel security mechanism
> > >>> (for what is generally a different class of operations) that has
> > >>> been quite successful, and different groups get along quite
> > >>> well, and ordinary mortals can understand it. The linux
> > >>> firewalling code.
> > >>
> > >> Well, I wouldn't go so far as the "ordinary mortals can understand
> > >> it" part; it's still pretty high on the obtuse-o-meter.
> > >
> > > True. Probably a more accurate statement is:`unix command line
> > > power users can and do handle it after reading the docs. That's
> > > not quite ordinary mortals but it feels like it some days. It
> > > might all be perception...
> >
> > I have seen more *wrong* iptables firewalls than I've seen correct
> > ones. Securing TCP/IP traffic properly requires either a lot of
> > training/experience or a good out-of-the-box system like Shorewall
> > which structures the necessary restrictions for you based on an
> > abstract description of the desired functionality. For instance what
> > percentage of admins do you think could correctly set up their
> > netfilter firewalls to log christmas-tree packets, smurfs, etc
> > without the help of some external tool? Hell, I don't trust myself
> > to reliably do it without a lot of reading of docs and testing, and
> > I've been doing netfilter firewalls for a while.
> >
> > The bottom line is that with iptables it is *CRITICAL* to have a good
> > set of interface tools to take the users' "My system is set up
> > like..." description in some form and turn it into the necessary set
> > of efficient security rules. The *exact* same issue applies to
> > SELinux, with 2 major additional problems:
> >
> > 1) Half the tools are still somewhat beta-ish and under heavy
> > development. Furthermore the semi-official reference policy is
> > nowhere near comprehensive and pretty ugly to read (go back to the
> > point about the tools being beta-ish).
> >
> > 2) If you break your system description or translation tools then
> > instead of just your network dying your entire *system* dies.
> >
> >
> > >>> The linux firewalling codes has hooks all throughout the
> > >>> networking stack, just like the LSM has hooks all throughout the
> > >>> rest of linux kernel. There is a difference however. The linux
> > >>> firewalling code in addition to hooks has tables behind those
> > >>> hooks that it consults. There is generic code to walk those
> > >>> tables and consult with different kernel modules to decide if we
> > >>> should drop a packet. Each of those kernel modules provides a
> > >>> different capability that can be used to generate a firewall.
> > >>
> > >> This is almost *EXACTLY* what SELinux provides as an LSM module.
> > >> The one difference is that with SELinux some compromises and
> > >> restrictions have been made so that (theoretically) the resulting
> > >> policy can be exhaustively analyzed to *prove* what it allows and
> > >> disallows. It may be that SELinux should be split into 2 parts,
> > >> one that provides the underlying table-matching and the other
> > >> that uses it to provide the provability guarantees. Here's a
> > >> direct comparison:
> > >>
> > >> netfilter:
> > >> (A) Each packet has src, dst, port, etc that can be matched
> > >> (B) Table of rules applied sequentially (MATCH => ACTION)
> > >> (C) Rules may alter the properties of packets as they are routed/
> > >> bridged/etc
> > >>
> > >> selinux:
> > >> (A) Each object has user, role, and type that can be matched
> > >> (B) Table of rules searched by object parameters (MATCH => allow/
> > >> auditallow/transition)
> > >> (C) Rules may alter the properties of objects through transition
> > >> rules.
> > >
> > > Ok. There is something here.
> > >
> > > However in a generic setup, at least role would be an extended
> > > match criteria provided by the selinux module. It would not be a
> > > core attribute. It would need to depend on some extra
> > > functionality being compiled in.
> >
> > Now see I think *THAT* is where Casey should be going with his SMACK
> > code. Don't add another LSM, start looking at SELinux and figuring
> > out what parts he does not need and how they can be parameterized out
> > at build time for smaller systems.
>
> Good suggestion. In fact, that is exactly how I approached my
> first two attempts at the problem. What you get if you take that
> route is an imposing infrastructure that has virually nothing
> to do and that adds no value to the solution. Programming to the
> LSM interface, on the other hand, allowed me to drastically reduce
> the size and complexity of the implementation.
It would be interesting to see the result of those first two attempts
(even if they didn't get very far) just to see your approach and what
obstacles you ran up against.
> > On the other hand, the "user" and "role" fields in SELinux are
> > already fairly flexible. The one constant is that user=>role and
> > role=>type must both be allowed for a label to be valid. Other than
> > that, the constraints specify what must be true for a transition to
> > be allowed. For example the standard strict reference policy
> > includes this bit:
> >
> > constrain process transition (
> > (u1 == u2) or
> > (t1 == can_change_process_identity and t2 == process_user_target) or
> > (t1 == cron_source_domain and (t2 == cron_job_domain or u2 ==
> > system_u)) or
> > (t1 == can_system_change and u2 == system_u) or
> > (t1 == process_uncond_exempt)
> > );
> >
> > Basically all constraints on a particular access vector must be
> > satisfied for that to be allowed (in addition to other things). For
> > the above example, a process running exec() may only change its user
> > if one of the following:
> >
> > * It's a login-like program and is starting a user entrypoint
> > * It's a cron-like program and is starting a user or system cronjob
> > * It's a process allowed to start system processes (admin runs
> > initscripts)
> > * It's unconditionally exempt
> >
> > By creating types and assigning meaningful attributes to those types
> > you may restrict the changing of the "user" and "role" however you
> > would like, including not at all.
> >
> > Really SELinux is just a fairly elaborate security state-machine.
> > Each process on the system is in a given "state", defined by its
> > label, and "state transitions" are only allowed based on the rules
> > defined in the database. Since there are 4 extremely common security
> > models that people like to combine there are 4 fields in each SELinux
> > label:
> > (A) User: User A may not poke user B's processes/data, even if
> > they happen to be running in the same UNIX UID
> > (B) Role: Users may only perform operations for the role they are
> > currently logged in as
> > (C) Type-enforcement: An apache process may only read files that
> > it needs to operate correctly
> > (D) Multi-level: Top-secret data can't magically become
> > unclassified
> >
> > Perhaps the thing to do would be to make it possible to compile out
> > the portions which people don't want. That would certainly satisfy
> > Casey, he would build only the "Type-enforcement" portion or only the
> > "Multi-level" portion and be able to do exactly the same things he
> > does now with a bit finer granularity of operations. By defining the
> > lists of operations he cares about for "r" (read), "w" (write),
> > "x" (exec), "a" (append), and requires-capabilities, you can just
> > give those permissions directly in a simplified SELinux-type policy.
>
> But Kyle, it's already possible to compile out the part I don't
> want. I configure SELinux off and away I go.
>
> Smack is not a subset of SELinux, it behaves differently. SELinux
> has a policy that is program behavior oriented, Smack is strictly
> subjet/object oriented. Your 4 components (A-D) are meaningless to
> Smack.
To clarify, SELinux is also based on subjects and objects grouped into
equivalence classes (labels), and the granularity at which one applies
protection is configurable, so you can certainly have very
coarse-grained labels that don't require any specific knowledge of
application behavior. A type is just a security equivalence class - it
doesn't have to map to an application at all.
Also, the idea behind SELinux was that its policy engine (security
server, security/selinux/ss/*) could be replaced with other
implementations without affecting the rest of SELinux if someone wanted
to try radically different logic. The interface to that policy engine
is itself general and not tied to TE.
> > >>> I'm not yet annoyed enough to go implement an iptables like
> > >>> interface to the LSM enhancing it with more generic mechanism to
> > >>> make the problem simpler, but I'm getting there. Perhaps next
> > >>> time I'm bored.
> > >>
> > >> I think a fair amount of what we need is already done in SELinux,
> > >> and efforts would be better spent in figuring out what seems too
> > >> complicated in SELinux and making it simpler.
>
> The granularity and consequently the size of the policy specificiation
> result in policies that are too complicated. Tieing the policy to the
> expected behavior of specific applications adds to the complexity.
Well, it reveals the complexity already present in the system, and gives
you the option of controlling it. Your choice as to at what granularity
to apply it.
> SELinux is designed to increase in complexity as it evolves. Making
> it simpler would conflict with the design goal of finer granularity.
>
> > >> Probably a fair amount of that just means better tools.
>
> Now what kind of tools are you talking about? Static analysis?
> Data flow diagrammers for Java?
>
> > > How about thinking of it another way.
> > >
> > > Perform the split up you talked about above and move the table
> > > matching into the LSM hooks.
> > >
> > > Use something like the iptables action and match to module mapping
> > > code so we can have multiple modules compiled in and useable at the
> > > same time with the LSM hooks.
> > >
> > > I think it is firmly established that selling SElinux to everyone
> > > is politically untenable. However enhancing the LSM (even if it is
> > > mostly selinux code movement down a layer) I think can be sold.
>
> That would be silly. Smack uses a significantly smaller set of hooks
> than SELinux requires and still does interesting things. We went through
> the "replace LSM with the SELinux interface" exercise a couple years
> ago, I would hate to have to regurgitate all those discussions.
I don't think Eric is proposing replacing LSM with the SELinux interface
as it exists today, but rather making LSM more Netfilter-like and
radically refactoring SELinux (and any other security module) to consist
of a chain of smaller modules that are more general and reusable, and
that can be composed and applied in interesting ways via an
iptables-like interface. I'm not sure what that would look like
exactly, but it seems reasonable to explore.
One of the things left unresolved with LSM is userland API, and it does
involve more than just returning EPERM or EACCES to applications. You
already have patched ls and sshd programs, and have acknowledged the
need for more userland modifications to ultimately achieve your own
goals. If LSM is going to succeed in the kernel, then ultimately you
need some common API for userland so that you don't need separate
versions of ls, ps, sshd, etc for Smack vs SELinux vs. whatever.
--
Stephen Smalley
National Security Agency
--- Stephen Smalley <[email protected]> wrote:
> ...
>
> > Good suggestion. In fact, that is exactly how I approached my
> > first two attempts at the problem. What you get if you take that
> > route is an imposing infrastructure that has virually nothing
> > to do and that adds no value to the solution. Programming to the
> > LSM interface, on the other hand, allowed me to drastically reduce
> > the size and complexity of the implementation.
>
> It would be interesting to see the result of those first two attempts
> (even if they didn't get very far) just to see your approach and what
> obstacles you ran up against.
Woof. It weren't pretty, and I've carefully archived it so as
to make it hard to go back to for that very reason. Maybe someday.
> ...
> > Smack is not a subset of SELinux, it behaves differently. SELinux
> > has a policy that is program behavior oriented, Smack is strictly
> > subjet/object oriented. Your 4 components (A-D) are meaningless to
> > Smack.
>
> To clarify, SELinux is also based on subjects and objects grouped into
> equivalence classes (labels), and the granularity at which one applies
> protection is configurable, so you can certainly have very
> coarse-grained labels that don't require any specific knowledge of
> application behavior. A type is just a security equivalence class - it
> doesn't have to map to an application at all.
>
> Also, the idea behind SELinux was that its policy engine (security
> server, security/selinux/ss/*) could be replaced with other
> implementations without affecting the rest of SELinux if someone wanted
> to try radically different logic. The interface to that policy engine
> is itself general and not tied to TE.
The ss interface provides no advantage over the LSM interface that
I can see.
> > > >>> I'm not yet annoyed enough to go implement an iptables like
> > > >>> interface to the LSM enhancing it with more generic mechanism to
> > > >>> make the problem simpler, but I'm getting there. Perhaps next
> > > >>> time I'm bored.
> > > >>
> > > >> I think a fair amount of what we need is already done in SELinux,
> > > >> and efforts would be better spent in figuring out what seems too
> > > >> complicated in SELinux and making it simpler.
> >
> > The granularity and consequently the size of the policy specificiation
> > result in policies that are too complicated. Tieing the policy to the
> > expected behavior of specific applications adds to the complexity.
>
> Well, it reveals the complexity already present in the system, and gives
> you the option of controlling it. Your choice as to at what granularity
> to apply it.
Which is the same for LSM. There are a bunch of LSM hooks that Smack
does not need, and going into SELinux code to choose to do nothing
is pretty pointless.
> > SELinux is designed to increase in complexity as it evolves. Making
> > it simpler would conflict with the design goal of finer granularity.
> >
> > > >> Probably a fair amount of that just means better tools.
> >
> > Now what kind of tools are you talking about? Static analysis?
> > Data flow diagrammers for Java?
> >
> > > > How about thinking of it another way.
> > > >
> > > > Perform the split up you talked about above and move the table
> > > > matching into the LSM hooks.
> > > >
> > > > Use something like the iptables action and match to module mapping
> > > > code so we can have multiple modules compiled in and useable at the
> > > > same time with the LSM hooks.
> > > >
> > > > I think it is firmly established that selling SElinux to everyone
> > > > is politically untenable. However enhancing the LSM (even if it is
> > > > mostly selinux code movement down a layer) I think can be sold.
> >
> > That would be silly. Smack uses a significantly smaller set of hooks
> > than SELinux requires and still does interesting things. We went through
> > the "replace LSM with the SELinux interface" exercise a couple years
> > ago, I would hate to have to regurgitate all those discussions.
>
> I don't think Eric is proposing replacing LSM with the SELinux interface
> as it exists today, but rather making LSM more Netfilter-like and
> radically refactoring SELinux (and any other security module) to consist
> of a chain of smaller modules that are more general and reusable, and
> that can be composed and applied in interesting ways via an
> iptables-like interface. I'm not sure what that would look like
> exactly, but it seems reasonable to explore.
The image that just flashed into my brain had a disturbing
similarity to STREAMS modules, but spread everywhere, not just
in the tty code. And anyone who thinks that there are too many
LSM hooks now would have kittens over this. I don't think it's a
bad idea, but I don't see how it would change the well documented
disputes regarding what kinds of security behavior it ought to
provide for. How would it help AppArmor, for example? I'm willing
to bet (a beer or equivalence) that anything that helped there
would face stiff resistance simply because it helped there.
I could see it working if you restricted the interface to dealing
with things that have security blobs, or even better to subjects
and objects. But that's my security mindset, and I think pretty
much yours, too. It's the policies that don't use good old
fashioned OrangeBook concepts that have issue, not SELinux or Smack.
> One of the things left unresolved with LSM is userland API, and it does
> involve more than just returning EPERM or EACCES to applications. You
> already have patched ls and sshd programs, and have acknowledged the
> need for more userland modifications to ultimately achieve your own
> goals. If LSM is going to succeed in the kernel, then ultimately you
> need some common API for userland so that you don't need separate
> versions of ls, ps, sshd, etc for Smack vs SELinux vs. whatever.
Smack uses text strings for labels. It's amazing how many of the API
issues evaporate when the only thing you have to do with your labels is
compare them and print them. With the labels for processes available
through /proc, and the labels for most things available via getxattr(2)
and its variants the API issue seems hard to get worked up about. If
ls(1) had an option to show selected extended attributes, and it really
should by now, it wouldn't require fixing at all. Now sshd, login, and
the rest of the authentification gaggle are going to need policy
specific behavior so I feel no serious need to provide common API there.
Smack is designed to make this easy because I had to do it the hard
way before and didn't like it much.
Casey Schaufler
[email protected]
Stephen Smalley <[email protected]> writes:
> On Fri, 2007-10-05 at 09:27 -0700, Casey Schaufler wrote:
>> --- Kyle Moffett <[email protected]> wrote:
>>
>> > On Oct 05, 2007, at 00:45:17, Eric W. Biederman wrote:
>> > > Kyle Moffett <[email protected]> writes:
>> > >
>> > >> On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
>> > > Yes. Currently with containers we are taking that one step farther
>> > > as that solves a wider set of problems.
>> > So containers are exclusive subsets of "the system" while LSM should
>> > be about non-exclusive information restriction.
>>
>> Yes. Isolation is a much simpler problem than access control.
Yes. Simple isolation is a different and simpler problem that can be
solved with the LSM hooks today. I brought it up for the contrast in
what the LSM hooks can be useful for. Hopefully allowing the LSM
hooks to be perceived as something other then just hacks for selinux.
Using a security module for isolation is currently uninteresting
because it would preclude use of a security module like selinux or
smack, because we can have at most one security module at a time
loaded.
I have seen several other places where a custom LSM would have
been a good solution but because we don't allow composition solving
a little problem with the LSm is not interesting enough to allow
the code to be merged.
So I see the current structure of the LSM hooks as hindering
development.
>> > >
>> > > I think it is firmly established that selling SElinux to everyone
>> > > is politically untenable. However enhancing the LSM (even if it is
>> > > mostly selinux code movement down a layer) I think can be sold.
>>
>> That would be silly. Smack uses a significantly smaller set of hooks
>> than SELinux requires and still does interesting things. We went through
>> the "replace LSM with the SELinux interface" exercise a couple years
>> ago, I would hate to have to regurgitate all those discussions.
>
> I don't think Eric is proposing replacing LSM with the SELinux interface
> as it exists today, but rather making LSM more Netfilter-like and
> radically refactoring SELinux (and any other security module) to consist
> of a chain of smaller modules that are more general and reusable, and
> that can be composed and applied in interesting ways via an
> iptables-like interface. I'm not sure what that would look like
> exactly, but it seems reasonable to explore.
Exactly refactoring security modules into small simple reusable chunks
to allow reuse. It might look something like selinux chains or it
might not. Inherently it needs to expose what you can do at the
existing hook points, and it needs to allow usage by different modules
that are compiled in at the same time.
It is certainly the case that you would not need to use all of the
existing hooks to get something done.
> One of the things left unresolved with LSM is userland API, and it does
> involve more than just returning EPERM or EACCES to applications. You
> already have patched ls and sshd programs, and have acknowledged the
> need for more userland modifications to ultimately achieve your own
> goals. If LSM is going to succeed in the kernel, then ultimately you
> need some common API for userland so that you don't need separate
> versions of ls, ps, sshd, etc for Smack vs SELinux vs. whatever.
Likely. Until we have a generalized LSM interface with 1000 config
options like netfilter I don't expect we will have grounds to talk
or agree to a common user space interface. Although I could be
wrong.
Eric
Kyle Moffett wrote:
> On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
>> What we want from the LSM is the ability to say -EPERM when we can
>> clearly articulate that we want to disallow something.
>
> This sort of depends on perspective; typically with security
> infrastructure you actually want "... the ability to return success when
> we can clearly articulate that we want to *ALLOW* something". File
> permissions work this way; we don't have a list of forbidden users
> attached to each file, we have an owner, a group, and a mode
> representing positive permissions. With that said in certain high-risk
> environments you need something even stronger that cannot be changed by
> the "owner" of the file, if we don't entirely trust them,
>
Other than ACLs, of course, which do allow blacklisting individual users.
--
Bill Davidsen <[email protected]>
"We have more to fear from the bungling of the incompetent than from
the machinations of the wicked." - from Slashdot
Quoting Eric W. Biederman ([email protected]):
> Kyle Moffett <[email protected]> writes:
>
> > On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
> >> What we want from the LSM is the ability to say -EPERM when we can clearly
> >> articulate that we want to disallow something.
> >
> > This sort of depends on perspective; typically with security infrastructure you
> > actually want "... the ability to return success when we can clearly articulate
> > that we want to *ALLOW* something". File permissions work this way; we don't
> > have a list of forbidden users attached to each file, we have an owner, a
> > group, and a mode representing positive permissions. With that said in certain
> > high-
> > risk environments you need something even stronger that cannot be changed by the
> > "owner" of the file, if we don't entirely trust them,
>
> Yes. However last I looked at the LSM hooks we first do the normal unix
> permission checks. Then we run the hook. So it can only increase the
> number of times we say -EPERM.
>
> >> SElinux is not all encompassing or it is generally incomprehensible I don't
> >> know which. Or someone long ago would have said a better way to implement
> >> containers was with a selinux ruleset, here is a selinux ruleset that does
> >> that. Although it is completely possible to implement all of the isolation
> >> with the existing LSM hooks as Serge showed.
> >
> > The difference between SELinux and containers is that SELinux (and LSM as a
> > whole) returns -EPERM to operations outside the scope of the subject, whereas
> > containers return -ENOENT (because it's not even in the same namespace).
>
> Yes. However if you look at what the first implementations were. Especially
> something like linux-vserver. All they provided was isolation. So perhaps
> you would not see every process ps but they all had unique pid values.
>
> I'm pretty certain Serge at least prototyped a simplified version
> of that using the LSM hooks. Is there something I'm not remember in
> those hooks that allows hiding of information like processes?
Actually I had to introduce a new LSM hook to filter /proc pid listings.
> Yes. Currently with containers we are taking that one step farther as
> that solves a wider set of problems.
And I'm far happier with the pid namespaces :)
> >> We also have in the kernel another parallel security mechanism (for what is
> >> generally a different class of operations) that has been quite successful,
> >> and different groups get along quite well, and ordinary mortals can
> >> understand it. The linux firewalling code.
> >
> > Well, I wouldn't go so far as the "ordinary mortals can understand it" part;
> > it's still pretty high on the obtuse-o-meter.
>
> True. Probably a more accurate statement is:`unix command line power
> users can and do handle it after reading the docs. That's not quite
> ordinary mortals but it feels like it some days. It might all be
> perception...
>
> >> The linux firewalling codes has hooks all throughout the networking stack,
> >> just like the LSM has hooks all throughout the rest of linux kernel. There
> >> is a difference however. The linux firewalling code in addition to hooks has
> >> tables behind those hooks that it consults. There is generic code to walk
> >> those tables and consult with different kernel modules to decide if we should
> >> drop a packet. Each of those kernel modules provides a different capability
> >> that can be used to generate a firewall.
> >
> > This is almost *EXACTLY* what SELinux provides as an LSM module. The one
> > difference is that with SELinux some compromises and restrictions have been
> > made so that (theoretically) the resulting policy can be exhaustively analyzed
> > to *prove* what it allows and disallows. It may be that SELinux should be
> > split into 2 parts, one that provides the underlying table-matching and the
> > other that uses it to provide the provability guarantees. Here's a direct
> > comparison:
> >
> > netfilter:
> > (A) Each packet has src, dst, port, etc that can be matched
> > (B) Table of rules applied sequentially (MATCH => ACTION)
> > (C) Rules may alter the properties of packets as they are routed/
> > bridged/etc
> >
> > selinux:
> > (A) Each object has user, role, and type that can be matched
> > (B) Table of rules searched by object parameters (MATCH => allow/
> > auditallow/transition)
> > (C) Rules may alter the properties of objects through transition rules.
>
> Ok. There is something here.
>
> However in a generic setup, at least role would be an extended match
> criteria provided by the selinux module. It would not be a core
> attribute. It would need to depend on some extra functionality being
> compiled in.
>
> >> I'm not yet annoyed enough to go implement an iptables like interface to the
> >> LSM enhancing it with more generic mechanism to make the problem simpler, but
> >> I'm getting there. Perhaps next time I'm bored.
> >
> > I think a fair amount of what we need is already done in SELinux, and efforts
> > would be better spent in figuring out what seems too complicated in SELinux and
> > making it simpler. Probably a fair amount of that just means better tools.
>
> How about thinking of it another way.
>
> Perform the split up you talked about above and move the table
> matching into the LSM hooks.
>
> Use something like the iptables action and match to module mapping
> code so we can have multiple modules compiled in and useable at the
> same time with the LSM hooks.
>
> I think it is firmly established that selling SElinux to everyone is
> politically untenable. However enhancing the LSM (even if it is
> mostly selinux code movement down a layer) I think can be sold.
>
> If I could run Serge's isolation code and selinux rules at the same
> time that would be interesting.
But given that namespaces are making it upstream, what else is to be
gained from the bsdail module? What exactly are you looking for?
1. are you looking to cover all the corner cases - i.e. prevent killing
a process in another namespace through F_SETOWN or mqueue, etc?
2. are you looking for a potentially easier fix to the current absence
of isolation in the user namespace?
3. are you just generally looking to make lsm/selinux easier for
yourself to configure?
If 1, an selinux policy should cover you. So you can then skip to 3.
Or, alternatively, I do plan - as soon as my free time clears up a bit -
on demonstrating how to write some selinux policy to create a secure
container based on current -mm + your experimental network namespace
patches.
If 2, well, see 1. But for the long term solution, I don't think we
want that in an LSM. Rather we want to implement proper user namespace
enforcement in the kernel, then put 'policy' basically at the filesystem
layer and further in userspace. So maybe not exactly what I've outlined
before, but certainly similar. The filesystem can decide what user
namespace a file belongs to, whether based on cryptographic keys stored
with the file, or based on mount arguments, or something else. Users
can get access to those files using keys stored with their task_struct
if they are not in the right user namespace to otherwise access it.
Otherwise access to a file in another user namespace defaults to
the 3d mode bit, so you default to being 'other'. Further isolation
probably still belongs in selinux or another lsm.
If 3, then selinux policy modules may actually help you, else either
a new LSM (maybe like LIDS) or a userspace tool which is a front-end to
selinux policy, emulating the iptables rules formats, may be what you
want?
> My impression is that selinux is one monolithic blob that doesn't
> allow me to incrementally add matching or action features that I
> find interesting.
Actually with policy modules it gets much much better. I have in fact
been able to pretty easily write a short policy module to, say, create
an selinux user which ran as root and had full access to the system to
do system setup for automated testing. There is a learning curve in
having to look at existing modules for maybe a few days to get started,
but once you get started the policy modules do make it very easy to
add to current policy.
-serge
Quoting Casey Schaufler ([email protected]):
>
> --- Kyle Moffett <[email protected]> wrote:
>
> > On Oct 05, 2007, at 00:45:17, Eric W. Biederman wrote:
> > > Kyle Moffett <[email protected]> writes:
> > >
> > >> On Oct 04, 2007, at 21:44:02, Eric W. Biederman wrote:
> > >>> SElinux is not all encompassing or it is generally
> > >>> incomprehensible I don't know which. Or someone long ago would
> > >>> have said a better way to implement containers was with a
> > >>> selinux ruleset, here is a selinux ruleset that does that.
> > >>> Although it is completely possible to implement all of the
> > >>> isolation with the existing LSM hooks as Serge showed.
> > >>
> > >> The difference between SELinux and containers is that SELinux (and
> > >> LSM as a whole) returns -EPERM to operations outside the scope of
> > >> the subject, whereas containers return -ENOENT (because it's not
> > >> even in the same namespace).
> > >
> > > Yes. However if you look at what the first implementations were.
> > > Especially something like linux-vserver. All they provided was
> > > isolation. So perhaps you would not see every process ps but they
> > > all had unique pid values.
> > >
> > > I'm pretty certain Serge at least prototyped a simplified version
> > > of that using the LSM hooks. Is there something I'm not remember
> > > in those hooks that allows hiding of information like processes?
> > >
> > > Yes. Currently with containers we are taking that one step farther
> > > as that solves a wider set of problems.
> >
> > IMHO, containers have a subtly different purpose from LSM even though
> > both are about information hiding. Basically a container is
> > information hiding primarily for administrative reasons; either as a
> > convenience to help prevent errors or as a way of describing
> > administrative boundaries. For example, even in an environment where
> > all sysadmins are trusted employees, a few head-honcho sysadmins
> > would get root container access, and all others would get access to
> > specific containers as a way of preventing "oops" errors. Basically
> > a container is about "full access inside this box and no access
> > outside".
> >
> > By contrast, LSM is more strictly about providing *limited* access to
> > resources. For an accounting business all client records would
> > grouped and associated together, however those which have passed this
> > year's review are read-only except by specific staff and others may
> > have information restricted to some subset of the employees.
> >
> > So containers are exclusive subsets of "the system" while LSM should
> > be about non-exclusive information restriction.
>
> Yes. Isolation is a much simpler problem than access control.
>
> > >>> We also have in the kernel another parallel security mechanism
> > >>> (for what is generally a different class of operations) that has
> > >>> been quite successful, and different groups get along quite
> > >>> well, and ordinary mortals can understand it. The linux
> > >>> firewalling code.
> > >>
> > >> Well, I wouldn't go so far as the "ordinary mortals can understand
> > >> it" part; it's still pretty high on the obtuse-o-meter.
> > >
> > > True. Probably a more accurate statement is:`unix command line
> > > power users can and do handle it after reading the docs. That's
> > > not quite ordinary mortals but it feels like it some days. It
> > > might all be perception...
> >
> > I have seen more *wrong* iptables firewalls than I've seen correct
> > ones. Securing TCP/IP traffic properly requires either a lot of
> > training/experience or a good out-of-the-box system like Shorewall
> > which structures the necessary restrictions for you based on an
> > abstract description of the desired functionality. For instance what
> > percentage of admins do you think could correctly set up their
> > netfilter firewalls to log christmas-tree packets, smurfs, etc
> > without the help of some external tool? Hell, I don't trust myself
> > to reliably do it without a lot of reading of docs and testing, and
> > I've been doing netfilter firewalls for a while.
> >
> > The bottom line is that with iptables it is *CRITICAL* to have a good
> > set of interface tools to take the users' "My system is set up
> > like..." description in some form and turn it into the necessary set
> > of efficient security rules. The *exact* same issue applies to
> > SELinux, with 2 major additional problems:
> >
> > 1) Half the tools are still somewhat beta-ish and under heavy
> > development. Furthermore the semi-official reference policy is
> > nowhere near comprehensive and pretty ugly to read (go back to the
> > point about the tools being beta-ish).
> >
> > 2) If you break your system description or translation tools then
> > instead of just your network dying your entire *system* dies.
> >
> >
> > >>> The linux firewalling codes has hooks all throughout the
> > >>> networking stack, just like the LSM has hooks all throughout the
> > >>> rest of linux kernel. There is a difference however. The linux
> > >>> firewalling code in addition to hooks has tables behind those
> > >>> hooks that it consults. There is generic code to walk those
> > >>> tables and consult with different kernel modules to decide if we
> > >>> should drop a packet. Each of those kernel modules provides a
> > >>> different capability that can be used to generate a firewall.
> > >>
> > >> This is almost *EXACTLY* what SELinux provides as an LSM module.
> > >> The one difference is that with SELinux some compromises and
> > >> restrictions have been made so that (theoretically) the resulting
> > >> policy can be exhaustively analyzed to *prove* what it allows and
> > >> disallows. It may be that SELinux should be split into 2 parts,
> > >> one that provides the underlying table-matching and the other
> > >> that uses it to provide the provability guarantees. Here's a
> > >> direct comparison:
> > >>
> > >> netfilter:
> > >> (A) Each packet has src, dst, port, etc that can be matched
> > >> (B) Table of rules applied sequentially (MATCH => ACTION)
> > >> (C) Rules may alter the properties of packets as they are routed/
> > >> bridged/etc
> > >>
> > >> selinux:
> > >> (A) Each object has user, role, and type that can be matched
> > >> (B) Table of rules searched by object parameters (MATCH => allow/
> > >> auditallow/transition)
> > >> (C) Rules may alter the properties of objects through transition
> > >> rules.
> > >
> > > Ok. There is something here.
> > >
> > > However in a generic setup, at least role would be an extended
> > > match criteria provided by the selinux module. It would not be a
> > > core attribute. It would need to depend on some extra
> > > functionality being compiled in.
> >
> > Now see I think *THAT* is where Casey should be going with his SMACK
> > code. Don't add another LSM, start looking at SELinux and figuring
> > out what parts he does not need and how they can be parameterized out
> > at build time for smaller systems.
>
> Good suggestion. In fact, that is exactly how I approached my
> first two attempts at the problem. What you get if you take that
> route is an imposing infrastructure that has virually nothing
> to do and that adds no value to the solution. Programming to the
> LSM interface, on the other hand, allowed me to drastically reduce
> the size and complexity of the implementation.
(tongue-in-cheek)
No no, everyone knows you don't build simpler things on top of more
complicated ones, you go the other way around. So what he was
suggesting was that selinux be re-written on top of smack.
:)
-serge
"Serge E. Hallyn" <[email protected]> writes:
> Quoting Eric W. Biederman ([email protected]):
>>
>> Perform the split up you talked about above and move the table
>> matching into the LSM hooks.
>>
>> Use something like the iptables action and match to module mapping
>> code so we can have multiple modules compiled in and useable at the
>> same time with the LSM hooks.
>>
>> I think it is firmly established that selling SElinux to everyone is
>> politically untenable. However enhancing the LSM (even if it is
>> mostly selinux code movement down a layer) I think can be sold.
>>
>> If I could run Serge's isolation code and selinux rules at the same
>> time that would be interesting.
>
> But given that namespaces are making it upstream, what else is to be
> gained from the bsdail module? What exactly are you looking for?
Good question. I keep tripping over the LSM hooks, and I have the
distinct impression that part of the current contention and lack of
agreement is simply the way things are current factored. So I'm
putting for a constructive suggestion that has the possibility of
going somewhere.
> 1. are you looking to cover all the corner cases - i.e. prevent killing
> a process in another namespace through F_SETOWN or mqueue, etc?
I'm looking towards this yes. There are times when we deliberately
allow mixing of things by the definition of what namespaces are and
there are some use cases where people don't want this.
> 2. are you looking for a potentially easier fix to the current absence
> of isolation in the user namespace?
No. I'm not even worrying about the user namespace until it resembles
complete. Currently I just view it as a stub because as is, the
security namespace is pretty much useless for any case I think about.
We still have way to many cases where the kernel treats different
names as the same name.
> 3. are you just generally looking to make lsm/selinux easier for
> yourself to configure?
Well. I'm trying to make the LSM more useful to hack on and configure,
and much less contentions for ordinary people to use.
There is one issue with sockets that has come up where there are
people who really want to filter things at connect and bind time.
The LSM is so inflexible the only sane suggestion at the time was
to duplicate the LSM hooks and add an new iptable style table
for making that decision.
Also I'm thinking towards what do we have to do isolate the security
module stuff in the context of a namespace. So that a person in
a container can setup their own rules that further restrict the
system.
So far I'm not ready to do anything yet but I'm keeping a weather eye
on the situation so I have a clue what I'm go.
> If 1, an selinux policy should cover you. So you can then skip to 3.
> Or, alternatively, I do plan - as soon as my free time clears up a bit -
> on demonstrating how to write some selinux policy to create a secure
> container based on current -mm + your experimental network namespace
> patches.
Thanks that sounds interesting.
> If 3, then selinux policy modules may actually help you, else either
> a new LSM (maybe like LIDS) or a userspace tool which is a front-end to
> selinux policy, emulating the iptables rules formats, may be what you
> want?
I don't want to have to choose my LSM at compile time. I want to
add support into the kernel at compile time and be able to configure
it before I go multi-user. I know this kind of architecture is
achievable because iptables allows it.
When I conceive as the security modules as just a firewall between
applications on my own box I think, oh yeah this is no big deal,
I might want to limit something that way some time. These are just
some additional rules on when to return -EPERM. So I ask myself why
is this situation much less flexible and much harder to use then our
network firewall code?
>> My impression is that selinux is one monolithic blob that doesn't
>> allow me to incrementally add matching or action features that I
>> find interesting.
>
> Actually with policy modules it gets much much better. I have in fact
> been able to pretty easily write a short policy module to, say, create
> an selinux user which ran as root and had full access to the system to
> do system setup for automated testing. There is a learning curve in
> having to look at existing modules for maybe a few days to get started,
> but once you get started the policy modules do make it very easy to
> add to current policy.
Ok. Interesting. Are these kernel modules?
Still while I get the general impression that selinux seems to be
very close to a generic solution, and that selinux more or less has
the architecture we might want. I don't get the impression that
selinux does this at a level that is open to other people doing
interesting things.
So I still ask the question can we move this functionality down to
the LSM in a way that will solve the composition problem between
multiple security modules?
It really seems to me that the LSM as currently structured creates
a large barrier to entry for people who have just this little thing
they want to do that is not possible with any existing security
module.
Eric
--- "Serge E. Hallyn" <[email protected]> wrote:
> Quoting Casey Schaufler ([email protected]):
> > ...
> > Good suggestion. In fact, that is exactly how I approached my
> > first two attempts at the problem. What you get if you take that
> > route is an imposing infrastructure that has virually nothing
> > to do and that adds no value to the solution. Programming to the
> > LSM interface, on the other hand, allowed me to drastically reduce
> > the size and complexity of the implementation.
>
> (tongue-in-cheek)
>
> No no, everyone knows you don't build simpler things on top of more
> complicated ones, you go the other way around. So what he was
> suggesting was that selinux be re-written on top of smack.
>
> :)
I'm not sure how seriously anyone ought to take what I'm about to
outline. Please feel free to treat it with as much or as little
reverence as you choose.
How to implement SELinux starting from Smack.
You'll need to break up the current rwxa accesses into a set
that matches the current SELinux set. Assign each a letter and
a "MAY_ACTION" #define.
You'll need a mapping for domain transitions, something like:
subject-label program-label new-subject-label
This will require bprm hooks that aren't there now.
Additional hooks will need to be filled out as Smack does not
add access control to things that aren't objects or actions that
aren't accesses. Treat these as if they are accesses to objects
and there shouldn't be too much trouble.
Do something about the linear search for subject/object label pairs.
With the larger label set searching will become an issue.
Audit integration, too. The networking code will require some work
for ipsec. The interfaces are pretty clean, Smack isn't using it
because the CIPSO interface is simpler, not because there's any
real problem with it.
I wouldn't expect the whole thing to be more than a couple week's
work for someone who really wanted to do it.
Casey Schaufler
[email protected]
--- "Eric W. Biederman" <[email protected]> wrote:
> Likely. Until we have a generalized LSM interface with 1000 config
> options like netfilter I don't expect we will have grounds to talk
> or agree to a common user space interface. Although I could be
> wrong.
Gulp. I know that many of you are granularity advocates, but I
have to say that security derived by tweeking 1000 knobs so that
they are all just right seems a little far fetched to me. I see
it as poopooing the 3rd and most important part of the reference
monitor concept, "small enough to analyze". Sure, you can analyse
the 1000 individual checks, but you'll never be able to describe
the system behavior as a whole.
Casey Schaufler
[email protected]
Quoting Eric W. Biederman ([email protected]):
> "Serge E. Hallyn" <[email protected]> writes:
> Also I'm thinking towards what do we have to do isolate the security
> module stuff in the context of a namespace. So that a person in
> a container can setup their own rules that further restrict the
> system.
In the selinux example I plan to do set up soon, that will be done
using the '.' namespace separator.
Every object/subject in vserver1 will have a type 'vserver1.whatever'.
'vserver1.root_t', 'vserver1.etc_t', etc.
I don't know how far the policy tools have gotten, but they are
*supposed* to implement constraints at policy compile time such that
every type which is a child of 'vserver1' would have no more access than
what is granted to type 'vserver1'. So this provides a pretty nice
conceptual way to set up security for a vserver.
Then using the userspace policy server and metapolicy (this would be a
step or two beyond my first example) the policy could define rules about
what sort of policy could be added by a process of type
'vserver1.root_t'. So we can allow the container admin to introduce
policy changes affecting only his own container, and subject to all
constraints placed by the host admin on vserver1.
> So far I'm not ready to do anything yet but I'm keeping a weather eye
> on the situation so I have a clue what I'm go.
>
> > If 1, an selinux policy should cover you. So you can then skip to 3.
> > Or, alternatively, I do plan - as soon as my free time clears up a bit -
> > on demonstrating how to write some selinux policy to create a secure
> > container based on current -mm + your experimental network namespace
> > patches.
>
> Thanks that sounds interesting.
>
> > If 3, then selinux policy modules may actually help you, else either
> > a new LSM (maybe like LIDS) or a userspace tool which is a front-end to
> > selinux policy, emulating the iptables rules formats, may be what you
> > want?
>
> I don't want to have to choose my LSM at compile time. I want to
> add support into the kernel at compile time and be able to configure
> it before I go multi-user. I know this kind of architecture is
> achievable because iptables allows it.
>
> When I conceive as the security modules as just a firewall between
> applications on my own box I think, oh yeah this is no big deal,
> I might want to limit something that way some time. These are just
> some additional rules on when to return -EPERM. So I ask myself why
> is this situation much less flexible and much harder to use then our
> network firewall code?
It actually used to be far more flexible than it is now. The consensus
appears to be that it's just too hard - at times impossible - to
properly label every object or subject at some point after they've all
been created (processes created, inodes read from disk, etc). Two
examples:
1. you've got pid 777. How was it created? Can you trust it's
history? In my DTE module I solved this by keeping track of the
*full* invocation history until a policy was loaded. I think
tomoyo may do something similar. But it's really not
sufficient, especially since you don't even want a LSM loaded
at all. So you can't reduce it to 'boot_t executd init_t
executed login_t executed shell_t', you have to keep track of
every inode executed
2. how do you reliably re-evaluate, for some file, what label
to assign to it? Do you guess at a pathname? Do you trust that
the inodes have been pre-labeled for every LSM, so when you load
the LSM you can grab the xattrs?
So it's a valid question - do we address these sorts of concerns in
order to add flexibility, or do we keep things as simple as possible
and say that it's up to the distro, for instance, or a site local
security administrator, to define policy, so that flexibility really
is of very limited use?
> >> My impression is that selinux is one monolithic blob that doesn't
> >> allow me to incrementally add matching or action features that I
> >> find interesting.
> >
> > Actually with policy modules it gets much much better. I have in fact
> > been able to pretty easily write a short policy module to, say, create
> > an selinux user which ran as root and had full access to the system to
> > do system setup for automated testing. There is a learning curve in
> > having to look at existing modules for maybe a few days to get started,
> > but once you get started the policy modules do make it very easy to
> > add to current policy.
>
> Ok. Interesting. Are these kernel modules?
Policy modules, loaded through selinuxfs at any time using 'semodule'.
> Still while I get the general impression that selinux seems to be
> very close to a generic solution, and that selinux more or less has
> the architecture we might want. I don't get the impression that
> selinux does this at a level that is open to other people doing
> interesting things.
>
> So I still ask the question can we move this functionality down to
> the LSM in a way that will solve the composition problem between
> multiple security modules?
I've tried :) At a less semantic and more purely technical level, using
the stacker module. After a few years it was finally decided (at
ksummit 2006) that it simply wasn't useful.
Now perhaps the problem was that I didn't address semantic issues.
But it does sound to me like what you want is a particular flexible LSM.
Be it LIDS or SELinux, or something new.
> It really seems to me that the LSM as currently structured creates
> a large barrier to entry for people who have just this little thing
> they want to do that is not possible with any existing security
> module.
Yes and it's been made increasingly so far particularly because of the
perceived potential for 'abuse'. So to be curt, allowing people like
you describe to do something small and interesting is deemed far less
important than making sure that the small thing they want to do fits
within the LSM mandate and is not a non-upstream module.
So that is the concern you would need to address before any other.
Still, I do think that selinux policy modules may do just what you want.
The main obstacle appears to be that the 'base' policy is so huge that
it's tough to get started to do something small.
You also might want to check out LIDS, as its rules are set up pretty
much the way you seem to want.
-serge
Casey Schaufler <[email protected]> writes:
> --- "Eric W. Biederman" <[email protected]> wrote:
>
>
>> Likely. Until we have a generalized LSM interface with 1000 config
>> options like netfilter I don't expect we will have grounds to talk
>> or agree to a common user space interface. Although I could be
>> wrong.
>
> Gulp. I know that many of you are granularity advocates, but I
> have to say that security derived by tweeking 1000 knobs so that
> they are all just right seems a little far fetched to me. I see
> it as poopooing the 3rd and most important part of the reference
> monitor concept, "small enough to analyze". Sure, you can analyse
> the 1000 individual checks, but you'll never be able to describe
> the system behavior as a whole.
Agreed. I wasn't thinking 1000 individual checks but 1000 different
capabilities, could be either checks or actions, basically fundamental
different capabilities. Things like CIPSO, or the ability to store a
security label on a file. I would not expect most security policies
to use most of them. Neither do I expect Orange book security to
necessarily be what people want to achieve with the LSM. But I
haven't looked at it enough detail to know how things should be
factored, in this case I was simply extrapolating from the iptables
experience where we do have a very large number of options.
The real point being is that I would be surprised if we could come
to an agreement of a common user space API when we can't agree on how
to compile all of the security modules into the kernel and have them
play nice with each other.
Assuming we can achieve security modules playing nice with each other
using a mechanism similar to iptables, then what needs to be evaluated
is the specific table configuration we are using on the system, not
the full general set of possibilities. Further I expect that for the
truly security paranoid we want the option to disable further table
changes after the tables have been configured.
On another side personally I don't see where the idea comes from that
you can describe system behavior as a whole without analyzing the
entire kernel. Has there been work on a sparse like tool that I'm
not aware of to ensure the we always perform the appropriate security
checks on the user/kernel interface boundary?
Eric
Quoting Eric W. Biederman ([email protected]):
> Casey Schaufler <[email protected]> writes:
>
> > --- "Eric W. Biederman" <[email protected]> wrote:
> >
> >
> >> Likely. Until we have a generalized LSM interface with 1000 config
> >> options like netfilter I don't expect we will have grounds to talk
> >> or agree to a common user space interface. Although I could be
> >> wrong.
> >
> > Gulp. I know that many of you are granularity advocates, but I
> > have to say that security derived by tweeking 1000 knobs so that
> > they are all just right seems a little far fetched to me. I see
> > it as poopooing the 3rd and most important part of the reference
> > monitor concept, "small enough to analyze". Sure, you can analyse
> > the 1000 individual checks, but you'll never be able to describe
> > the system behavior as a whole.
>
> Agreed. I wasn't thinking 1000 individual checks but 1000 different
> capabilities, could be either checks or actions, basically fundamental
> different capabilities. Things like CIPSO, or the ability to store a
> security label on a file. I would not expect most security policies
> to use most of them. Neither do I expect Orange book security to
> necessarily be what people want to achieve with the LSM. But I
> haven't looked at it enough detail to know how things should be
> factored, in this case I was simply extrapolating from the iptables
> experience where we do have a very large number of options.
>
> The real point being is that I would be surprised if we could come
> to an agreement of a common user space API when we can't agree on how
> to compile all of the security modules into the kernel and have them
> play nice with each other.
>
> Assuming we can achieve security modules playing nice with each other
> using a mechanism similar to iptables, then what needs to be evaluated
> is the specific table configuration we are using on the system, not
> the full general set of possibilities. Further I expect that for the
> truly security paranoid we want the option to disable further table
> changes after the tables have been configured.
>
> On another side personally I don't see where the idea comes from that
> you can describe system behavior as a whole without analyzing the
> entire kernel. Has there been work on a sparse like tool that I'm
> not aware of to ensure the we always perform the appropriate security
> checks on the user/kernel interface boundary?
Yup, see the top of http://www.research.ibm.com/vali/
Pretty cool work that really should be continued.
-serge
"Serge E. Hallyn" <[email protected]> writes:
> Quoting Eric W. Biederman ([email protected]):
>
>
> So it's a valid question - do we address these sorts of concerns in
> order to add flexibility, or do we keep things as simple as possible
> and say that it's up to the distro, for instance, or a site local
> security administrator, to define policy, so that flexibility really
> is of very limited use?
I want what we have for the rest of the kernel. The ability to build
one kernel binary that can do everything and that is configured at
boot time or run time.
My perspective is that if we are going to have an in-kernel labeling
operation running that may be an unconditional function that can
only be enabled or disabled as the system runs.
I'm not after the kind of flexibility that allows us to do things late
in the game, at least not inherently. I'm after things like being
able to have the checks separated from the labeling, roughly where
are today with iptables.
I'm really after refactoring the problem so that we don't get these
winner take all fights for use of the LSM. If we can break things
up into small enough factors so that a solution does not all come
from one project then I think we have a chance of getting multiple
security module authors to work together. Right now we don't seem
to have that kind of cross pollination when using the LSM.
But frankly even the ability to compile in all of the kernel security
modules at compile time and be able to switch between them with a
kernel command line option would be a start.
>> Still while I get the general impression that selinux seems to be
>> very close to a generic solution, and that selinux more or less has
>> the architecture we might want. I don't get the impression that
>> selinux does this at a level that is open to other people doing
>> interesting things.
>>
>> So I still ask the question can we move this functionality down to
>> the LSM in a way that will solve the composition problem between
>> multiple security modules?
>
> I've tried :) At a less semantic and more purely technical level, using
> the stacker module. After a few years it was finally decided (at
> ksummit 2006) that it simply wasn't useful.
>
> Now perhaps the problem was that I didn't address semantic issues.
> But it does sound to me like what you want is a particular flexible LSM.
> Be it LIDS or SELinux, or something new.
My perspective of the stacker module was that it's problem was it
did not change the problem into a more useable form. That it didn't
dig deep enough to have useful consequences. I don't think the goal
was bad.
In one sense what I'm proposing is putting the stacker functionality
into the LSM. Allowing me to choose after I boot my kernel which of
the compiled in security modules I want to run, and ideally for each
logical kind of security test which order I call the security modules
in if I have more then one.
>> It really seems to me that the LSM as currently structured creates
>> a large barrier to entry for people who have just this little thing
>> they want to do that is not possible with any existing security
>> module.
>
> Yes and it's been made increasingly so far particularly because of the
> perceived potential for 'abuse'. So to be curt, allowing people like
> you describe to do something small and interesting is deemed far less
> important than making sure that the small thing they want to do fits
> within the LSM mandate and is not a non-upstream module.
>
> So that is the concern you would need to address before any other.
Communication error. I can't do small pieces that are useful in an
upstreamable fashion. That is the problem I see. I don't care about
out of kernel code. If we have to compile all of the code into the
kernel and have no exports to modules that is fine with me.
My question is how do we get more interesting functionality into the
kernel. How do we get the generic kernel support simple and easy to
hack so it can be used by people who have unique unanticipated
problems.
> Still, I do think that selinux policy modules may do just what you want.
> The main obstacle appears to be that the 'base' policy is so huge that
> it's tough to get started to do something small.
Quite likely, or at least I expect that they are close.
I just think we should solve this at the LSM layer if it is at all
possible not in selinux.
> You also might want to check out LIDS, as its rules are set up pretty
> much the way you seem to want.
What is the kernel compile option for that?
Or is LIDS yet another security module that hasn't made it upstream
because the way the problem is currently factored it is nearly
impossible to your code upstream?
Eric
"Serge E. Hallyn" <[email protected]> writes:
> Quoting Eric W. Biederman ([email protected]):
>> It really seems to me that the LSM as currently structured creates
>> a large barrier to entry for people who have just this little thing
>> they want to do that is not possible with any existing security
>> module.
>
> Yes and it's been made increasingly so far particularly because of the
> perceived potential for 'abuse'. So to be curt, allowing people like
> you describe to do something small and interesting is deemed far less
> important than making sure that the small thing they want to do fits
> within the LSM mandate and is not a non-upstream module.
>
> So that is the concern you would need to address before any other.
>
> Still, I do think that selinux policy modules may do just what you want.
> The main obstacle appears to be that the 'base' policy is so huge that
> it's tough to get started to do something small.
>
> You also might want to check out LIDS, as its rules are set up pretty
> much the way you seem to want.
To be very clear. Enhancing the LSM is of interest to me as it looks
like that is a way to get people working and playing well together,
and that ultimately to be able to run a full distro in a container
I'm going to need this ability.
Examples of better ways to do this in selinux, LIDS, or SMACK are only
interesting as far as they suggest how to enhance the LSM.
I honestly think enhancing the LSM would actually reduce it's ability
to be abused, because nothing would directly own the hook.
My very practical question: How do I run selinux in one container,
and SMACK in another?
Eric
--- "Eric W. Biederman" <[email protected]> wrote:
> It really seems to me that the LSM as currently structured creates
> a large barrier to entry for people who have just this little thing
> they want to do that is not possible with any existing security
> module.
I honestly think that the barrier has been more political
in nature than technical. I don't know how long you've been
watching, but no attempt to get an LSM upstream has escaped
exagerated cricism from certain factions. Only someone who wants
to get cut to metaphorical ribbons would submit a little LSM.
Maybe that will get better now. I sure hope so.
Casey Schaufler
[email protected]
--- "Eric W. Biederman" <[email protected]> wrote:
> My very practical question: How do I run selinux in one container,
> and SMACK in another?
How would you run PREEMPT_RT in one container, and PREEMPT_DESKTOP
in another? How would you run SMP in one and UP in the other?
One aspect that SELinux and Smack share is that they only really
provide security if all processes involved are under their control,
just like the preemption behavior.
This is not necessarily true of all possible LSMs. In that case it may
be practicle to have different behavior for different containers.
Casey Schaufler
[email protected]
Casey Schaufler <[email protected]> writes:
> --- "Eric W. Biederman" <[email protected]> wrote:
>
>> It really seems to me that the LSM as currently structured creates
>> a large barrier to entry for people who have just this little thing
>> they want to do that is not possible with any existing security
>> module.
>
> I honestly think that the barrier has been more political
> in nature than technical. I don't know how long you've been
> watching, but no attempt to get an LSM upstream has escaped
> exagerated cricism from certain factions. Only someone who wants
> to get cut to metaphorical ribbons would submit a little LSM.
> Maybe that will get better now. I sure hope so.
Yes. Me to. I certainly agree about the political part.
My only hope was to suggest something that my reduce what there is to
get political about.
Eric
Casey Schaufler <[email protected]> writes:
> --- "Eric W. Biederman" <[email protected]> wrote:
>
>
>> My very practical question: How do I run selinux in one container,
>> and SMACK in another?
>
> How would you run PREEMPT_RT in one container, and PREEMPT_DESKTOP
> in another?
Well the style of kernel preemption is generally an implementation
detail that is not visible to user space.
> How would you run SMP in one and UP in the other?
Bind all of the UP processes to a single cpu.
> One aspect that SELinux and Smack share is that they only really
> provide security if all processes involved are under their control,
> just like the preemption behavior.
Right. But in a container that look like a full system arguably this
is doable. There are a few additional details that would be needed
to ensure containers are isolated from each other that would be
needed to ensure this is effective but those are fairly minor.
> This is not necessarily true of all possible LSMs. In that case it may
> be practicle to have different behavior for different containers.
When we get to the point where this is a real concern I believe the
isolation will be sufficient that this it is a valid question to
ask.
If there is nothing visible to user space I don't care. But security
modules are fundamentally about changing when -EPERM happens so are
very visible to user space.
Eric
--- "Eric W. Biederman" <[email protected]> wrote:
> Casey Schaufler <[email protected]> writes:
>
> > --- "Eric W. Biederman" <[email protected]> wrote:
> >
> >
> >> Likely. Until we have a generalized LSM interface with 1000 config
> >> options like netfilter I don't expect we will have grounds to talk
> >> or agree to a common user space interface. Although I could be
> >> wrong.
> >
> > Gulp. I know that many of you are granularity advocates, but I
> > have to say that security derived by tweeking 1000 knobs so that
> > they are all just right seems a little far fetched to me. I see
> > it as poopooing the 3rd and most important part of the reference
> > monitor concept, "small enough to analyze". Sure, you can analyse
> > the 1000 individual checks, but you'll never be able to describe
> > the system behavior as a whole.
>
> Agreed. I wasn't thinking 1000 individual checks but 1000 different
> capabilities, could be either checks or actions, basically fundamental
> different capabilities. Things like CIPSO, or the ability to store a
> security label on a file. I would not expect most security policies
> to use most of them. Neither do I expect Orange book security to
> necessarily be what people want to achieve with the LSM. But I
> haven't looked at it enough detail to know how things should be
> factored, in this case I was simply extrapolating from the iptables
> experience where we do have a very large number of options.
You start getting into some pretty serious mindset battles on
this particular road. For starters, the "hooks" have to be
authoritative if you want them properly switchable, and I'm not
going to show you the scars I got the last time I proposed
authoritative hooks. Next you'll have to deal with defining what is
security behavior and what isn't. You wouldn't believe the debates
over the security implications, or lack thereof, of disk quotas.
Unless you're willing to take the approach that every conditional
in the kernel is a potential security checkpoint you are going to
miss someone's requirement and if you're willing to propose that,
well, let's just say that Linus was right about security people.
> The real point being is that I would be surprised if we could come
> to an agreement of a common user space API when we can't agree on how
> to compile all of the security modules into the kernel and have them
> play nice with each other.
The API issue cannot be solved if LSMs are going to implement
different behaviors. A reasonable subset can be addressed using
the POSIX P1003.1e/2c MAC definition plus the TSIG APIs. It is
unfortunate that SELinux has gone in a completely different
direction.
> Assuming we can achieve security modules playing nice with each other
> using a mechanism similar to iptables, then what needs to be evaluated
> is the specific table configuration we are using on the system, not
> the full general set of possibilities. Further I expect that for the
> truly security paranoid we want the option to disable further table
> changes after the tables have been configured.
A specific table configuration sounds an awful lot like a
specific SELinux Policy. Either way, your configuration is
going to be large and may not implement anything rational.
> On another side personally I don't see where the idea comes from that
> you can describe system behavior as a whole without analyzing the
> entire kernel. Has there been work on a sparse like tool that I'm
> not aware of to ensure the we always perform the appropriate security
> checks on the user/kernel interface boundary?
In addition to tools, there's the labor and money intensive Common
Criteria Evaluation Process.
Casey Schaufler
[email protected]
> My very practical question: How do I run selinux in one container,
> and SMACK in another?
In the LSM model you don't because you could have the same container
objects visible in different contains at the same time and subject to
different LSMs. What does it mean to pass an SELinux protected object
over an AppArmour protected unix domain socket into a SMACK protected
container ?
If you want consistency then you probably need to put the container id
into the LSM calls and provide the ability in one system to do container
specific checks. Right now I suspect the way to do it is to complete the
work to convert SMACK rulesets into SELinux rulesets with tools.
Really its the same problem as "I'd like to use different file permission
systems on different process identifiers" and it would be very hard to
get right simply because objects can pass between two different security
models.
Pyramid tried to do the "simple" case of BSD and System 5 on the same box
and got caught out even with that because of the different rules on stuff
like chgrp..
Eric W. Biederman wrote:
> My very practical question: How do I run selinux in one container,
> and SMACK in another?
>
In AppArmor, we plan to 'containerize' (not sure what to call it) policy
so that you can have an AppArmor policy per container. This is not
currently the case, it is just the direction we want to go. We think it
would be very useful for virtual hosts to be able to have their own
AppArmor policy, independent of what other hosts are doing.
The major step towards this goal so far is that AppArmor rules are now
canonicalized to the name space.
However, I have never considered the idea of separate LSM modules per
container. The idea doesn't really make sense to me. It is kind of like
asking for private device drivers, or even a private kernel, per name
space. If that's what you want, use virtualization like KVM, Xen, or VMware.
Crispin
--
Crispin Cowan, Ph.D. http://crispincowan.com/~crispin/
Itanium. Vista. GPLv3. Complexity at work
Serge E. Hallyn wrote:
> (tongue-in-cheek)
>
> No no, everyone knows you don't build simpler things on top of more
> complicated ones, you go the other way around. So what he was
> suggesting was that selinux be re-written on top of smack.
>
Having gone from proposing a simpler and easier to use security system
as an alternative to SELinux, you now propose to change the one working
security system we have. And yes, it's hard to use, but it works. Let's
keep this a patch, people who want adventure can have one, and people
who have gotten Linux accepted "if SELinux is enabled" will avoid one.
--
bill davidsen <[email protected]>
CTO TMR Associates, Inc
Doing interesting things with small computers since 1979
On Mon, 2007-10-08 at 10:31 -0700, Casey Schaufler wrote:
> --- "Serge E. Hallyn" <[email protected]> wrote:
>
> > Quoting Casey Schaufler ([email protected]):
> > > ...
> > > Good suggestion. In fact, that is exactly how I approached my
> > > first two attempts at the problem. What you get if you take that
> > > route is an imposing infrastructure that has virually nothing
> > > to do and that adds no value to the solution. Programming to the
> > > LSM interface, on the other hand, allowed me to drastically reduce
> > > the size and complexity of the implementation.
> >
> > (tongue-in-cheek)
> >
> > No no, everyone knows you don't build simpler things on top of more
> > complicated ones, you go the other way around. So what he was
> > suggesting was that selinux be re-written on top of smack.
> >
> > :)
>
> I'm not sure how seriously anyone ought to take what I'm about to
> outline. Please feel free to treat it with as much or as little
> reverence as you choose.
>
> How to implement SELinux starting from Smack.
>
> You'll need to break up the current rwxa accesses into a set
> that matches the current SELinux set. Assign each a letter and
> a "MAY_ACTION" #define.
>
> You'll need a mapping for domain transitions, something like:
>
> subject-label program-label new-subject-label
>
> This will require bprm hooks that aren't there now.
>
> Additional hooks will need to be filled out as Smack does not
> add access control to things that aren't objects or actions that
> aren't accesses. Treat these as if they are accesses to objects
> and there shouldn't be too much trouble.
>
> Do something about the linear search for subject/object label pairs.
> With the larger label set searching will become an issue.
>
> Audit integration, too. The networking code will require some work
> for ipsec. The interfaces are pretty clean, Smack isn't using it
> because the CIPSO interface is simpler, not because there's any
> real problem with it.
>
> I wouldn't expect the whole thing to be more than a couple week's
> work for someone who really wanted to do it.
Note that Serge said "SELinux re-written on top of Smack", not "rewrite
Smack to be more like SELinux". I don't believe the former is even
possible, given that Smack is strictly less expressive and granular by
design. Rewriting Smack to be more like SELinux should be possible, but
seems like more work than emulating Smack on SELinux via policy, and to
what end?
--
Stephen Smalley
National Security Agency
--- Stephen Smalley <[email protected]> wrote:
> On Mon, 2007-10-08 at 10:31 -0700, Casey Schaufler wrote:
> > ...
> > I wouldn't expect the whole thing to be more than a couple week's
> > work for someone who really wanted to do it.
>
> Note that Serge said "SELinux re-written on top of Smack", not "rewrite
> Smack to be more like SELinux".
Sorry, the subtlety of the difference seems insignificant to me.
> I don't believe the former is even
> possible, given that Smack is strictly less expressive and granular by
> design. Rewriting Smack to be more like SELinux should be possible,
As I outlined, it wouldn't be that hard to rewack SELinux from Smack.
> but seems like more work than emulating Smack on SELinux via policy,
Y'all keep saying that, but since noone has actually done that
SELinux policy, or anything like it, I maintain that it's not as
easy as you are inclined to claim. It is certainly not the "I'll
whip it up this weekend" sort of task that some have suggested.
> and to what end?
Well, there is that. I personally think that one implementation of
SELinux is plenty.
On the other hand, I think that if the concept of a single security
architecture has value the advocates of that position ought to be
looking at SELinux on/of Smack just as carefully as they look at
Smack on/of SELinux. If they are not, I suggest that the Single
Security Architecture argument is a sophistic device rather than
a legitimate issue of technology and should thus be ignored.
Casey Schaufler
[email protected]
Alan Cox <[email protected]> writes:
>> My very practical question: How do I run selinux in one container,
>> and SMACK in another?
>
> In the LSM model you don't because you could have the same container
> objects visible in different contains at the same time and subject to
> different LSMs. What does it mean to pass an SELinux protected object
> over an AppArmour protected unix domain socket into a SMACK protected
> container ?
You raise a good point. My intuitive definition would go something like
this. In the initial LSM space we would have whatever is the primary
LSM and it would always be invoked about everything. However it
would view a single container (no matter what user in that container)
as having a single set of permissions. Then the LSM in the container
be asked to further validate accesses, but it would distinguish
between users in the container.
At this point it looks like if I am going to be effective at doing
anything I am going to need to step back watch SMACK get merged and
then really look at what the LSM modules are implementing. Then
I can refactor the whole mess and move additional functionality into
the LSM to help me achieve other things.
> Really its the same problem as "I'd like to use different file permission
> systems on different process identifiers" and it would be very hard to
> get right simply because objects can pass between two different security
> models.
Yep. Although the isolation of a container with a completely
different set of namespaces is tight enough that except for people
debugging a container from processes in the container from outside the
container object exchange essentially doesn't happen.
You do raise a very good question here. Does an LSM implement a
different file permission system? Or does an LSM implement a firewall
between processes?
Certainly selinux seems too programmable to be considered just a
different file permission system.
> Pyramid tried to do the "simple" case of BSD and System 5 on the same box
> and got caught out even with that because of the different rules on stuff
> like chgrp..
Yes. There are many hard problems here and many people have tried and
failed in the past. That hasn't stopped me before, and I don't see
why security should be any different.
Eric
On Wed, 2007-10-10 at 07:48 -0600, Eric W. Biederman wrote:
> Alan Cox <[email protected]> writes:
>
> >> My very practical question: How do I run selinux in one container,
> >> and SMACK in another?
> >
> > In the LSM model you don't because you could have the same container
> > objects visible in different contains at the same time and subject to
> > different LSMs. What does it mean to pass an SELinux protected object
> > over an AppArmour protected unix domain socket into a SMACK protected
> > container ?
>
> You raise a good point. My intuitive definition would go something like
> this. In the initial LSM space we would have whatever is the primary
> LSM and it would always be invoked about everything. However it
> would view a single container (no matter what user in that container)
> as having a single set of permissions. Then the LSM in the container
> be asked to further validate accesses, but it would distinguish
> between users in the container.
SELinux internally has a notion of a type hierarchy, where a type is
limited to a subset of its parent's permissions, and one can then
delegate the ability to manage sub-types via a policy daemon. But this
is all handled in userspace; the kernel doesn't care about it.
Ditto for the modular policy support - that's a userspace construct that
is ultimately turned into a single coherent policy for the kernel to
enforce.
> At this point it looks like if I am going to be effective at doing
> anything I am going to need to step back watch SMACK get merged and
> then really look at what the LSM modules are implementing. Then
> I can refactor the whole mess and move additional functionality into
> the LSM to help me achieve other things.
>
> > Really its the same problem as "I'd like to use different file permission
> > systems on different process identifiers" and it would be very hard to
> > get right simply because objects can pass between two different security
> > models.
>
> Yep. Although the isolation of a container with a completely
> different set of namespaces is tight enough that except for people
> debugging a container from processes in the container from outside the
> container object exchange essentially doesn't happen.
>
> You do raise a very good question here. Does an LSM implement a
> different file permission system? Or does an LSM implement a firewall
> between processes?
>
> Certainly selinux seems too programmable to be considered just a
> different file permission system.
A LSM implements a security model, where that model may encompass all
processes and objects. SELinux (and Smack) in particular implement
mandatory access control and thus need to enforce consistent policy over
all processes and objects based on their security labels.
--
Stephen Smalley
National Security Agency
--- Stephen Smalley <[email protected]> wrote:
> On Wed, 2007-10-10 at 07:48 -0600, Eric W. Biederman wrote:
> > Alan Cox <[email protected]> writes:
> >
> > >> My very practical question: How do I run selinux in one container,
> > >> and SMACK in another?
> > >
> > > In the LSM model you don't because you could have the same container
> > > objects visible in different contains at the same time and subject to
> > > different LSMs. What does it mean to pass an SELinux protected object
> > > over an AppArmour protected unix domain socket into a SMACK protected
> > > container ?
> >
> > You raise a good point. My intuitive definition would go something like
> > this. In the initial LSM space we would have whatever is the primary
> > LSM and it would always be invoked about everything. However it
> > would view a single container (no matter what user in that container)
> > as having a single set of permissions. Then the LSM in the container
> > be asked to further validate accesses, but it would distinguish
> > between users in the container.
>
> SELinux internally has a notion of a type hierarchy, where a type is
> limited to a subset of its parent's permissions, and one can then
> delegate the ability to manage sub-types via a policy daemon. But this
> is all handled in userspace; the kernel doesn't care about it.
>
> Ditto for the modular policy support - that's a userspace construct that
> is ultimately turned into a single coherent policy for the kernel to
> enforce.
>
> > At this point it looks like if I am going to be effective at doing
> > anything I am going to need to step back watch SMACK get merged and
> > then really look at what the LSM modules are implementing. Then
> > I can refactor the whole mess and move additional functionality into
> > the LSM to help me achieve other things.
I think that you'll want to be careful with that approach.
Smack and SELinux both implement mandatory access control,
with very different mindsets too be sure, but MAC nonetheless.
Smack doesn't use any LSM hooks that SELinux doesn't. You
aren't going to get a very broad view of potential LSMs
comparing these two. AppArmor and TOMOYO are much more likely
to provide interesting alternative viewpoints. If you want to
get carried away factor the audit code in, too.
> > > Really its the same problem as "I'd like to use different file permission
> > > systems on different process identifiers" and it would be very hard to
> > > get right simply because objects can pass between two different security
> > > models.
> >
> > Yep. Although the isolation of a container with a completely
> > different set of namespaces is tight enough that except for people
> > debugging a container from processes in the container from outside the
> > container object exchange essentially doesn't happen.
> >
> > You do raise a very good question here. Does an LSM implement a
> > different file permission system? Or does an LSM implement a firewall
> > between processes?
> >
> > Certainly selinux seems too programmable to be considered just a
> > different file permission system.
>
> A LSM implements a security model, where that model may encompass all
> processes and objects. SELinux (and Smack) in particular implement
> mandatory access control and thus need to enforce consistent policy over
> all processes and objects based on their security labels.
What he said as far as Smack and SELinux go. Other models need not
encompass all processes and objects.
Casey Schaufler
[email protected]
Ok, finally getting some time to work on this stuff once again (life
gets really crazy sometimes). I would like to postulate that you can
restate any SMACK policy as a functionally equivalent SELinux policy
(with a few slight technical differences, see below). I've been
working on a script to do this but keep getting stuck tracking down
minor bugs and then get dragged off on other things I need to do.
Here is the method I am presently trying to implement:
First divide the SELinux access vectors into 7 groups based on which
ones SMACK wishes to influence:
(R) Requires "read" permissions (the 'r' bit)
(W) Requires "write" permissions (the 'w' bit)
(X) Requires "execute" permissions (the 'x' bit)
(A) Requires "append" OR "write" permissions (the 'a' bit)
(P) Requires CAP_MAC_OVERRIDE
(K) May not be performed by a non-CAP_MAC_OVERRIDE process on a
CAP_MAC_OVERRIDE process
(N) Does not require any special permissions
The letters in front indicate the names I will use in the rest of
this document to describe the sets of access vectors.
Next define a single SELinux user "smack", and two independent roles,
"priv" and "unpriv". We create the set of SMACK equivalence-classes
defined as various SELinux types with substitutions for "*", "^",
"_", and "?", and then completely omit the MLS portions of the
SELinux policy.
The next step is to establish the fundamental constraints of the
policy. To prevent processes from gaining CAP_MAC_OVERRIDE we
iterate over the access vectors in (K) and add the following
constraint for each vector:
constrain $OBJECT_CLASS $ACCESS_VECTOR ((r1 == r2) || (r1 == priv))
This also includes:
constrain process transition ((r1 == r2) || (r1 == priv))
Then we require privilege to access the (P) vectors; for each vector
in (P) we add a constraint:
constrain $OBJECT_CLASS $ACCESS_VECTOR (r1 == priv)
At this point the only rules left to add are the between-type rules.
Here it gets mildly complicated because SMACK is a linear-lookup
system (each rule must be matched in order) whereas SELinux is a
globally-unique-lookup system (all rules are mutually exclusive and
matched simultaneously). Essentially for each SMACK rule:
$SOURCE $DEST $PERM_BITS
We iterate over all of the classes represented in the access vector
lists in $PERM_BITS and create rules for each one:
allow { $SOURCE } { $DEST }:$PERM_CLASS { $PERM_VECTORS };
If you need SMACK to allow subtractive permissions then you need to
expand that further, however I believe as an initial cut that it
sufficient.
The only other task is to prepend the auto-generated object-class and
access-vector lists to the policy and append the initial SIDs that
smack wants various objects to have, as well as allowing the "smack"
user the "priv" and "nopriv" roles and allowing those two roles entry
into all of the SMACK types. The resulting SELinux-ified SMACK
labels would go from:
SomeLabel (with CAP_MAC_OVERRIDE)
AnotherLabel
YetAnotherLabel
to:
smack:priv:SomeLabel
smack:nopriv:AnotherLabel
smack:nopriv:YetAnotherLabel
Casey, hopefully this gives you some ideas about how I think you
could modify the SELinux code to compile out the "user" field and
simplify the "role" field as needed. I'm still not seeing anything
which SELinux cannot directly implement without additional code, even
the "CAP_MAC_OVERRIDE" bit. If the semantics don't seem quite right,
please provide details about how you think the models differ and I
will try to address the concerns.
Cheers,
Kyle Moffett
--- Kyle Moffett <[email protected]> wrote:
> Ok, finally getting some time to work on this stuff once again (life
> gets really crazy sometimes). I would like to postulate that you can
> restate any SMACK policy as a functionally equivalent SELinux policy
> (with a few slight technical differences, see below). I've been
> working on a script to do this but keep getting stuck tracking down
> minor bugs and then get dragged off on other things I need to do.
> Here is the method I am presently trying to implement:
>
> First divide the SELinux access vectors into 7 groups based on which
> ones SMACK wishes to influence:
> (R) Requires "read" permissions (the 'r' bit)
> (W) Requires "write" permissions (the 'w' bit)
> (X) Requires "execute" permissions (the 'x' bit)
> (A) Requires "append" OR "write" permissions (the 'a' bit)
> (P) Requires CAP_MAC_OVERRIDE
> (K) May not be performed by a non-CAP_MAC_OVERRIDE process on a
> CAP_MAC_OVERRIDE process
> (N) Does not require any special permissions
>
> The letters in front indicate the names I will use in the rest of
> this document to describe the sets of access vectors.
>
> Next define a single SELinux user "smack", and two independent roles,
> "priv" and "unpriv". We create the set of SMACK equivalence-classes
> defined as various SELinux types with substitutions for "*", "^",
> "_", and "?", and then completely omit the MLS portions of the
> SELinux policy.
>
> The next step is to establish the fundamental constraints of the
> policy. To prevent processes from gaining CAP_MAC_OVERRIDE we
> iterate over the access vectors in (K) and add the following
> constraint for each vector:
> constrain $OBJECT_CLASS $ACCESS_VECTOR ((r1 == r2) || (r1 == priv))
>
> This also includes:
> constrain process transition ((r1 == r2) || (r1 == priv))
>
> Then we require privilege to access the (P) vectors; for each vector
> in (P) we add a constraint:
> constrain $OBJECT_CLASS $ACCESS_VECTOR (r1 == priv)
>
> At this point the only rules left to add are the between-type rules.
> Here it gets mildly complicated because SMACK is a linear-lookup
> system (each rule must be matched in order) whereas SELinux is a
> globally-unique-lookup system (all rules are mutually exclusive and
> matched simultaneously). Essentially for each SMACK rule:
> $SOURCE $DEST $PERM_BITS
>
> We iterate over all of the classes represented in the access vector
> lists in $PERM_BITS and create rules for each one:
> allow { $SOURCE } { $DEST }:$PERM_CLASS { $PERM_VECTORS };
>
> If you need SMACK to allow subtractive permissions then you need to
> expand that further, however I believe as an initial cut that it
> sufficient.
>
> The only other task is to prepend the auto-generated object-class and
> access-vector lists to the policy and append the initial SIDs that
> smack wants various objects to have, as well as allowing the "smack"
> user the "priv" and "nopriv" roles and allowing those two roles entry
> into all of the SMACK types. The resulting SELinux-ified SMACK
> labels would go from:
>
> SomeLabel (with CAP_MAC_OVERRIDE)
> AnotherLabel
> YetAnotherLabel
>
> to:
>
> smack:priv:SomeLabel
> smack:nopriv:AnotherLabel
> smack:nopriv:YetAnotherLabel
>
>
> Casey, hopefully this gives you some ideas about how I think you
> could modify the SELinux code to compile out the "user" field and
> simplify the "role" field as needed. I'm still not seeing anything
> which SELinux cannot directly implement without additional code, even
> the "CAP_MAC_OVERRIDE" bit. If the semantics don't seem quite right,
> please provide details about how you think the models differ and I
> will try to address the concerns.
I'm still waiting to see the proposed SELinux policy that does
what Smack does. I can accept that you don't see anything that
can't be implemented thus, but that's not the point. You've
provided some really clear design notes, and that's great, but
it ain't the code. You said that you could write a 500 line
perl script that would do the whole thing, and that left some
people with an impression that Smack is a subset of SELinux.
Well, I'm already finding myself digging out from under that
missunderstanding, and with people who are assuming that your
policy has been done, "proving" the point.
I see nothing wrong with your approach, although I'm curious
about how your emulation of capabilities will work, or if it's
even rational to include in the SELinux context. I have my
benchmark lab* ready to go when you have a policy for me to try.
Thank you.
----
* It's a sony VAIO laptop with an 800MHZ AMD processor.
Casey Schaufler
[email protected]
On Oct 11, 2007, at 11:41:34, Casey Schaufler wrote:
> --- Kyle Moffett <[email protected]> wrote:
>> [snipped]
>
> I'm still waiting to see the proposed SELinux policy that does what
> Smack does.
That *is* the SELinux policy which does what Smack does. I keep
having bugs in the perl-script I'm writing on account of not having
the time to really get around to fixing it, but that is exactly the
procedure for generating an SELinux policy from a SMACK policy.
> I can accept that you don't see anything that can't be implemented
> thus, but that's not the point. You've provided some really clear
> design notes, and that's great, but it ain't the code. You said
> that you could write a 500 line perl script that would do the whole
> thing, and that left some people with an impression that Smack is a
> subset of SELinux. Well, I'm already finding myself digging out
> from under that missunderstanding, and with people who are assuming
> that your policy has been done, "proving" the point.
I'd love to have time to finish the script but unfortunately real
life keeps interfering and I'm going to have to go back to lurking on
this thread.
Cheers,
Kyle Moffett
> > from under that missunderstanding, and with people who are assuming
> > that your policy has been done, "proving" the point.
>
> I'd love to have time to finish the script but unfortunately real
> life keeps interfering and I'm going to have to go back to lurking on
> this thread.
How about posting the partial one you've got ?
Dear, Folks,
Now we are planning to submit LIDS to mainline.
(As you know, it already written for supporing LSM for several years.)
When we will finish to re-write documentation and some FAQ, then
we will be able to submit the patch.
Sincerely,
OMO
Serge E. Hallyn wrote: (2007/10/09 03:00):
> Quoting Eric W. Biederman ([email protected]):
>> "Serge E. Hallyn" <[email protected]> writes:
>> Also I'm thinking towards what do we have to do isolate the security
>> module stuff in the context of a namespace. So that a person in
>> a container can setup their own rules that further restrict the
>> system.
>
> In the selinux example I plan to do set up soon, that will be done
> using the '.' namespace separator.
>
> Every object/subject in vserver1 will have a type 'vserver1.whatever'.
> 'vserver1.root_t', 'vserver1.etc_t', etc.
>
> I don't know how far the policy tools have gotten, but they are
> *supposed* to implement constraints at policy compile time such that
> every type which is a child of 'vserver1' would have no more access than
> what is granted to type 'vserver1'. So this provides a pretty nice
> conceptual way to set up security for a vserver.
>
> Then using the userspace policy server and metapolicy (this would be a
> step or two beyond my first example) the policy could define rules about
> what sort of policy could be added by a process of type
> 'vserver1.root_t'. So we can allow the container admin to introduce
> policy changes affecting only his own container, and subject to all
> constraints placed by the host admin on vserver1.
>
>> So far I'm not ready to do anything yet but I'm keeping a weather eye
>> on the situation so I have a clue what I'm go.
>>
>>> If 1, an selinux policy should cover you. So you can then skip to 3.
>>> Or, alternatively, I do plan - as soon as my free time clears up a bit -
>>> on demonstrating how to write some selinux policy to create a secure
>>> container based on current -mm + your experimental network namespace
>>> patches.
>> Thanks that sounds interesting.
>>
>>> If 3, then selinux policy modules may actually help you, else either
>>> a new LSM (maybe like LIDS) or a userspace tool which is a front-end to
>>> selinux policy, emulating the iptables rules formats, may be what you
>>> want?
>> I don't want to have to choose my LSM at compile time. I want to
>> add support into the kernel at compile time and be able to configure
>> it before I go multi-user. I know this kind of architecture is
>> achievable because iptables allows it.
>>
>> When I conceive as the security modules as just a firewall between
>> applications on my own box I think, oh yeah this is no big deal,
>> I might want to limit something that way some time. These are just
>> some additional rules on when to return -EPERM. So I ask myself why
>> is this situation much less flexible and much harder to use then our
>> network firewall code?
>
> It actually used to be far more flexible than it is now. The consensus
> appears to be that it's just too hard - at times impossible - to
> properly label every object or subject at some point after they've all
> been created (processes created, inodes read from disk, etc). Two
> examples:
>
> 1. you've got pid 777. How was it created? Can you trust it's
> history? In my DTE module I solved this by keeping track of the
> *full* invocation history until a policy was loaded. I think
> tomoyo may do something similar. But it's really not
> sufficient, especially since you don't even want a LSM loaded
> at all. So you can't reduce it to 'boot_t executd init_t
> executed login_t executed shell_t', you have to keep track of
> every inode executed
>
> 2. how do you reliably re-evaluate, for some file, what label
> to assign to it? Do you guess at a pathname? Do you trust that
> the inodes have been pre-labeled for every LSM, so when you load
> the LSM you can grab the xattrs?
>
> So it's a valid question - do we address these sorts of concerns in
> order to add flexibility, or do we keep things as simple as possible
> and say that it's up to the distro, for instance, or a site local
> security administrator, to define policy, so that flexibility really
> is of very limited use?
>
>>>> My impression is that selinux is one monolithic blob that doesn't
>>>> allow me to incrementally add matching or action features that I
>>>> find interesting.
>>> Actually with policy modules it gets much much better. I have in fact
>>> been able to pretty easily write a short policy module to, say, create
>>> an selinux user which ran as root and had full access to the system to
>>> do system setup for automated testing. There is a learning curve in
>>> having to look at existing modules for maybe a few days to get started,
>>> but once you get started the policy modules do make it very easy to
>>> add to current policy.
>> Ok. Interesting. Are these kernel modules?
>
> Policy modules, loaded through selinuxfs at any time using 'semodule'.
>
>> Still while I get the general impression that selinux seems to be
>> very close to a generic solution, and that selinux more or less has
>> the architecture we might want. I don't get the impression that
>> selinux does this at a level that is open to other people doing
>> interesting things.
>>
>> So I still ask the question can we move this functionality down to
>> the LSM in a way that will solve the composition problem between
>> multiple security modules?
>
> I've tried :) At a less semantic and more purely technical level, using
> the stacker module. After a few years it was finally decided (at
> ksummit 2006) that it simply wasn't useful.
>
> Now perhaps the problem was that I didn't address semantic issues.
> But it does sound to me like what you want is a particular flexible LSM.
> Be it LIDS or SELinux, or something new.
>
>> It really seems to me that the LSM as currently structured creates
>> a large barrier to entry for people who have just this little thing
>> they want to do that is not possible with any existing security
>> module.
>
> Yes and it's been made increasingly so far particularly because of the
> perceived potential for 'abuse'. So to be curt, allowing people like
> you describe to do something small and interesting is deemed far less
> important than making sure that the small thing they want to do fits
> within the LSM mandate and is not a non-upstream module.
>
> So that is the concern you would need to address before any other.
>
> Still, I do think that selinux policy modules may do just what you want.
> The main obstacle appears to be that the 'base' policy is so huge that
> it's tough to get started to do something small.
>
> You also might want to check out LIDS, as its rules are set up pretty
> much the way you seem to want.
>
> -serge
> -
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Kazuki Omo: [email protected]
Group Manager, OSS Technology Center
Diary: http://omok.livejournal.com
--- "Kazuki Omo(Company)" <[email protected]> wrote:
> Dear, Folks,
>
> Now we are planning to submit LIDS to mainline.
> (As you know, it already written for supporing LSM for several years.)
>
> When we will finish to re-write documentation and some FAQ, then
> we will be able to submit the patch.
>
> Sincerely,
>
> OMO
Most excellent. Thank you.
Casey Schaufler
[email protected]