Merge branch 'next-smack' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull smack updates from James Morris:
 "Bug fixes for IPv6 handling and other issues and two memory use
  improvements."

* 'next-smack' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  Smack: Fix kbuild reported build error
  smack: Check address length before reading address family
  Smack: Fix IPv6 handling of 0 secmark
  Smack: Create smack_rule cache to optimize memory usage
  smack: removal of global rule list
This commit is contained in:
Linus Torvalds 2019-05-09 13:08:05 -07:00
commit 800c608c97
3 changed files with 45 additions and 45 deletions

View File

@ -348,6 +348,7 @@ extern struct list_head smack_onlycap_list;
#define SMACK_HASH_SLOTS 16 #define SMACK_HASH_SLOTS 16
extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; 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) static inline struct task_smack *smack_cred(const struct cred *cred)
{ {

View File

@ -59,6 +59,7 @@ DEFINE_MUTEX(smack_ipv6_lock);
static LIST_HEAD(smk_ipv6_port_list); static LIST_HEAD(smk_ipv6_port_list);
#endif #endif
static struct kmem_cache *smack_inode_cache; static struct kmem_cache *smack_inode_cache;
struct kmem_cache *smack_rule_cache;
int smack_enabled; int smack_enabled;
#define A(s) {"smack"#s, sizeof("smack"#s) - 1, Opt_##s} #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; int rc = 0;
list_for_each_entry_rcu(orp, ohead, list) { 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) { if (nrp == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
break; break;
@ -1931,7 +1932,7 @@ static void smack_cred_free(struct cred *cred)
list_for_each_safe(l, n, &tsp->smk_rules) { list_for_each_safe(l, n, &tsp->smk_rules) {
rp = list_entry(l, struct smack_rule, list); rp = list_entry(l, struct smack_rule, list);
list_del(&rp->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. * 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, static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
int addrlen) 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); smk_ipv6_port_label(sock, address);
}
return 0; return 0;
} }
#endif /* SMACK_IPV6_PORT_LABELING */ #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) { switch (sock->sk->sk_family) {
case PF_INET: case PF_INET:
if (addrlen < sizeof(struct sockaddr_in)) if (addrlen < sizeof(struct sockaddr_in) ||
sap->sa_family != AF_INET)
return -EINVAL; return -EINVAL;
rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
break; break;
case PF_INET6: case PF_INET6:
if (addrlen < sizeof(struct sockaddr_in6)) if (addrlen < SIN6_LEN_RFC2133 || sap->sa_family != AF_INET6)
return -EINVAL; return -EINVAL;
#ifdef SMACK_IPV6_SECMARK_LABELING #ifdef SMACK_IPV6_SECMARK_LABELING
rsp = smack_ipv6host_label(sip); 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) { switch (sock->sk->sk_family) {
case AF_INET: 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); rc = smack_netlabel_send(sock->sk, sip);
break; break;
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6: case AF_INET6:
if (msg->msg_namelen < SIN6_LEN_RFC2133 ||
sap->sin6_family != AF_INET6)
return -EINVAL;
#ifdef SMACK_IPV6_SECMARK_LABELING #ifdef SMACK_IPV6_SECMARK_LABELING
rsp = smack_ipv6host_label(sap); rsp = smack_ipv6host_label(sap);
if (rsp != NULL) if (rsp != NULL)
@ -3694,6 +3707,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
#ifdef SMACK_IPV6_PORT_LABELING #ifdef SMACK_IPV6_PORT_LABELING
rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
#endif #endif
#endif /* IS_ENABLED(CONFIG_IPV6) */
break; break;
} }
return rc; return rc;
@ -3906,6 +3920,8 @@ access_check:
#ifdef SMACK_IPV6_SECMARK_LABELING #ifdef SMACK_IPV6_SECMARK_LABELING
if (skb && skb->secmark != 0) if (skb && skb->secmark != 0)
skp = smack_from_secid(skb->secmark); skp = smack_from_secid(skb->secmark);
else if (smk_ipv6_localhost(&sadd))
break;
else else
skp = smack_ipv6host_label(&sadd); skp = smack_ipv6host_label(&sadd);
if (skp == NULL) if (skp == NULL)
@ -4758,6 +4774,12 @@ static __init int smack_init(void)
if (!smack_inode_cache) if (!smack_inode_cache)
return -ENOMEM; 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. * Set the security state for the initial task.
*/ */

View File

@ -67,7 +67,6 @@ enum smk_inos {
/* /*
* List locks * List locks
*/ */
static DEFINE_MUTEX(smack_master_list_lock);
static DEFINE_MUTEX(smack_cipso_lock); static DEFINE_MUTEX(smack_cipso_lock);
static DEFINE_MUTEX(smack_ambient_lock); static DEFINE_MUTEX(smack_ambient_lock);
static DEFINE_MUTEX(smk_net4addr_lock); static DEFINE_MUTEX(smk_net4addr_lock);
@ -134,15 +133,7 @@ LIST_HEAD(smk_net6addr_list);
/* /*
* Rule lists are maintained for each label. * 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_parsed_rule {
struct smack_known *smk_subject; struct smack_known *smk_subject;
struct smack_known *smk_object; 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 * @srp: the rule to add or replace
* @rule_list: the list of rules * @rule_list: the list of rules
* @rule_lock: the rule list lock * @rule_lock: the rule list lock
* @global: if non-zero, indicates a global rule
* *
* Looks through the current subject/object/access list for * Looks through the current subject/object/access list for
* the subject/object pair and replaces the access that was * 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, static int smk_set_access(struct smack_parsed_rule *srp,
struct list_head *rule_list, struct list_head *rule_list,
struct mutex *rule_lock, int global) struct mutex *rule_lock)
{ {
struct smack_rule *sp; struct smack_rule *sp;
struct smack_master_list *smlp;
int found = 0; int found = 0;
int rc = 0; int rc = 0;
@ -247,7 +236,7 @@ static int smk_set_access(struct smack_parsed_rule *srp,
} }
if (found == 0) { if (found == 0) {
sp = kzalloc(sizeof(*sp), GFP_KERNEL); sp = kmem_cache_zalloc(smack_rule_cache, GFP_KERNEL);
if (sp == NULL) { if (sp == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; 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; sp->smk_access = srp->smk_access1 & ~srp->smk_access2;
list_add_rcu(&sp->list, rule_list); 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: out:
@ -540,9 +513,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
if (rule_list == NULL) if (rule_list == NULL)
rc = smk_set_access(&rule, &rule.smk_subject->smk_rules, rc = smk_set_access(&rule, &rule.smk_subject->smk_rules,
&rule.smk_subject->smk_rules_lock, 1); &rule.smk_subject->smk_rules_lock);
else else
rc = smk_set_access(&rule, rule_list, rule_lock, 0); rc = smk_set_access(&rule, rule_list, rule_lock);
if (rc) if (rc)
goto out; 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) 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) 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) static int load_seq_show(struct seq_file *s, void *v)
{ {
struct list_head *list = v; struct list_head *list = v;
struct smack_master_list *smlp = struct smack_rule *srp;
list_entry_rcu(list, struct smack_master_list, list); 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; 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) static int load2_seq_show(struct seq_file *s, void *v)
{ {
struct list_head *list = v; struct list_head *list = v;
struct smack_master_list *smlp = struct smack_rule *srp;
list_entry_rcu(list, struct smack_master_list, list); 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; return 0;
} }