summaryrefslogtreecommitdiff
path: root/security/smack/smackfs.c
diff options
context:
space:
mode:
authorCasey Schaufler <casey@schaufler-ca.com>2008-07-30 15:37:11 -0700
committerJames Morris <jmorris@namei.org>2008-08-05 10:55:53 +1000
commit15446235367fa4a621ff5abfa4b6ebbe25b33763 (patch)
treebc6823055afbef26560c63f8041caeadd4cef078 /security/smack/smackfs.c
parentcf9481e289247fe9cf40f2e2481220d899132049 (diff)
downloadlwn-15446235367fa4a621ff5abfa4b6ebbe25b33763.tar.gz
lwn-15446235367fa4a621ff5abfa4b6ebbe25b33763.zip
smack: limit privilege by label
There have been a number of requests to make the Smack LSM enforce MAC even in the face of privilege, either capability based or superuser based. This is not universally desired, however, so it seems desirable to make it optional. Further, at least one legacy OS implemented a scheme whereby only processes running with one particular label could be exempt from MAC. This patch supports these three cases. If /smack/onlycap is empty (unset or null-string) privilege is enforced in the normal way. If /smack/onlycap contains a label only processes running with that label may be MAC exempt. If the label in /smack/onlycap is the star label ("*") the semantics of the star label combine with the privilege restrictions to prevent any violations of MAC, even in the presence of privilege. Again, this will be independent of the privilege scheme. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> Reviewed-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 271a835fbbe3..e7c642458ec9 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -39,6 +39,7 @@ enum smk_inos {
SMK_DIRECT = 6, /* CIPSO level indicating direct label */
SMK_AMBIENT = 7, /* internet ambient label */
SMK_NLTYPE = 8, /* label scheme to use by default */
+ SMK_ONLYCAP = 9, /* the only "capable" label */
};
/*
@@ -68,6 +69,16 @@ int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
*/
int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
+/*
+ * Unless a process is running with this label even
+ * having CAP_MAC_OVERRIDE isn't enough to grant
+ * privilege to violate MAC policy. If no label is
+ * designated (the NULL case) capabilities apply to
+ * everyone. It is expected that the hat (^) label
+ * will be used if any label is used.
+ */
+char *smack_onlycap;
+
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
struct smk_list_entry *smack_list;
@@ -787,6 +798,85 @@ static const struct file_operations smk_ambient_ops = {
.write = smk_write_ambient,
};
+/**
+ * smk_read_onlycap - read() for /smack/onlycap
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @cn: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
+ size_t cn, loff_t *ppos)
+{
+ char *smack = "";
+ ssize_t rc = -EINVAL;
+ int asize;
+
+ if (*ppos != 0)
+ return 0;
+
+ if (smack_onlycap != NULL)
+ smack = smack_onlycap;
+
+ asize = strlen(smack) + 1;
+
+ if (cn >= asize)
+ rc = simple_read_from_buffer(buf, cn, ppos, smack, asize);
+
+ return rc;
+}
+
+/**
+ * smk_write_onlycap - write() for /smack/onlycap
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char in[SMK_LABELLEN];
+ char *sp = current->security;
+
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ /*
+ * This can be done using smk_access() but is done
+ * explicitly for clarity. The smk_access() implementation
+ * would use smk_access(smack_onlycap, MAY_WRITE)
+ */
+ if (smack_onlycap != NULL && smack_onlycap != sp)
+ return -EPERM;
+
+ if (count >= SMK_LABELLEN)
+ return -EINVAL;
+
+ if (copy_from_user(in, buf, count) != 0)
+ return -EFAULT;
+
+ /*
+ * Should the null string be passed in unset the onlycap value.
+ * This seems like something to be careful with as usually
+ * smk_import only expects to return NULL for errors. It
+ * is usually the case that a nullstring or "\n" would be
+ * bad to pass to smk_import but in fact this is useful here.
+ */
+ smack_onlycap = smk_import(in, count);
+
+ return count;
+}
+
+static const struct file_operations smk_onlycap_ops = {
+ .read = smk_read_onlycap,
+ .write = smk_write_onlycap,
+};
+
struct option_names {
int o_number;
char *o_name;
@@ -919,6 +1009,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
{"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
[SMK_NLTYPE] =
{"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
+ [SMK_ONLYCAP] =
+ {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
/* last one */ {""}
};