From c673944347edfd4362b10eea11ac384a582b1cf5 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 22 May 2013 18:42:56 -0700 Subject: Smack: Local IPv6 port based controls Smack does not provide access controls on IPv6 communications. This patch introduces a mechanism for maintaining Smack lables for local IPv6 communications. It is based on labeling local ports. The behavior should be compatible with any future "real" IPv6 support as it provides no interfaces for users to manipulate the labeling. Remote IPv6 connections use the ambient label the same way that unlabeled IPv4 packets are treated. Targeted for git://git.gitorious.org/smack-next/kernel.git Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 348 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 308 insertions(+), 40 deletions(-) (limited to 'security/smack/smack_lsm.c') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d52c780bdb7..609e89de3c2 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -27,10 +27,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -45,6 +48,12 @@ #define TRANS_TRUE "TRUE" #define TRANS_TRUE_SIZE 4 +#define SMK_CONNECTING 0 +#define SMK_RECEIVING 1 +#define SMK_SENDING 2 + +LIST_HEAD(smk_ipv6_port_list); + /** * smk_fetch - Fetch the smack label from a file. * @ip: a pointer to the inode @@ -1877,6 +1886,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) return smack_netlabel(sk, sk_lbl); } +/** + * smk_ipv6_port_label - Smack port access table management + * @sock: socket + * @address: address + * + * Create or update the port list entry + */ +static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) +{ + struct sock *sk = sock->sk; + struct sockaddr_in6 *addr6; + struct socket_smack *ssp = sock->sk->sk_security; + struct smk_port_label *spp; + unsigned short port = 0; + + if (address == NULL) { + /* + * This operation is changing the Smack information + * on the bound socket. Take the changes to the port + * as well. + */ + list_for_each_entry(spp, &smk_ipv6_port_list, list) { + if (sk != spp->smk_sock) + continue; + spp->smk_in = ssp->smk_in; + spp->smk_out = ssp->smk_out; + return; + } + /* + * A NULL address is only used for updating existing + * bound entries. If there isn't one, it's OK. + */ + return; + } + + addr6 = (struct sockaddr_in6 *)address; + port = ntohs(addr6->sin6_port); + /* + * This is a special case that is safely ignored. + */ + if (port == 0) + return; + + /* + * Look for an existing port list entry. + * This is an indication that a port is getting reused. + */ + list_for_each_entry(spp, &smk_ipv6_port_list, list) { + if (spp->smk_port != port) + continue; + spp->smk_port = port; + spp->smk_sock = sk; + spp->smk_in = ssp->smk_in; + spp->smk_out = ssp->smk_out; + return; + } + + /* + * A new port entry is required. + */ + spp = kzalloc(sizeof(*spp), GFP_KERNEL); + if (spp == NULL) + return; + + spp->smk_port = port; + spp->smk_sock = sk; + spp->smk_in = ssp->smk_in; + spp->smk_out = ssp->smk_out; + + list_add(&spp->list, &smk_ipv6_port_list); + return; +} + +/** + * smk_ipv6_port_check - check Smack port access + * @sock: socket + * @address: address + * + * Create or update the port list entry + */ +static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, + int act) +{ + __be16 *bep; + __be32 *be32p; + struct sockaddr_in6 *addr6; + struct smk_port_label *spp; + struct socket_smack *ssp = sk->sk_security; + unsigned short port = 0; + char *subject; + char *object; + struct smk_audit_info ad; +#ifdef CONFIG_AUDIT + struct lsm_network_audit net; +#endif + + if (act == SMK_RECEIVING) { + subject = smack_net_ambient; + object = ssp->smk_in; + } else { + subject = ssp->smk_out; + object = smack_net_ambient; + } + + /* + * Get the IP address and port from the address. + */ + addr6 = (struct sockaddr_in6 *)address; + port = ntohs(addr6->sin6_port); + bep = (__be16 *)(&addr6->sin6_addr); + be32p = (__be32 *)(&addr6->sin6_addr); + + /* + * It's remote, so port lookup does no good. + */ + if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1) + goto auditout; + + /* + * It's local so the send check has to have passed. + */ + if (act == SMK_RECEIVING) { + subject = smack_known_web.smk_known; + goto auditout; + } + + list_for_each_entry(spp, &smk_ipv6_port_list, list) { + if (spp->smk_port != port) + continue; + object = spp->smk_in; + if (act == SMK_CONNECTING) + ssp->smk_packet = spp->smk_out; + break; + } + +auditout: + +#ifdef CONFIG_AUDIT + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); + ad.a.u.net->family = sk->sk_family; + ad.a.u.net->dport = port; + if (act == SMK_RECEIVING) + ad.a.u.net->v6info.saddr = addr6->sin6_addr; + else + ad.a.u.net->v6info.daddr = addr6->sin6_addr; +#endif + return smk_access(subject, object, MAY_WRITE, &ad); +} + /** * smack_inode_setsecurity - set smack xattrs * @inode: the object @@ -1926,7 +2084,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ssp->smk_in = sp; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { ssp->smk_out = sp; - if (sock->sk->sk_family != PF_UNIX) { + if (sock->sk->sk_family == PF_INET) { rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); if (rc != 0) printk(KERN_WARNING @@ -1936,6 +2094,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, } else return -EOPNOTSUPP; + if (sock->sk->sk_family == PF_INET6) + smk_ipv6_port_label(sock, NULL); + return 0; } @@ -1962,6 +2123,25 @@ static int smack_socket_post_create(struct socket *sock, int family, return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); } +/** + * smack_socket_bind - record port binding information. + * @sock: the socket + * @address: the port address + * @addrlen: size of the address + * + * Records the label bound to a port. + * + * Returns 0 + */ +static int smack_socket_bind(struct socket *sock, struct sockaddr *address, + int addrlen) +{ + if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) + smk_ipv6_port_label(sock, address); + + return 0; +} + /** * smack_socket_connect - connect access check * @sock: the socket @@ -1975,12 +2155,24 @@ static int smack_socket_post_create(struct socket *sock, int family, static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, int addrlen) { - if (sock->sk == NULL || sock->sk->sk_family != PF_INET) + int rc = 0; + + if (sock->sk == NULL) return 0; - if (addrlen < sizeof(struct sockaddr_in)) - return -EINVAL; - return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); + switch (sock->sk->sk_family) { + case PF_INET: + if (addrlen < sizeof(struct sockaddr_in)) + return -EINVAL; + rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); + break; + case PF_INET6: + if (addrlen < sizeof(struct sockaddr_in6)) + return -EINVAL; + rc = smk_ipv6_port_check(sock->sk, sap, SMK_CONNECTING); + break; + } + return rc; } /** @@ -2792,22 +2984,32 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) * @msg: the message * @size: the size of the message * - * Return 0 if the current subject can write to the destination - * host. This is only a question if the destination is a single - * label host. + * Return 0 if the current subject can write to the destination host. + * For IPv4 this is only a question if the destination is a single label host. + * For IPv6 this is a check against the label of the port. */ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; + struct sockaddr *sap = (struct sockaddr *) msg->msg_name; + int rc = 0; /* * Perfectly reasonable for this to be NULL */ - if (sip == NULL || sip->sin_family != AF_INET) + if (sip == NULL) return 0; - return smack_netlabel_send(sock->sk, sip); + switch (sip->sin_family) { + case AF_INET: + rc = smack_netlabel_send(sock->sk, sip); + break; + case AF_INET6: + rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); + break; + } + return rc; } /** @@ -2878,6 +3080,54 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, return smack_net_ambient; } +static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr *sap) +{ + struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap; + u8 nexthdr; + int offset; + int proto = -EINVAL; + struct ipv6hdr _ipv6h; + struct ipv6hdr *ip6; + __be16 frag_off; + struct tcphdr _tcph, *th; + struct udphdr _udph, *uh; + struct dccp_hdr _dccph, *dh; + + sip->sin6_port = 0; + + offset = skb_network_offset(skb); + ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); + if (ip6 == NULL) + return -EINVAL; + sip->sin6_addr = ip6->saddr; + + nexthdr = ip6->nexthdr; + offset += sizeof(_ipv6h); + offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); + if (offset < 0) + return -EINVAL; + + proto = nexthdr; + switch (proto) { + case IPPROTO_TCP: + th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); + if (th != NULL) + sip->sin6_port = th->source; + break; + case IPPROTO_UDP: + uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); + if (uh != NULL) + sip->sin6_port = uh->source; + break; + case IPPROTO_DCCP: + dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); + if (dh != NULL) + sip->sin6_port = dh->dccph_sport; + break; + } + return proto; +} + /** * smack_socket_sock_rcv_skb - Smack packet delivery access check * @sk: socket @@ -2889,43 +3139,52 @@ 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; + struct sockaddr sadd; char *csp; - int rc; + int rc = 0; struct smk_audit_info ad; #ifdef CONFIG_AUDIT struct lsm_network_audit net; #endif - if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) - return 0; - - /* - * Translate what netlabel gave us. - */ - netlbl_secattr_init(&secattr); + switch (sk->sk_family) { + case PF_INET: + /* + * Translate what netlabel gave us. + */ + netlbl_secattr_init(&secattr); - rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); - if (rc == 0) - csp = smack_from_secattr(&secattr, ssp); - else - csp = smack_net_ambient; + rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); + if (rc == 0) + csp = smack_from_secattr(&secattr, ssp); + else + csp = smack_net_ambient; - netlbl_secattr_destroy(&secattr); + netlbl_secattr_destroy(&secattr); #ifdef CONFIG_AUDIT - smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); - ad.a.u.net->family = sk->sk_family; - ad.a.u.net->netif = skb->skb_iif; - ipv4_skb_to_auditdata(skb, &ad.a, NULL); + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); + ad.a.u.net->family = sk->sk_family; + ad.a.u.net->netif = skb->skb_iif; + ipv4_skb_to_auditdata(skb, &ad.a, NULL); #endif - /* - * 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(csp, ssp->smk_in, MAY_WRITE, &ad); - if (rc != 0) - netlbl_skbuff_err(skb, rc, 0); + /* + * 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(csp, ssp->smk_in, MAY_WRITE, &ad); + if (rc != 0) + netlbl_skbuff_err(skb, rc, 0); + break; + case PF_INET6: + rc = smk_skb_to_addr_ipv6(skb, &sadd); + if (rc == IPPROTO_UDP || rc == IPPROTO_TCP) + rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); + else + rc = 0; + break; + } return rc; } @@ -3063,9 +3322,17 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct lsm_network_audit net; #endif - /* handle mapped IPv4 packets arriving via IPv6 sockets */ - if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) - family = PF_INET; + if (family == PF_INET6) { + /* + * Handle mapped IPv4 packets arriving + * via IPv6 sockets. Don't set up netlabel + * processing on IPv6. + */ + if (skb->protocol == htons(ETH_P_IP)) + family = PF_INET; + else + return 0; + } netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); @@ -3498,6 +3765,7 @@ struct security_operations smack_ops = { .unix_may_send = smack_unix_may_send, .socket_post_create = smack_socket_post_create, + .socket_bind = smack_socket_bind, .socket_connect = smack_socket_connect, .socket_sendmsg = smack_socket_sendmsg, .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, -- cgit v1.2.3-18-g5258 From 2f823ff8bec03a1e6f9e11fd0c4d54e4c7d09532 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 22 May 2013 18:43:03 -0700 Subject: Smack: Improve access check performance Each Smack label that the kernel has seen is added to a list of labels. The list of access rules for a given subject label hangs off of the label list entry for the label. This patch changes the structures that contain subject labels to point at the label list entry rather that the label itself. Doing so removes a label list lookup in smk_access() that was accounting for the largest single chunk of Smack overhead. Targeted for git://git.gitorious.org/smack-next/kernel.git Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 331 ++++++++++++++++++++++++--------------------- 1 file changed, 180 insertions(+), 151 deletions(-) (limited to 'security/smack/smack_lsm.c') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 609e89de3c2..3669d9f9824 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -62,11 +62,12 @@ LIST_HEAD(smk_ipv6_port_list); * 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(const char *name, struct inode *ip, struct dentry *dp) +static struct smack_known *smk_fetch(const char *name, struct inode *ip, + struct dentry *dp) { int rc; char *buffer; - char *result = NULL; + struct smack_known *skp = NULL; if (ip->i_op->getxattr == NULL) return NULL; @@ -77,11 +78,11 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); if (rc > 0) - result = smk_import(buffer, rc); + skp = smk_import_entry(buffer, rc); kfree(buffer); - return result; + return skp; } /** @@ -111,7 +112,8 @@ struct inode_smack *new_inode_smack(char *smack) * * Returns the new blob or NULL if there's no memory available */ -static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp) +static struct task_smack *new_task_smack(struct smack_known *task, + struct smack_known *forked, gfp_t gfp) { struct task_smack *tsp; @@ -173,17 +175,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) { int rc; struct smk_audit_info ad; - char *tsp; + struct smack_known *skp; rc = cap_ptrace_access_check(ctp, mode); if (rc != 0) return rc; - tsp = smk_of_task(task_security(ctp)); + skp = smk_of_task(task_security(ctp)); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ctp); - rc = smk_curacc(tsp, MAY_READWRITE, &ad); + rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad); return rc; } @@ -199,17 +201,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp) { int rc; struct smk_audit_info ad; - char *tsp; + struct smack_known *skp; rc = cap_ptrace_traceme(ptp); if (rc != 0) return rc; - tsp = smk_of_task(task_security(ptp)); + skp = smk_of_task(task_security(ptp)); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ptp); - rc = smk_curacc(tsp, MAY_READWRITE, &ad); + rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad); return rc; } @@ -224,12 +226,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp) static int smack_syslog(int typefrom_file) { int rc = 0; - char *sp = smk_of_current(); + struct smack_known *skp = smk_of_current(); if (smack_privileged(CAP_MAC_OVERRIDE)) return 0; - if (sp != smack_known_floor.smk_known) + if (skp != &smack_known_floor) rc = -EACCES; return rc; @@ -533,7 +535,9 @@ static int smack_bprm_secureexec(struct linux_binprm *bprm) */ static int smack_inode_alloc_security(struct inode *inode) { - inode->i_security = new_inode_smack(smk_of_current()); + struct smack_known *skp = smk_of_current(); + + inode->i_security = new_inode_smack(skp->smk_known); if (inode->i_security == NULL) return -ENOMEM; return 0; @@ -566,9 +570,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, char **name, void **value, size_t *len) { - struct smack_known *skp; struct inode_smack *issp = inode->i_security; - char *csp = smk_of_current(); + struct smack_known *skp = smk_of_current(); char *isp = smk_of_inode(inode); char *dsp = smk_of_inode(dir); int may; @@ -580,9 +583,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, } if (value) { - skp = smk_find_entry(csp); rcu_read_lock(); - may = smk_access_entry(csp, dsp, &skp->smk_rules); + may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules); rcu_read_unlock(); /* @@ -871,29 +873,31 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - char *nsp; + struct smack_known *skp; struct inode_smack *isp = dentry->d_inode->i_security; + if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { + isp->smk_flags |= SMK_INODE_TRANSMUTE; + return; + } + + skp = smk_import_entry(value, size); if (strcmp(name, XATTR_NAME_SMACK) == 0) { - nsp = smk_import(value, size); - if (nsp != NULL) - isp->smk_inode = nsp; + if (skp != NULL) + isp->smk_inode = skp->smk_known; else isp->smk_inode = smack_known_invalid.smk_known; } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { - nsp = smk_import(value, size); - if (nsp != NULL) - isp->smk_task = nsp; + if (skp != NULL) + isp->smk_task = skp; else - isp->smk_task = smack_known_invalid.smk_known; + isp->smk_task = &smack_known_invalid; } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { - nsp = smk_import(value, size); - if (nsp != NULL) - isp->smk_mmap = nsp; + if (skp != NULL) + isp->smk_mmap = skp; else - isp->smk_mmap = smack_known_invalid.smk_known; - } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) - isp->smk_flags |= SMK_INODE_TRANSMUTE; + isp->smk_mmap = &smack_known_invalid; + } return; } @@ -999,7 +1003,7 @@ static int smack_inode_getsecurity(const struct inode *inode, if (strcmp(name, XATTR_SMACK_IPIN) == 0) isp = ssp->smk_in; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) - isp = ssp->smk_out; + isp = ssp->smk_out->smk_known; else return -EOPNOTSUPP; @@ -1079,7 +1083,9 @@ static int smack_file_permission(struct file *file, int mask) */ static int smack_file_alloc_security(struct file *file) { - file->f_security = smk_of_current(); + struct smack_known *skp = smk_of_current(); + + file->f_security = skp->smk_known; return 0; } @@ -1190,10 +1196,9 @@ static int smack_mmap_file(struct file *file, unsigned long flags) { struct smack_known *skp; + struct smack_known *mkp; struct smack_rule *srp; struct task_smack *tsp; - char *sp; - char *msmack; char *osmack; struct inode_smack *isp; int may; @@ -1207,11 +1212,10 @@ static int smack_mmap_file(struct file *file, isp = file_inode(file)->i_security; if (isp->smk_mmap == NULL) return 0; - msmack = isp->smk_mmap; + mkp = isp->smk_mmap; tsp = current_security(); - sp = smk_of_current(); - skp = smk_find_entry(sp); + skp = smk_of_current(); rc = 0; rcu_read_lock(); @@ -1225,13 +1229,13 @@ static int smack_mmap_file(struct file *file, /* * Matching labels always allows access. */ - if (msmack == osmack) + if (mkp->smk_known == osmack) continue; /* * If there is a matching local rule take * that into account as well. */ - may = smk_access_entry(srp->smk_subject, osmack, + may = smk_access_entry(srp->smk_subject->smk_known, osmack, &tsp->smk_rules); if (may == -ENOENT) may = srp->smk_access; @@ -1249,8 +1253,8 @@ static int smack_mmap_file(struct file *file, * If there isn't one a SMACK64MMAP subject * can't have as much access as current. */ - skp = smk_find_entry(msmack); - mmay = smk_access_entry(msmack, osmack, &skp->smk_rules); + mmay = smk_access_entry(mkp->smk_known, osmack, + &mkp->smk_rules); if (mmay == -ENOENT) { rc = -EACCES; break; @@ -1259,7 +1263,8 @@ static int smack_mmap_file(struct file *file, * If there is a local entry it modifies the * potential access, too. */ - tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules); + tmay = smk_access_entry(mkp->smk_known, osmack, + &tsp->smk_rules); if (tmay != -ENOENT) mmay &= tmay; @@ -1288,7 +1293,9 @@ static int smack_mmap_file(struct file *file, */ static int smack_file_set_fowner(struct file *file) { - file->f_security = smk_of_current(); + struct smack_known *skp = smk_of_current(); + + file->f_security = skp->smk_known; return 0; } @@ -1306,9 +1313,10 @@ static int smack_file_set_fowner(struct file *file) static int smack_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { + struct smack_known *skp; + struct smack_known *tkp = smk_of_task(tsk->cred->security); struct file *file; int rc; - char *tsp = smk_of_task(tsk->cred->security); struct smk_audit_info ad; /* @@ -1317,13 +1325,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, file = container_of(fown, struct file, f_owner); /* we don't log here as rc can be overriden */ - rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); + skp = smk_find_entry(file->f_security); + rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL); if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, tsk); - smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad); + smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad); return rc; } @@ -1478,12 +1487,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old) static int smack_kernel_act_as(struct cred *new, u32 secid) { struct task_smack *new_tsp = new->security; - char *smack = smack_from_secid(secid); + struct smack_known *skp = smack_from_secid(secid); - if (smack == NULL) + if (skp == NULL) return -EINVAL; - new_tsp->smk_task = smack; + new_tsp->smk_task = skp; return 0; } @@ -1501,8 +1510,8 @@ static int smack_kernel_create_files_as(struct cred *new, struct inode_smack *isp = inode->i_security; struct task_smack *tsp = new->security; - tsp->smk_forked = isp->smk_inode; - tsp->smk_task = isp->smk_inode; + tsp->smk_forked = smk_find_entry(isp->smk_inode); + tsp->smk_task = tsp->smk_forked; return 0; } @@ -1518,10 +1527,11 @@ static int smk_curacc_on_task(struct task_struct *p, int access, const char *caller) { struct smk_audit_info ad; + struct smack_known *skp = smk_of_task(task_security(p)); 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(skp->smk_known, access, &ad); } /** @@ -1567,7 +1577,9 @@ 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))); + struct smack_known *skp = smk_of_task(task_security(p)); + + *secid = skp->smk_secid; } /** @@ -1671,6 +1683,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid) { struct smk_audit_info ad; + struct smack_known *skp; + struct smack_known *tkp = smk_of_task(task_security(p)); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); @@ -1679,15 +1693,14 @@ 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, - &ad); + return smk_curacc(tkp->smk_known, MAY_WRITE, &ad); /* * 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), - smk_of_task(task_security(p)), MAY_WRITE, &ad); + skp = smack_from_secid(secid); + return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad); } /** @@ -1719,7 +1732,9 @@ 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)); + struct smack_known *skp = smk_of_task(task_security(p)); + + isp->smk_inode = skp->smk_known; } /* @@ -1738,15 +1753,15 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode) */ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) { - char *csp = smk_of_current(); + struct smack_known *skp = smk_of_current(); struct socket_smack *ssp; ssp = kzalloc(sizeof(struct socket_smack), gfp_flags); if (ssp == NULL) return -ENOMEM; - ssp->smk_in = csp; - ssp->smk_out = csp; + ssp->smk_in = skp->smk_known; + ssp->smk_out = skp; ssp->smk_packet = NULL; sk->sk_security = ssp; @@ -1833,7 +1848,7 @@ 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); + skp = ssp->smk_out; rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); } @@ -1856,6 +1871,7 @@ static int smack_netlabel(struct sock *sk, int labeled) */ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) { + struct smack_known *skp; int rc; int sk_lbl; char *hostsp; @@ -1874,7 +1890,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr; #endif sk_lbl = SMACK_UNLABELED_SOCKET; - rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad); + skp = ssp->smk_out; + rc = smk_access(skp, hostsp, MAY_WRITE, &ad); } else { sk_lbl = SMACK_CIPSO_SOCKET; rc = 0; @@ -1974,8 +1991,8 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, struct sockaddr_in6 *addr6; struct smk_port_label *spp; struct socket_smack *ssp = sk->sk_security; + struct smack_known *skp; unsigned short port = 0; - char *subject; char *object; struct smk_audit_info ad; #ifdef CONFIG_AUDIT @@ -1983,11 +2000,11 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, #endif if (act == SMK_RECEIVING) { - subject = smack_net_ambient; + skp = smack_net_ambient; object = ssp->smk_in; } else { - subject = ssp->smk_out; - object = smack_net_ambient; + skp = ssp->smk_out; + object = smack_net_ambient->smk_known; } /* @@ -2008,7 +2025,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, * It's local so the send check has to have passed. */ if (act == SMK_RECEIVING) { - subject = smack_known_web.smk_known; + skp = &smack_known_web; goto auditout; } @@ -2017,7 +2034,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, continue; object = spp->smk_in; if (act == SMK_CONNECTING) - ssp->smk_packet = spp->smk_out; + ssp->smk_packet = spp->smk_out->smk_known; break; } @@ -2032,7 +2049,7 @@ auditout: else ad.a.u.net->v6info.daddr = addr6->sin6_addr; #endif - return smk_access(subject, object, MAY_WRITE, &ad); + return smk_access(skp, object, MAY_WRITE, &ad); } /** @@ -2050,7 +2067,7 @@ auditout: static int smack_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) { - char *sp; + struct smack_known *skp; struct inode_smack *nsp = inode->i_security; struct socket_smack *ssp; struct socket *sock; @@ -2059,12 +2076,12 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, if (value == NULL || size > SMK_LONGLABEL || size == 0) return -EACCES; - sp = smk_import(value, size); - if (sp == NULL) + skp = smk_import_entry(value, size); + if (skp == NULL) return -EINVAL; if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { - nsp->smk_inode = sp; + nsp->smk_inode = skp->smk_known; nsp->smk_flags |= SMK_INODE_INSTANT; return 0; } @@ -2081,9 +2098,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ssp = sock->sk->sk_security; if (strcmp(name, XATTR_SMACK_IPIN) == 0) - ssp->smk_in = sp; + ssp->smk_in = skp->smk_known; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { - ssp->smk_out = sp; + ssp->smk_out = skp; if (sock->sk->sk_family == PF_INET) { rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); if (rc != 0) @@ -2203,7 +2220,9 @@ static int smack_flags_to_may(int flags) */ static int smack_msg_msg_alloc_security(struct msg_msg *msg) { - msg->security = smk_of_current(); + struct smack_known *skp = smk_of_current(); + + msg->security = skp->smk_known; return 0; } @@ -2238,8 +2257,9 @@ static char *smack_of_shm(struct shmid_kernel *shp) static int smack_shm_alloc_security(struct shmid_kernel *shp) { struct kern_ipc_perm *isp = &shp->shm_perm; + struct smack_known *skp = smk_of_current(); - isp->security = smk_of_current(); + isp->security = skp->smk_known; return 0; } @@ -2361,8 +2381,9 @@ static char *smack_of_sem(struct sem_array *sma) static int smack_sem_alloc_security(struct sem_array *sma) { struct kern_ipc_perm *isp = &sma->sem_perm; + struct smack_known *skp = smk_of_current(); - isp->security = smk_of_current(); + isp->security = skp->smk_known; return 0; } @@ -2479,8 +2500,9 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, static int smack_msg_queue_alloc_security(struct msg_queue *msq) { struct kern_ipc_perm *kisp = &msq->q_perm; + struct smack_known *skp = smk_of_current(); - kisp->security = smk_of_current(); + kisp->security = skp->smk_known; return 0; } @@ -2652,8 +2674,8 @@ 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 = smk_of_current(); - char *fetched; + struct smack_known *skp; + struct smack_known *ckp = smk_of_current(); char *final; char trattr[TRANS_TRUE_SIZE]; int transflag = 0; @@ -2720,7 +2742,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * Programs that change smack have to treat the * pty with respect. */ - final = csp; + final = ckp->smk_known; break; case SOCKFS_MAGIC: /* @@ -2775,9 +2797,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * Get the dentry for xattr. */ dp = dget(opt_dentry); - fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); - if (fetched != NULL) - final = fetched; + skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); + if (skp != NULL) + final = skp->smk_known; /* * Transmuting directory @@ -2817,7 +2839,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) } if (final == NULL) - isp->smk_inode = csp; + isp->smk_inode = ckp->smk_known; else isp->smk_inode = final; @@ -2840,13 +2862,14 @@ unlockandout: */ static int smack_getprocattr(struct task_struct *p, char *name, char **value) { + struct smack_known *skp = smk_of_task(task_security(p)); char *cp; int slen; if (strcmp(name, "current") != 0) return -EINVAL; - cp = kstrdup(smk_of_task(task_security(p)), GFP_KERNEL); + cp = kstrdup(skp->smk_known, GFP_KERNEL); if (cp == NULL) return -ENOMEM; @@ -2872,7 +2895,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, { struct task_smack *tsp; struct cred *new; - char *newsmack; + struct smack_known *skp; /* * Changing another process' Smack value is too dangerous @@ -2890,14 +2913,14 @@ static int smack_setprocattr(struct task_struct *p, char *name, if (strcmp(name, "current") != 0) return -EINVAL; - newsmack = smk_import(value, size); - if (newsmack == NULL) + skp = smk_import_entry(value, size); + if (skp == NULL) return -EINVAL; /* * No process is ever allowed the web ("@") label. */ - if (newsmack == smack_known_web.smk_known) + if (skp == &smack_known_web) return -EPERM; new = prepare_creds(); @@ -2905,7 +2928,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, return -ENOMEM; tsp = new->security; - tsp->smk_task = newsmack; + tsp->smk_task = skp; commit_creds(new); return size; @@ -2923,6 +2946,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, static int smack_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk) { + struct smack_known *skp; struct socket_smack *ssp = sock->sk_security; struct socket_smack *osp = other->sk_security; struct socket_smack *nsp = newsk->sk_security; @@ -2936,15 +2960,17 @@ static int smack_unix_stream_connect(struct sock *sock, smk_ad_setfield_u_net_sk(&ad, other); #endif - if (!smack_privileged(CAP_MAC_OVERRIDE)) - rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + if (!smack_privileged(CAP_MAC_OVERRIDE)) { + skp = ssp->smk_out; + rc = smk_access(skp, osp->smk_in, MAY_WRITE, &ad); + } /* * Cross reference the peer labels for SO_PEERSEC. */ if (rc == 0) { - nsp->smk_packet = ssp->smk_out; - ssp->smk_packet = osp->smk_out; + nsp->smk_packet = ssp->smk_out->smk_known; + ssp->smk_packet = osp->smk_out->smk_known; } return rc; @@ -2962,8 +2988,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) { struct socket_smack *ssp = sock->sk->sk_security; struct socket_smack *osp = other->sk->sk_security; + struct smack_known *skp; struct smk_audit_info ad; - int rc = 0; #ifdef CONFIG_AUDIT struct lsm_network_audit net; @@ -2972,10 +2998,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) smk_ad_setfield_u_net_sk(&ad, other->sk); #endif - if (!smack_privileged(CAP_MAC_OVERRIDE)) - rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + if (smack_privileged(CAP_MAC_OVERRIDE)) + return 0; - return rc; + skp = ssp->smk_out; + return smk_access(skp, osp->smk_in, MAY_WRITE, &ad); } /** @@ -3017,13 +3044,12 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, * @sap: netlabel secattr * @ssp: socket security information * - * Returns a pointer to a Smack label found on the label list. + * Returns a pointer to a Smack label entry found on the label list. */ -static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, - struct socket_smack *ssp) +static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, + struct socket_smack *ssp) { - struct smack_known *kp; - char *sp; + struct smack_known *skp; int found = 0; if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { @@ -3038,11 +3064,11 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, * 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) + list_for_each_entry(skp, &smack_known_list, list) { + if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) continue; if (memcmp(sap->attr.mls.cat, - kp->smk_netlabel.attr.mls.cat, + skp->smk_netlabel.attr.mls.cat, SMK_CIPSOLEN) != 0) continue; found = 1; @@ -3051,17 +3077,17 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, rcu_read_unlock(); if (found) - return kp->smk_known; + return skp; if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) - return smack_known_web.smk_known; - return smack_known_star.smk_known; + return &smack_known_web; + return &smack_known_star; } if ((sap->flags & NETLBL_SECATTR_SECID) != 0) { /* * Looks like a fallback, which gives us a secid. */ - sp = smack_from_secid(sap->attr.secid); + skp = smack_from_secid(sap->attr.secid); /* * This has got to be a bug because it is * impossible to specify a fallback without @@ -3069,8 +3095,8 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, * it has a secid, and the only way to get a * secid is from a fallback. */ - BUG_ON(sp == NULL); - return sp; + BUG_ON(skp == NULL); + return skp; } /* * Without guidance regarding the smack value @@ -3139,8 +3165,8 @@ 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; + struct smack_known *skp; struct sockaddr sadd; - char *csp; int rc = 0; struct smk_audit_info ad; #ifdef CONFIG_AUDIT @@ -3155,9 +3181,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); if (rc == 0) - csp = smack_from_secattr(&secattr, ssp); + skp = smack_from_secattr(&secattr, ssp); else - csp = smack_net_ambient; + skp = smack_net_ambient; netlbl_secattr_destroy(&secattr); @@ -3173,7 +3199,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) * This is the simplist possible security model * for networking. */ - rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); if (rc != 0) netlbl_skbuff_err(skb, rc, 0); break; @@ -3238,7 +3264,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, { struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = NULL; - char *sp; + struct smack_known *skp; int family = PF_UNSPEC; u32 s = 0; /* 0 is the invalid secid */ int rc; @@ -3254,7 +3280,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, if (family == PF_UNIX) { ssp = sock->sk->sk_security; - s = smack_to_secid(ssp->smk_out); + s = ssp->smk_out->smk_secid; } else if (family == PF_INET || family == PF_INET6) { /* * Translate what netlabel gave us. @@ -3264,8 +3290,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); if (rc == 0) { - sp = smack_from_secattr(&secattr, ssp); - s = smack_to_secid(sp); + skp = smack_from_secattr(&secattr, ssp); + s = skp->smk_secid; } netlbl_secattr_destroy(&secattr); } @@ -3286,13 +3312,15 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, static void smack_sock_graft(struct sock *sk, struct socket *parent) { struct socket_smack *ssp; + struct smack_known *skp = smk_of_current(); if (sk == NULL || (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)) return; ssp = sk->sk_security; - ssp->smk_in = ssp->smk_out = smk_of_current(); + ssp->smk_in = skp->smk_known; + ssp->smk_out = skp; /* cssp->smk_packet is already set in smack_inet_csk_clone() */ } @@ -3314,7 +3342,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct netlbl_lsm_secattr secattr; struct sockaddr_in addr; struct iphdr *hdr; - char *sp; char *hsp; int rc; struct smk_audit_info ad; @@ -3337,9 +3364,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); if (rc == 0) - sp = smack_from_secattr(&secattr, ssp); + skp = smack_from_secattr(&secattr, ssp); else - sp = smack_known_huh.smk_known; + skp = &smack_known_huh; netlbl_secattr_destroy(&secattr); #ifdef CONFIG_AUDIT @@ -3352,7 +3379,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, * Receiving a packet requires that the other end be able to write * here. Read access is not required. */ - rc = smk_access(sp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); if (rc != 0) return rc; @@ -3360,7 +3387,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, * Save the peer's label in the request_sock so we can later setup * smk_packet in the child socket so that SO_PEERCRED can report it. */ - req->peer_secid = smack_to_secid(sp); + req->peer_secid = skp->smk_secid; /* * We need to decide if we want to label the incoming connection here @@ -3373,10 +3400,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, hsp = smack_host_label(&addr); rcu_read_unlock(); - if (hsp == NULL) { - skp = smk_find_entry(sp); + if (hsp == NULL) rc = netlbl_req_setattr(req, &skp->smk_netlabel); - } else + else netlbl_req_delattr(req); return rc; @@ -3393,10 +3419,12 @@ static void smack_inet_csk_clone(struct sock *sk, const struct request_sock *req) { struct socket_smack *ssp = sk->sk_security; + struct smack_known *skp; - if (req->peer_secid != 0) - ssp->smk_packet = smack_from_secid(req->peer_secid); - else + if (req->peer_secid != 0) { + skp = smack_from_secid(req->peer_secid); + ssp->smk_packet = skp->smk_known; + } else ssp->smk_packet = NULL; } @@ -3422,7 +3450,9 @@ static void smack_inet_csk_clone(struct sock *sk, static int smack_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) { - key->security = smk_of_task(cred->security); + struct smack_known *skp = smk_of_task(cred->security); + + key->security = skp->smk_known; return 0; } @@ -3451,7 +3481,7 @@ static int smack_key_permission(key_ref_t key_ref, { struct key *keyp; struct smk_audit_info ad; - char *tsp = smk_of_task(cred->security); + struct smack_known *tkp = smk_of_task(cred->security); keyp = key_ref_to_ptr(key_ref); if (keyp == NULL) @@ -3465,15 +3495,14 @@ static int smack_key_permission(key_ref_t key_ref, /* * This should not occur */ - if (tsp == NULL) + if (tkp == NULL) return -EACCES; #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY); ad.a.u.key_struct.key = keyp->serial; ad.a.u.key_struct.key_desc = keyp->description; #endif - return smk_access(tsp, keyp->security, - MAY_READWRITE, &ad); + return smk_access(tkp, keyp->security, MAY_READWRITE, &ad); } #endif /* CONFIG_KEYS */ @@ -3555,7 +3584,7 @@ static int smack_audit_rule_known(struct audit_krule *krule) static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, struct audit_context *actx) { - char *smack; + struct smack_known *skp; char *rule = vrule; if (!rule) { @@ -3567,7 +3596,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) return 0; - smack = smack_from_secid(secid); + skp = smack_from_secid(secid); /* * No need to do string comparisons. If a match occurs, @@ -3575,9 +3604,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, * label. */ if (op == Audit_equal) - return (rule == smack); + return (rule == skp->smk_known); if (op == Audit_not_equal) - return (rule != smack); + return (rule != skp->smk_known); return 0; } @@ -3605,11 +3634,11 @@ static void smack_audit_rule_free(void *vrule) */ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { - char *sp = smack_from_secid(secid); + struct smack_known *skp = smack_from_secid(secid); if (secdata) - *secdata = sp; - *seclen = strlen(sp); + *secdata = skp->smk_known; + *seclen = strlen(skp->smk_known); return 0; } @@ -3845,8 +3874,8 @@ static __init int smack_init(void) if (!security_module_enable(&smack_ops)) return 0; - tsp = new_task_smack(smack_known_floor.smk_known, - smack_known_floor.smk_known, GFP_KERNEL); + tsp = new_task_smack(&smack_known_floor, &smack_known_floor, + GFP_KERNEL); if (tsp == NULL) return -ENOMEM; -- cgit v1.2.3-18-g5258 From e830b39412ca2bbedd7508243f21c04d57ad543c Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 22 May 2013 18:43:07 -0700 Subject: Smack: Add smkfstransmute mount option Suppliment the smkfsroot mount option with another, smkfstransmute, that does the same thing but also marks the root inode as transmutting. This allows a freshly created filesystem to be mounted with a transmutting heirarchy. Targeted for git://git.gitorious.org/smack-next/kernel.git Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'security/smack/smack_lsm.c') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 3669d9f9824..6a083303501 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -261,8 +261,9 @@ static int smack_sb_alloc_security(struct super_block *sb) 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; - + /* + * smk_initialized will be zero from kzalloc. + */ sb->s_security = sbsp; return 0; @@ -306,6 +307,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts) dp = smackopts; else if (strstr(cp, SMK_FSROOT) == cp) dp = smackopts; + else if (strstr(cp, SMK_FSTRANS) == cp) + dp = smackopts; else dp = otheropts; @@ -341,8 +344,9 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) char *op; char *commap; char *nsp; + int transmute = 0; - if (sp->smk_initialized != 0) + if (sp->smk_initialized) return 0; sp->smk_initialized = 1; @@ -373,6 +377,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) nsp = smk_import(op, 0); if (nsp != NULL) sp->smk_root = nsp; + } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { + op += strlen(SMK_FSTRANS); + nsp = smk_import(op, 0); + if (nsp != NULL) { + sp->smk_root = nsp; + transmute = 1; + } } } @@ -380,11 +391,15 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) * Initialize the root inode. */ isp = inode->i_security; - if (isp == NULL) + if (inode->i_security == NULL) { inode->i_security = new_inode_smack(sp->smk_root); - else + isp = inode->i_security; + } else isp->smk_inode = sp->smk_root; + if (transmute) + isp->smk_flags |= SMK_INODE_TRANSMUTE; + return 0; } -- cgit v1.2.3-18-g5258