diff --git a/security/smack/smack.h b/security/smack/smack.h index cf52af77d15e..e41ca1d58484 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -348,6 +348,7 @@ extern struct list_head smack_onlycap_list; #define SMACK_HASH_SLOTS 16 extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; +extern struct kmem_cache *smack_rule_cache; static inline struct task_smack *smack_cred(const struct cred *cred) { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 5c1613519d5a..0de725f88bed 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -59,6 +59,7 @@ DEFINE_MUTEX(smack_ipv6_lock); static LIST_HEAD(smk_ipv6_port_list); #endif static struct kmem_cache *smack_inode_cache; +struct kmem_cache *smack_rule_cache; int smack_enabled; #define A(s) {"smack"#s, sizeof("smack"#s) - 1, Opt_##s} @@ -354,7 +355,7 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, int rc = 0; list_for_each_entry_rcu(orp, ohead, list) { - nrp = kzalloc(sizeof(struct smack_rule), gfp); + nrp = kmem_cache_zalloc(smack_rule_cache, gfp); if (nrp == NULL) { rc = -ENOMEM; break; @@ -1931,7 +1932,7 @@ static void smack_cred_free(struct cred *cred) list_for_each_safe(l, n, &tsp->smk_rules) { rp = list_entry(l, struct smack_rule, list); list_del(&rp->list); - kfree(rp); + kmem_cache_free(smack_rule_cache, rp); } } @@ -2805,13 +2806,17 @@ static int smack_socket_socketpair(struct socket *socka, * * Records the label bound to a port. * - * Returns 0 + * Returns 0 on success, and error code otherwise */ static int smack_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { - if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) + if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) { + if (addrlen < SIN6_LEN_RFC2133 || + address->sa_family != AF_INET6) + return -EINVAL; smk_ipv6_port_label(sock, address); + } return 0; } #endif /* SMACK_IPV6_PORT_LABELING */ @@ -2847,12 +2852,13 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, switch (sock->sk->sk_family) { case PF_INET: - if (addrlen < sizeof(struct sockaddr_in)) + if (addrlen < sizeof(struct sockaddr_in) || + sap->sa_family != AF_INET) return -EINVAL; rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); break; case PF_INET6: - if (addrlen < sizeof(struct sockaddr_in6)) + if (addrlen < SIN6_LEN_RFC2133 || sap->sa_family != AF_INET6) return -EINVAL; #ifdef SMACK_IPV6_SECMARK_LABELING rsp = smack_ipv6host_label(sip); @@ -3682,9 +3688,16 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, switch (sock->sk->sk_family) { case AF_INET: + if (msg->msg_namelen < sizeof(struct sockaddr_in) || + sip->sin_family != AF_INET) + return -EINVAL; rc = smack_netlabel_send(sock->sk, sip); break; +#if IS_ENABLED(CONFIG_IPV6) case AF_INET6: + if (msg->msg_namelen < SIN6_LEN_RFC2133 || + sap->sin6_family != AF_INET6) + return -EINVAL; #ifdef SMACK_IPV6_SECMARK_LABELING rsp = smack_ipv6host_label(sap); if (rsp != NULL) @@ -3694,6 +3707,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, #ifdef SMACK_IPV6_PORT_LABELING rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); #endif +#endif /* IS_ENABLED(CONFIG_IPV6) */ break; } return rc; @@ -3906,6 +3920,8 @@ access_check: #ifdef SMACK_IPV6_SECMARK_LABELING if (skb && skb->secmark != 0) skp = smack_from_secid(skb->secmark); + else if (smk_ipv6_localhost(&sadd)) + break; else skp = smack_ipv6host_label(&sadd); if (skp == NULL) @@ -4758,6 +4774,12 @@ static __init int smack_init(void) if (!smack_inode_cache) return -ENOMEM; + smack_rule_cache = KMEM_CACHE(smack_rule, 0); + if (!smack_rule_cache) { + kmem_cache_destroy(smack_inode_cache); + return -ENOMEM; + } + /* * Set the security state for the initial task. */ diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index faf2ea3968b3..47f73a0dabb1 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -67,7 +67,6 @@ enum smk_inos { /* * List locks */ -static DEFINE_MUTEX(smack_master_list_lock); static DEFINE_MUTEX(smack_cipso_lock); static DEFINE_MUTEX(smack_ambient_lock); static DEFINE_MUTEX(smk_net4addr_lock); @@ -134,15 +133,7 @@ LIST_HEAD(smk_net6addr_list); /* * Rule lists are maintained for each label. - * This master list is just for reading /smack/load and /smack/load2. */ -struct smack_master_list { - struct list_head list; - struct smack_rule *smk_rule; -}; - -static LIST_HEAD(smack_rule_list); - struct smack_parsed_rule { struct smack_known *smk_subject; struct smack_known *smk_object; @@ -211,7 +202,6 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) * @srp: the rule to add or replace * @rule_list: the list of rules * @rule_lock: the rule list lock - * @global: if non-zero, indicates a global rule * * Looks through the current subject/object/access list for * the subject/object pair and replaces the access that was @@ -223,10 +213,9 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) */ static int smk_set_access(struct smack_parsed_rule *srp, struct list_head *rule_list, - struct mutex *rule_lock, int global) + struct mutex *rule_lock) { struct smack_rule *sp; - struct smack_master_list *smlp; int found = 0; int rc = 0; @@ -247,7 +236,7 @@ static int smk_set_access(struct smack_parsed_rule *srp, } if (found == 0) { - sp = kzalloc(sizeof(*sp), GFP_KERNEL); + sp = kmem_cache_zalloc(smack_rule_cache, GFP_KERNEL); if (sp == NULL) { rc = -ENOMEM; goto out; @@ -258,22 +247,6 @@ static int smk_set_access(struct smack_parsed_rule *srp, sp->smk_access = srp->smk_access1 & ~srp->smk_access2; list_add_rcu(&sp->list, rule_list); - /* - * If this is a global as opposed to self and a new rule - * it needs to get added for reporting. - */ - if (global) { - mutex_unlock(rule_lock); - smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); - if (smlp != NULL) { - smlp->smk_rule = sp; - mutex_lock(&smack_master_list_lock); - list_add_rcu(&smlp->list, &smack_rule_list); - mutex_unlock(&smack_master_list_lock); - } else - rc = -ENOMEM; - return rc; - } } out: @@ -540,9 +513,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, if (rule_list == NULL) rc = smk_set_access(&rule, &rule.smk_subject->smk_rules, - &rule.smk_subject->smk_rules_lock, 1); + &rule.smk_subject->smk_rules_lock); else - rc = smk_set_access(&rule, rule_list, rule_lock, 0); + rc = smk_set_access(&rule, rule_list, rule_lock); if (rc) goto out; @@ -636,21 +609,23 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) static void *load2_seq_start(struct seq_file *s, loff_t *pos) { - return smk_seq_start(s, pos, &smack_rule_list); + return smk_seq_start(s, pos, &smack_known_list); } static void *load2_seq_next(struct seq_file *s, void *v, loff_t *pos) { - return smk_seq_next(s, v, pos, &smack_rule_list); + return smk_seq_next(s, v, pos, &smack_known_list); } static int load_seq_show(struct seq_file *s, void *v) { struct list_head *list = v; - struct smack_master_list *smlp = - list_entry_rcu(list, struct smack_master_list, list); + struct smack_rule *srp; + struct smack_known *skp = + list_entry_rcu(list, struct smack_known, list); - smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); + list_for_each_entry_rcu(srp, &skp->smk_rules, list) + smk_rule_show(s, srp, SMK_LABELLEN); return 0; } @@ -2352,10 +2327,12 @@ static const struct file_operations smk_access_ops = { static int load2_seq_show(struct seq_file *s, void *v) { struct list_head *list = v; - struct smack_master_list *smlp = - list_entry_rcu(list, struct smack_master_list, list); + struct smack_rule *srp; + struct smack_known *skp = + list_entry_rcu(list, struct smack_known, list); - smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); + list_for_each_entry_rcu(srp, &skp->smk_rules, list) + smk_rule_show(s, srp, SMK_LONGLABEL); return 0; }