diff options
Diffstat (limited to 'security/smack')
-rw-r--r-- | security/smack/smack.h | 1 | ||||
-rw-r--r-- | security/smack/smack_access.c | 10 | ||||
-rw-r--r-- | security/smack/smackfs.c | 92 |
3 files changed, 102 insertions, 1 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h index 4a4477f5afdc..31dce559595a 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -178,6 +178,7 @@ u32 smack_to_secid(const char *); extern int smack_cipso_direct; extern int smack_net_nltype; extern char *smack_net_ambient; +extern char *smack_onlycap; extern struct smack_known *smack_known; extern struct smack_known smack_known_floor; diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index f6b5f6eed6dd..79ff21ed4c3b 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -157,7 +157,7 @@ int smk_access(char *subject_label, char *object_label, int request) * * This function checks the current subject label/object label pair * in the access rule list and returns 0 if the access is permitted, - * non zero otherwise. It allows that current my have the capability + * non zero otherwise. It allows that current may have the capability * to override the rules. */ int smk_curacc(char *obj_label, u32 mode) @@ -168,6 +168,14 @@ int smk_curacc(char *obj_label, u32 mode) if (rc == 0) return 0; + /* + * Return if a specific label has been designated as the + * only one that gets privilege and current does not + * have that label. + */ + if (smack_onlycap != NULL && smack_onlycap != current->security) + return rc; + if (capable(CAP_MAC_OVERRIDE)) return 0; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 9733f8eb1a2a..c21d8c8bf0c7 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; @@ -789,6 +800,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; @@ -921,6 +1011,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 */ {""} }; |