diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-23 23:15:19 +0200 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-23 23:15:19 +0200 |
commit | 272e77de798362c31e6452a46a0e7d5b6aaeb550 (patch) | |
tree | 52c767d8f7a1ffd3df0a910478450da5d9d47cf4 /security/smack/smack_lsm.c | |
parent | 7134863d0877e48d58344a51024a410fe1093a34 (diff) | |
download | kernel_samsung_smdk4412-272e77de798362c31e6452a46a0e7d5b6aaeb550.zip kernel_samsung_smdk4412-272e77de798362c31e6452a46a0e7d5b6aaeb550.tar.gz kernel_samsung_smdk4412-272e77de798362c31e6452a46a0e7d5b6aaeb550.tar.bz2 |
first round of updates to the security code
Diffstat (limited to 'security/smack/smack_lsm.c')
-rw-r--r-- | security/smack/smack_lsm.c | 303 |
1 files changed, 176 insertions, 127 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c43f73b..774c159 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -30,6 +30,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/pipe_fs_i.h> +#include <net/netlabel.h> #include <net/cipso_ipv4.h> #include <linux/audit.h> #include <linux/magic.h> @@ -37,8 +38,6 @@ #include <linux/personality.h> #include "smack.h" -#define task_security(task) (task_cred_xxx((task), security)) - #define TRANS_TRUE "TRUE" #define TRANS_TRUE_SIZE 4 @@ -53,23 +52,16 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) { int rc; - char *buffer; - char *result = NULL; + char in[SMK_LABELLEN]; if (ip->i_op->getxattr == NULL) return NULL; - buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); - if (buffer == NULL) + rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN); + if (rc < 0) return NULL; - rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); - if (rc > 0) - result = smk_import(buffer, rc); - - kfree(buffer); - - return result; + return smk_import(in, rc); } /** @@ -167,7 +159,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) if (rc != 0) return rc; - tsp = smk_of_task(task_security(ctp)); + tsp = smk_of_task_struct(ctp); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ctp); @@ -193,7 +185,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp) if (rc != 0) return rc; - tsp = smk_of_task(task_security(ptp)); + tsp = smk_of_task_struct(ptp); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ptp); @@ -214,7 +206,7 @@ static int smack_syslog(int typefrom_file) int rc = 0; char *sp = smk_of_current(); - if (smack_privileged(CAP_MAC_OVERRIDE)) + if (capable(CAP_MAC_OVERRIDE)) return 0; if (sp != smack_known_floor.smk_known) @@ -559,7 +551,6 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, void **value, size_t *len) { struct smack_known *skp; - struct inode_smack *issp = inode->i_security; char *csp = smk_of_current(); char *isp = smk_of_inode(inode); char *dsp = smk_of_inode(dir); @@ -581,13 +572,10 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, * If the access rule allows transmutation and * the directory requests transmutation then * by all means transmute. - * Mark the inode as changed. */ if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && - smk_inode_transmutable(dir)) { + smk_inode_transmutable(dir)) isp = dsp; - issp->smk_flags |= SMK_INODE_CHANGED; - } *value = kstrdup(isp, GFP_KERNEL); if (*value == NULL) @@ -733,15 +721,15 @@ static int smack_inode_rename(struct inode *old_inode, * smack_inode_permission - Smack version of permission() * @inode: the inode in question * @mask: the access requested - * @flags: special case * * This is the important Smack hook. * * Returns 0 if access is permitted, -EACCES otherwise */ -static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) +static int smack_inode_permission(struct inode *inode, int mask) { struct smk_audit_info ad; + int no_block = mask & MAY_NOT_BLOCK; mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); /* @@ -751,9 +739,8 @@ static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) return 0; /* May be droppable after audit */ - if (flags & IPERM_FLAG_RCU) + if (no_block) return -ECHILD; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, inode); return smk_curacc(smk_of_inode(inode), mask, &ad); @@ -823,17 +810,17 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; /* * check label validity here so import wont fail on * post_setxattr */ - if (size == 0 || size >= SMK_LONGLABEL || + if (size == 0 || size >= SMK_LABELLEN || smk_import(value, size) == NULL) rc = -EINVAL; } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; if (size != TRANS_TRUE_SIZE || strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) @@ -929,7 +916,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || strcmp(name, XATTR_NAME_SMACKMMAP)) { - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; } else rc = cap_inode_removexattr(dentry, name); @@ -1526,7 +1513,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access, smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); - return smk_curacc(smk_of_task(task_security(p)), access, &ad); + return smk_curacc(smk_of_task_struct(p), access, &ad); } /** @@ -1572,7 +1559,7 @@ static int smack_task_getsid(struct task_struct *p) */ static void smack_task_getsecid(struct task_struct *p, u32 *secid) { - *secid = smack_to_secid(smk_of_task(task_security(p))); + *secid = smack_to_secid(smk_of_task_struct(p)); } /** @@ -1684,7 +1671,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * can write the receiver. */ if (secid == 0) - return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE, + return smk_curacc(smk_of_task_struct(p), MAY_WRITE, &ad); /* * If the secid isn't 0 we're dealing with some USB IO @@ -1692,7 +1679,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * we can't take privilege into account. */ return smk_access(smack_from_secid(secid), - smk_of_task(task_security(p)), MAY_WRITE, &ad); + smk_of_task_struct(p), MAY_WRITE, &ad); } /** @@ -1705,9 +1692,13 @@ static int smack_task_wait(struct task_struct *p) { struct smk_audit_info ad; char *sp = smk_of_current(); - char *tsp = smk_of_forked(task_security(p)); + char *tsp; int rc; + rcu_read_lock(); + tsp = smk_of_forked(__task_cred(p)->security); + rcu_read_unlock(); + /* we don't log here, we can be overriden */ rc = smk_access(tsp, sp, MAY_WRITE, NULL); if (rc == 0) @@ -1724,8 +1715,7 @@ static int smack_task_wait(struct task_struct *p) * state into account in the decision as well as * the smack value. */ - if (smack_privileged(CAP_MAC_OVERRIDE) || - has_capability(p, CAP_MAC_OVERRIDE)) + if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE)) rc = 0; /* we log only if we didn't get overriden */ out_log: @@ -1745,7 +1735,7 @@ static int smack_task_wait(struct task_struct *p) static void smack_task_to_inode(struct task_struct *p, struct inode *inode) { struct inode_smack *isp = inode->i_security; - isp->smk_inode = smk_of_task(task_security(p)); + isp->smk_inode = smk_of_task_struct(p); } /* @@ -1829,6 +1819,65 @@ static char *smack_host_label(struct sockaddr_in *sip) } /** + * smack_set_catset - convert a capset to netlabel mls categories + * @catset: the Smack categories + * @sap: where to put the netlabel categories + * + * Allocates and fills attr.mls.cat + */ +static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap) +{ + unsigned char *cp; + unsigned char m; + int cat; + int rc; + int byte; + + if (!catset) + return; + + sap->flags |= NETLBL_SECATTR_MLS_CAT; + sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); + sap->attr.mls.cat->startbit = 0; + + for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++) + for (m = 0x80; m != 0; m >>= 1, cat++) { + if ((m & *cp) == 0) + continue; + rc = netlbl_secattr_catmap_setbit(&sap->attr.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. + * Apologies 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; + + nlsp->domain = smack; + nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; + + rc = smack_to_cipso(smack, &cipso); + if (rc == 0) { + nlsp->attr.mls.lvl = cipso.smk_level; + smack_set_catset(cipso.smk_catset, nlsp); + } else { + nlsp->attr.mls.lvl = smack_cipso_direct; + smack_set_catset(smack, nlsp); + } +} + +/** * smack_netlabel - Set the secattr on a socket * @sk: the socket * @labeled: socket label scheme @@ -1840,8 +1889,8 @@ static char *smack_host_label(struct sockaddr_in *sip) */ static int smack_netlabel(struct sock *sk, int labeled) { - struct smack_known *skp; struct socket_smack *ssp = sk->sk_security; + struct netlbl_lsm_secattr secattr; int rc = 0; /* @@ -1859,8 +1908,10 @@ static int smack_netlabel(struct sock *sk, int labeled) labeled == SMACK_UNLABELED_SOCKET) netlbl_sock_delattr(sk); else { - skp = smk_find_entry(ssp->smk_out); - rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); + netlbl_secattr_init(&secattr); + smack_to_secattr(ssp->smk_out, &secattr); + rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr); + netlbl_secattr_destroy(&secattr); } bh_unlock_sock(sk); @@ -1931,7 +1982,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, struct socket *sock; int rc = 0; - if (value == NULL || size > SMK_LONGLABEL || size == 0) + if (value == NULL || size > SMK_LABELLEN || size == 0) return -EACCES; sp = smk_import(value, size); @@ -2498,7 +2549,6 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) char *final; char trattr[TRANS_TRUE_SIZE]; int transflag = 0; - int rc; struct dentry *dp; if (inode == NULL) @@ -2617,38 +2667,17 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ dp = dget(opt_dentry); fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); - if (fetched != NULL) + if (fetched != NULL) { final = fetched; - - /* - * Transmuting directory - */ - if (S_ISDIR(inode->i_mode)) { - /* - * If this is a new directory and the label was - * transmuted when the inode was initialized - * set the transmute attribute on the directory - * and mark the inode. - * - * If there is a transmute attribute on the - * directory mark the inode. - */ - if (isp->smk_flags & SMK_INODE_CHANGED) { - isp->smk_flags &= ~SMK_INODE_CHANGED; - rc = inode->i_op->setxattr(dp, + if (S_ISDIR(inode->i_mode)) { + trattr[0] = '\0'; + inode->i_op->getxattr(dp, XATTR_NAME_SMACKTRANSMUTE, - TRANS_TRUE, TRANS_TRUE_SIZE, - 0); - } else { - rc = inode->i_op->getxattr(dp, - XATTR_NAME_SMACKTRANSMUTE, trattr, - TRANS_TRUE_SIZE); - if (rc >= 0 && strncmp(trattr, TRANS_TRUE, - TRANS_TRUE_SIZE) != 0) - rc = -EINVAL; + trattr, TRANS_TRUE_SIZE); + if (strncmp(trattr, TRANS_TRUE, + TRANS_TRUE_SIZE) == 0) + transflag = SMK_INODE_TRANSMUTE; } - if (rc >= 0) - transflag = SMK_INODE_TRANSMUTE; } isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); @@ -2687,7 +2716,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) if (strcmp(name, "current") != 0) return -EINVAL; - cp = kstrdup(smk_of_task(task_security(p)), GFP_KERNEL); + cp = kstrdup(smk_of_task_struct(p), GFP_KERNEL); if (cp == NULL) return -ENOMEM; @@ -2724,10 +2753,10 @@ static int smack_setprocattr(struct task_struct *p, char *name, if (p != current) return -EPERM; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; - if (value == NULL || size == 0 || size >= SMK_LONGLABEL) + if (value == NULL || size == 0 || size >= SMK_LABELLEN) return -EINVAL; if (strcmp(name, "current") != 0) @@ -2783,7 +2812,7 @@ static int smack_unix_stream_connect(struct sock *sock, smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); smk_ad_setfield_u_net_sk(&ad, other); - if (!smack_privileged(CAP_MAC_OVERRIDE)) + if (!capable(CAP_MAC_OVERRIDE)) rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); /* @@ -2815,7 +2844,7 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); smk_ad_setfield_u_net_sk(&ad, other->sk); - if (!smack_privileged(CAP_MAC_OVERRIDE)) + if (!capable(CAP_MAC_OVERRIDE)) rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); return rc; @@ -2855,9 +2884,10 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, struct socket_smack *ssp) { - struct smack_known *kp; + struct smack_known *skp; + char smack[SMK_LABELLEN]; char *sp; - int found = 0; + int pcat; if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { /* @@ -2865,27 +2895,59 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, * If there are flags but no level netlabel isn't * behaving the way we expect it to. * - * Look it up in the label table + * Get the categories, if any * Without guidance regarding the smack value * for the packet fall back on the network * ambient value. */ - rcu_read_lock(); - list_for_each_entry(kp, &smack_known_list, list) { - if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl) - continue; - if (memcmp(sap->attr.mls.cat, - kp->smk_netlabel.attr.mls.cat, - SMK_CIPSOLEN) != 0) - continue; - found = 1; - break; + memset(smack, '\0', SMK_LABELLEN); + if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) + for (pcat = -1;;) { + pcat = netlbl_secattr_catmap_walk( + sap->attr.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->attr.mls.lvl == smack_cipso_direct) { + /* + * The label sent is usually on the label list. + * + * If it is not we may still want to allow the + * delivery. + * + * If the recipient is accepting all packets + * because it is using the star ("*") label + * for SMACK64IPIN provide the web ("@") label + * so that a directed response will succeed. + * This is not very correct from a MAC point + * of view, but gets around the problem that + * locking prevents adding the newly discovered + * label to the list. + * The case where the recipient is not using + * the star label should obviously fail. + * The easy way to do this is to provide the + * star label as the subject label. + */ + skp = smk_find_entry(smack); + if (skp != NULL) + return skp->smk_known; + if (ssp != NULL && + ssp->smk_in == smack_known_star.smk_known) + return smack_known_web.smk_known; + return smack_known_star.smk_known; } - rcu_read_unlock(); - - if (found) - return kp->smk_known; - + /* + * Look it up in the supplied table if it is not + * a direct mapping. + */ + sp = smack_from_cipso(sap->attr.mls.lvl, smack); + if (sp != NULL) + return sp; if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) return smack_known_web.smk_known; return smack_known_star.smk_known; @@ -3082,13 +3144,11 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct request_sock *req) { u16 family = sk->sk_family; - struct smack_known *skp; struct socket_smack *ssp = sk->sk_security; struct netlbl_lsm_secattr secattr; struct sockaddr_in addr; struct iphdr *hdr; char *sp; - char *hsp; int rc; struct smk_audit_info ad; @@ -3132,14 +3192,16 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, hdr = ip_hdr(skb); addr.sin_addr.s_addr = hdr->saddr; rcu_read_lock(); - hsp = smack_host_label(&addr); - rcu_read_unlock(); - - if (hsp == NULL) { - skp = smk_find_entry(sp); - rc = netlbl_req_setattr(req, &skp->smk_netlabel); - } else + if (smack_host_label(&addr) == NULL) { + rcu_read_unlock(); + netlbl_secattr_init(&secattr); + smack_to_secattr(sp, &secattr); + rc = netlbl_req_setattr(req, &secattr); + netlbl_secattr_destroy(&secattr); + } else { + rcu_read_unlock(); netlbl_req_delattr(req); + } return rc; } @@ -3561,29 +3623,8 @@ struct security_operations smack_ops = { }; -static __init void init_smack_known_list(void) +static __init void init_smack_know_list(void) { - /* - * Initialize rule list locks - */ - mutex_init(&smack_known_huh.smk_rules_lock); - mutex_init(&smack_known_hat.smk_rules_lock); - mutex_init(&smack_known_floor.smk_rules_lock); - mutex_init(&smack_known_star.smk_rules_lock); - mutex_init(&smack_known_invalid.smk_rules_lock); - mutex_init(&smack_known_web.smk_rules_lock); - /* - * Initialize rule lists - */ - INIT_LIST_HEAD(&smack_known_huh.smk_rules); - INIT_LIST_HEAD(&smack_known_hat.smk_rules); - INIT_LIST_HEAD(&smack_known_star.smk_rules); - INIT_LIST_HEAD(&smack_known_floor.smk_rules); - INIT_LIST_HEAD(&smack_known_invalid.smk_rules); - INIT_LIST_HEAD(&smack_known_web.smk_rules); - /* - * Create the known labels list - */ list_add(&smack_known_huh.list, &smack_known_list); list_add(&smack_known_hat.list, &smack_known_list); list_add(&smack_known_star.list, &smack_known_list); @@ -3618,8 +3659,16 @@ static __init int smack_init(void) cred = (struct cred *) current->cred; cred->security = tsp; - /* initialize the smack_known_list */ - init_smack_known_list(); + /* initialize the smack_know_list */ + init_smack_know_list(); + /* + * Initialize locks + */ + 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); /* * Register with LSM |