diff options
author | Casey Schaufler <casey@schaufler-ca.com> | 2014-04-10 19:37:08 -0400 |
---|---|---|
committer | Casey Schaufler <casey@schaufler-ca.com> | 2014-04-11 17:35:28 -0400 |
commit | 54e70ec5eb090193b03e69d551fa6771a5a217c4 (patch) | |
tree | f015da7353f4824800a5fc6a89442f37628f62d1 /security/smack | |
parent | f59bdfba3e2b0ba5182f23d96101d106f18132ca (diff) |
Smack: bidirectional UDS connect check
Smack IPC policy requires that the sender have write access
to the receiver. UDS streams don't do per-packet checks. The
only check is done at connect time. The existing code checks
if the connecting process can write to the other, but not the
other way around. This change adds a check that the other end
can write to the connecting process.
Targeted for git://git.gitorious.org/smack-next/kernel.git
Signed-off-by: Casey Schuafler <casey@schaufler-ca.com>
Diffstat (limited to 'security/smack')
-rw-r--r-- | security/smack/smack.h | 6 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 44 |
2 files changed, 27 insertions, 23 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h index fade085b1128..020307ef0972 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -80,8 +80,8 @@ struct superblock_smack { | |||
80 | 80 | ||
81 | struct socket_smack { | 81 | struct socket_smack { |
82 | struct smack_known *smk_out; /* outbound label */ | 82 | struct smack_known *smk_out; /* outbound label */ |
83 | char *smk_in; /* inbound label */ | 83 | struct smack_known *smk_in; /* inbound label */ |
84 | char *smk_packet; /* TCP peer label */ | 84 | struct smack_known *smk_packet; /* TCP peer label */ |
85 | }; | 85 | }; |
86 | 86 | ||
87 | /* | 87 | /* |
@@ -133,7 +133,7 @@ struct smk_port_label { | |||
133 | struct list_head list; | 133 | struct list_head list; |
134 | struct sock *smk_sock; /* socket initialized on */ | 134 | struct sock *smk_sock; /* socket initialized on */ |
135 | unsigned short smk_port; /* the port number */ | 135 | unsigned short smk_port; /* the port number */ |
136 | char *smk_in; /* incoming label */ | 136 | struct smack_known *smk_in; /* inbound label */ |
137 | struct smack_known *smk_out; /* outgoing label */ | 137 | struct smack_known *smk_out; /* outgoing label */ |
138 | }; | 138 | }; |
139 | 139 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 3d1c9086d0d6..3410e3abd19b 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -1095,7 +1095,7 @@ static int smack_inode_getsecurity(const struct inode *inode, | |||
1095 | ssp = sock->sk->sk_security; | 1095 | ssp = sock->sk->sk_security; |
1096 | 1096 | ||
1097 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) | 1097 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) |
1098 | isp = ssp->smk_in; | 1098 | isp = ssp->smk_in->smk_known; |
1099 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) | 1099 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) |
1100 | isp = ssp->smk_out->smk_known; | 1100 | isp = ssp->smk_out->smk_known; |
1101 | else | 1101 | else |
@@ -1859,7 +1859,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) | |||
1859 | if (ssp == NULL) | 1859 | if (ssp == NULL) |
1860 | return -ENOMEM; | 1860 | return -ENOMEM; |
1861 | 1861 | ||
1862 | ssp->smk_in = skp->smk_known; | 1862 | ssp->smk_in = skp; |
1863 | ssp->smk_out = skp; | 1863 | ssp->smk_out = skp; |
1864 | ssp->smk_packet = NULL; | 1864 | ssp->smk_packet = NULL; |
1865 | 1865 | ||
@@ -2099,7 +2099,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | |||
2099 | 2099 | ||
2100 | if (act == SMK_RECEIVING) { | 2100 | if (act == SMK_RECEIVING) { |
2101 | skp = smack_net_ambient; | 2101 | skp = smack_net_ambient; |
2102 | object = ssp->smk_in; | 2102 | object = ssp->smk_in->smk_known; |
2103 | } else { | 2103 | } else { |
2104 | skp = ssp->smk_out; | 2104 | skp = ssp->smk_out; |
2105 | object = smack_net_ambient->smk_known; | 2105 | object = smack_net_ambient->smk_known; |
@@ -2129,9 +2129,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | |||
2129 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { | 2129 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { |
2130 | if (spp->smk_port != port) | 2130 | if (spp->smk_port != port) |
2131 | continue; | 2131 | continue; |
2132 | object = spp->smk_in; | 2132 | object = spp->smk_in->smk_known; |
2133 | if (act == SMK_CONNECTING) | 2133 | if (act == SMK_CONNECTING) |
2134 | ssp->smk_packet = spp->smk_out->smk_known; | 2134 | ssp->smk_packet = spp->smk_out; |
2135 | break; | 2135 | break; |
2136 | } | 2136 | } |
2137 | 2137 | ||
@@ -2195,7 +2195,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
2195 | ssp = sock->sk->sk_security; | 2195 | ssp = sock->sk->sk_security; |
2196 | 2196 | ||
2197 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) | 2197 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) |
2198 | ssp->smk_in = skp->smk_known; | 2198 | ssp->smk_in = skp; |
2199 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { | 2199 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { |
2200 | ssp->smk_out = skp; | 2200 | ssp->smk_out = skp; |
2201 | if (sock->sk->sk_family == PF_INET) { | 2201 | if (sock->sk->sk_family == PF_INET) { |
@@ -3054,30 +3054,34 @@ static int smack_unix_stream_connect(struct sock *sock, | |||
3054 | struct sock *other, struct sock *newsk) | 3054 | struct sock *other, struct sock *newsk) |
3055 | { | 3055 | { |
3056 | struct smack_known *skp; | 3056 | struct smack_known *skp; |
3057 | struct smack_known *okp; | ||
3057 | struct socket_smack *ssp = sock->sk_security; | 3058 | struct socket_smack *ssp = sock->sk_security; |
3058 | struct socket_smack *osp = other->sk_security; | 3059 | struct socket_smack *osp = other->sk_security; |
3059 | struct socket_smack *nsp = newsk->sk_security; | 3060 | struct socket_smack *nsp = newsk->sk_security; |
3060 | struct smk_audit_info ad; | 3061 | struct smk_audit_info ad; |
3061 | int rc = 0; | 3062 | int rc = 0; |
3062 | |||
3063 | #ifdef CONFIG_AUDIT | 3063 | #ifdef CONFIG_AUDIT |
3064 | struct lsm_network_audit net; | 3064 | struct lsm_network_audit net; |
3065 | |||
3066 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
3067 | smk_ad_setfield_u_net_sk(&ad, other); | ||
3068 | #endif | 3065 | #endif |
3069 | 3066 | ||
3070 | if (!smack_privileged(CAP_MAC_OVERRIDE)) { | 3067 | if (!smack_privileged(CAP_MAC_OVERRIDE)) { |
3071 | skp = ssp->smk_out; | 3068 | skp = ssp->smk_out; |
3072 | rc = smk_access(skp, osp->smk_in, MAY_WRITE, &ad); | 3069 | okp = osp->smk_out; |
3070 | #ifdef CONFIG_AUDIT | ||
3071 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
3072 | smk_ad_setfield_u_net_sk(&ad, other); | ||
3073 | #endif | ||
3074 | rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad); | ||
3075 | if (rc == 0) | ||
3076 | rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL); | ||
3073 | } | 3077 | } |
3074 | 3078 | ||
3075 | /* | 3079 | /* |
3076 | * Cross reference the peer labels for SO_PEERSEC. | 3080 | * Cross reference the peer labels for SO_PEERSEC. |
3077 | */ | 3081 | */ |
3078 | if (rc == 0) { | 3082 | if (rc == 0) { |
3079 | nsp->smk_packet = ssp->smk_out->smk_known; | 3083 | nsp->smk_packet = ssp->smk_out; |
3080 | ssp->smk_packet = osp->smk_out->smk_known; | 3084 | ssp->smk_packet = osp->smk_out; |
3081 | } | 3085 | } |
3082 | 3086 | ||
3083 | return rc; | 3087 | return rc; |
@@ -3109,7 +3113,7 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) | |||
3109 | return 0; | 3113 | return 0; |
3110 | 3114 | ||
3111 | skp = ssp->smk_out; | 3115 | skp = ssp->smk_out; |
3112 | return smk_access(skp, osp->smk_in, MAY_WRITE, &ad); | 3116 | return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad); |
3113 | } | 3117 | } |
3114 | 3118 | ||
3115 | /** | 3119 | /** |
@@ -3204,7 +3208,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
3204 | if (found) | 3208 | if (found) |
3205 | return skp; | 3209 | return skp; |
3206 | 3210 | ||
3207 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) | 3211 | if (ssp != NULL && ssp->smk_in == &smack_known_star) |
3208 | return &smack_known_web; | 3212 | return &smack_known_web; |
3209 | return &smack_known_star; | 3213 | return &smack_known_star; |
3210 | } | 3214 | } |
@@ -3323,7 +3327,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3323 | * This is the simplist possible security model | 3327 | * This is the simplist possible security model |
3324 | * for networking. | 3328 | * for networking. |
3325 | */ | 3329 | */ |
3326 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); | 3330 | rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); |
3327 | if (rc != 0) | 3331 | if (rc != 0) |
3328 | netlbl_skbuff_err(skb, rc, 0); | 3332 | netlbl_skbuff_err(skb, rc, 0); |
3329 | break; | 3333 | break; |
@@ -3358,7 +3362,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock, | |||
3358 | 3362 | ||
3359 | ssp = sock->sk->sk_security; | 3363 | ssp = sock->sk->sk_security; |
3360 | if (ssp->smk_packet != NULL) { | 3364 | if (ssp->smk_packet != NULL) { |
3361 | rcp = ssp->smk_packet; | 3365 | rcp = ssp->smk_packet->smk_known; |
3362 | slen = strlen(rcp) + 1; | 3366 | slen = strlen(rcp) + 1; |
3363 | } | 3367 | } |
3364 | 3368 | ||
@@ -3443,7 +3447,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) | |||
3443 | return; | 3447 | return; |
3444 | 3448 | ||
3445 | ssp = sk->sk_security; | 3449 | ssp = sk->sk_security; |
3446 | ssp->smk_in = skp->smk_known; | 3450 | ssp->smk_in = skp; |
3447 | ssp->smk_out = skp; | 3451 | ssp->smk_out = skp; |
3448 | /* cssp->smk_packet is already set in smack_inet_csk_clone() */ | 3452 | /* cssp->smk_packet is already set in smack_inet_csk_clone() */ |
3449 | } | 3453 | } |
@@ -3503,7 +3507,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3503 | * Receiving a packet requires that the other end be able to write | 3507 | * Receiving a packet requires that the other end be able to write |
3504 | * here. Read access is not required. | 3508 | * here. Read access is not required. |
3505 | */ | 3509 | */ |
3506 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); | 3510 | rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); |
3507 | if (rc != 0) | 3511 | if (rc != 0) |
3508 | return rc; | 3512 | return rc; |
3509 | 3513 | ||
@@ -3547,7 +3551,7 @@ static void smack_inet_csk_clone(struct sock *sk, | |||
3547 | 3551 | ||
3548 | if (req->peer_secid != 0) { | 3552 | if (req->peer_secid != 0) { |
3549 | skp = smack_from_secid(req->peer_secid); | 3553 | skp = smack_from_secid(req->peer_secid); |
3550 | ssp->smk_packet = skp->smk_known; | 3554 | ssp->smk_packet = skp; |
3551 | } else | 3555 | } else |
3552 | ssp->smk_packet = NULL; | 3556 | ssp->smk_packet = NULL; |
3553 | } | 3557 | } |