diff options
-rw-r--r-- | include/linux/security.h | 19 | ||||
-rw-r--r-- | include/net/xfrm.h | 2 | ||||
-rw-r--r-- | net/key/af_key.c | 15 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 2 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 13 | ||||
-rw-r--r-- | security/dummy.c | 3 | ||||
-rw-r--r-- | security/selinux/include/xfrm.h | 3 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 33 |
8 files changed, 66 insertions, 24 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index f3909d189fe0..8e3dc6c51a6d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -827,8 +827,10 @@ struct swap_info_struct; | |||
827 | * used by the XFRM system. | 827 | * used by the XFRM system. |
828 | * @sec_ctx contains the security context information being provided by | 828 | * @sec_ctx contains the security context information being provided by |
829 | * the user-level policy update program (e.g., setkey). | 829 | * the user-level policy update program (e.g., setkey). |
830 | * @sk refers to the sock from which to derive the security context. | ||
830 | * Allocate a security structure to the xp->security field; the security | 831 | * Allocate a security structure to the xp->security field; the security |
831 | * field is initialized to NULL when the xfrm_policy is allocated. | 832 | * field is initialized to NULL when the xfrm_policy is allocated. Only |
833 | * one of sec_ctx or sock can be specified. | ||
832 | * Return 0 if operation was successful (memory to allocate, legal context) | 834 | * Return 0 if operation was successful (memory to allocate, legal context) |
833 | * @xfrm_policy_clone_security: | 835 | * @xfrm_policy_clone_security: |
834 | * @old contains an existing xfrm_policy in the SPD. | 836 | * @old contains an existing xfrm_policy in the SPD. |
@@ -1359,7 +1361,8 @@ struct security_operations { | |||
1359 | #endif /* CONFIG_SECURITY_NETWORK */ | 1361 | #endif /* CONFIG_SECURITY_NETWORK */ |
1360 | 1362 | ||
1361 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1363 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1362 | int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx); | 1364 | int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, |
1365 | struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); | ||
1363 | int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); | 1366 | int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); |
1364 | void (*xfrm_policy_free_security) (struct xfrm_policy *xp); | 1367 | void (*xfrm_policy_free_security) (struct xfrm_policy *xp); |
1365 | int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); | 1368 | int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); |
@@ -3057,7 +3060,12 @@ static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl) | |||
3057 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 3060 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
3058 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | 3061 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) |
3059 | { | 3062 | { |
3060 | return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); | 3063 | return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL); |
3064 | } | ||
3065 | |||
3066 | static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) | ||
3067 | { | ||
3068 | return security_ops->xfrm_policy_alloc_security(xp, NULL, sk); | ||
3061 | } | 3069 | } |
3062 | 3070 | ||
3063 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | 3071 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) |
@@ -3132,6 +3140,11 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm | |||
3132 | return 0; | 3140 | return 0; |
3133 | } | 3141 | } |
3134 | 3142 | ||
3143 | static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) | ||
3144 | { | ||
3145 | return 0; | ||
3146 | } | ||
3147 | |||
3135 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | 3148 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) |
3136 | { | 3149 | { |
3137 | return 0; | 3150 | return 0; |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 3ecd9fa1ed4b..00bf86e6e82b 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -362,7 +362,7 @@ struct xfrm_mgr | |||
362 | char *id; | 362 | char *id; |
363 | int (*notify)(struct xfrm_state *x, struct km_event *c); | 363 | int (*notify)(struct xfrm_state *x, struct km_event *c); |
364 | int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); | 364 | int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); |
365 | struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir); | 365 | struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir); |
366 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); | 366 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); |
367 | int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); | 367 | int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); |
368 | }; | 368 | }; |
diff --git a/net/key/af_key.c b/net/key/af_key.c index a065e1a67773..797c744a8438 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -2843,14 +2843,14 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct | |||
2843 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); | 2843 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); |
2844 | } | 2844 | } |
2845 | 2845 | ||
2846 | static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | 2846 | static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, |
2847 | u8 *data, int len, int *dir) | 2847 | u8 *data, int len, int *dir) |
2848 | { | 2848 | { |
2849 | struct xfrm_policy *xp; | 2849 | struct xfrm_policy *xp; |
2850 | struct sadb_x_policy *pol = (struct sadb_x_policy*)data; | 2850 | struct sadb_x_policy *pol = (struct sadb_x_policy*)data; |
2851 | struct sadb_x_sec_ctx *sec_ctx; | 2851 | struct sadb_x_sec_ctx *sec_ctx; |
2852 | 2852 | ||
2853 | switch (family) { | 2853 | switch (sk->sk_family) { |
2854 | case AF_INET: | 2854 | case AF_INET: |
2855 | if (opt != IP_IPSEC_POLICY) { | 2855 | if (opt != IP_IPSEC_POLICY) { |
2856 | *dir = -EOPNOTSUPP; | 2856 | *dir = -EOPNOTSUPP; |
@@ -2891,7 +2891,7 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
2891 | xp->lft.hard_byte_limit = XFRM_INF; | 2891 | xp->lft.hard_byte_limit = XFRM_INF; |
2892 | xp->lft.soft_packet_limit = XFRM_INF; | 2892 | xp->lft.soft_packet_limit = XFRM_INF; |
2893 | xp->lft.hard_packet_limit = XFRM_INF; | 2893 | xp->lft.hard_packet_limit = XFRM_INF; |
2894 | xp->family = family; | 2894 | xp->family = sk->sk_family; |
2895 | 2895 | ||
2896 | xp->xfrm_nr = 0; | 2896 | xp->xfrm_nr = 0; |
2897 | if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && | 2897 | if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && |
@@ -2907,8 +2907,10 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
2907 | p += pol->sadb_x_policy_len*8; | 2907 | p += pol->sadb_x_policy_len*8; |
2908 | sec_ctx = (struct sadb_x_sec_ctx *)p; | 2908 | sec_ctx = (struct sadb_x_sec_ctx *)p; |
2909 | if (len < pol->sadb_x_policy_len*8 + | 2909 | if (len < pol->sadb_x_policy_len*8 + |
2910 | sec_ctx->sadb_x_sec_len) | 2910 | sec_ctx->sadb_x_sec_len) { |
2911 | *dir = -EINVAL; | ||
2911 | goto out; | 2912 | goto out; |
2913 | } | ||
2912 | if ((*dir = verify_sec_ctx_len(p))) | 2914 | if ((*dir = verify_sec_ctx_len(p))) |
2913 | goto out; | 2915 | goto out; |
2914 | uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | 2916 | uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); |
@@ -2918,6 +2920,11 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
2918 | if (*dir) | 2920 | if (*dir) |
2919 | goto out; | 2921 | goto out; |
2920 | } | 2922 | } |
2923 | else { | ||
2924 | *dir = security_xfrm_sock_policy_alloc(xp, sk); | ||
2925 | if (*dir) | ||
2926 | goto out; | ||
2927 | } | ||
2921 | 2928 | ||
2922 | *dir = pol->sadb_x_policy_dir-1; | 2929 | *dir = pol->sadb_x_policy_dir-1; |
2923 | return xp; | 2930 | return xp; |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index be02bd981d12..1c796087ee78 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -1026,7 +1026,7 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen | |||
1026 | err = -EINVAL; | 1026 | err = -EINVAL; |
1027 | read_lock(&xfrm_km_lock); | 1027 | read_lock(&xfrm_km_lock); |
1028 | list_for_each_entry(km, &xfrm_km_list, list) { | 1028 | list_for_each_entry(km, &xfrm_km_list, list) { |
1029 | pol = km->compile_policy(sk->sk_family, optname, data, | 1029 | pol = km->compile_policy(sk, optname, data, |
1030 | optlen, &err); | 1030 | optlen, &err); |
1031 | if (err >= 0) | 1031 | if (err >= 0) |
1032 | break; | 1032 | break; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index dac8db1088bc..f70e158874d2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1757,7 +1757,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
1757 | /* User gives us xfrm_user_policy_info followed by an array of 0 | 1757 | /* User gives us xfrm_user_policy_info followed by an array of 0 |
1758 | * or more templates. | 1758 | * or more templates. |
1759 | */ | 1759 | */ |
1760 | static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | 1760 | static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, |
1761 | u8 *data, int len, int *dir) | 1761 | u8 *data, int len, int *dir) |
1762 | { | 1762 | { |
1763 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; | 1763 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; |
@@ -1765,7 +1765,7 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1765 | struct xfrm_policy *xp; | 1765 | struct xfrm_policy *xp; |
1766 | int nr; | 1766 | int nr; |
1767 | 1767 | ||
1768 | switch (family) { | 1768 | switch (sk->sk_family) { |
1769 | case AF_INET: | 1769 | case AF_INET: |
1770 | if (opt != IP_XFRM_POLICY) { | 1770 | if (opt != IP_XFRM_POLICY) { |
1771 | *dir = -EOPNOTSUPP; | 1771 | *dir = -EOPNOTSUPP; |
@@ -1807,6 +1807,15 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1807 | copy_from_user_policy(xp, p); | 1807 | copy_from_user_policy(xp, p); |
1808 | copy_templates(xp, ut, nr); | 1808 | copy_templates(xp, ut, nr); |
1809 | 1809 | ||
1810 | if (!xp->security) { | ||
1811 | int err = security_xfrm_sock_policy_alloc(xp, sk); | ||
1812 | if (err) { | ||
1813 | kfree(xp); | ||
1814 | *dir = err; | ||
1815 | return NULL; | ||
1816 | } | ||
1817 | } | ||
1818 | |||
1810 | *dir = p->dir; | 1819 | *dir = p->dir; |
1811 | 1820 | ||
1812 | return xp; | 1821 | return xp; |
diff --git a/security/dummy.c b/security/dummy.c index c0ff6b9bfd7d..66cc06404930 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -815,7 +815,8 @@ static inline void dummy_sk_getsecid(struct sock *sk, u32 *secid) | |||
815 | #endif /* CONFIG_SECURITY_NETWORK */ | 815 | #endif /* CONFIG_SECURITY_NETWORK */ |
816 | 816 | ||
817 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 817 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
818 | static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | 818 | static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, |
819 | struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk) | ||
819 | { | 820 | { |
820 | return 0; | 821 | return 0; |
821 | } | 822 | } |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 8e45c1d588a8..1822c73e5085 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
@@ -7,7 +7,8 @@ | |||
7 | #ifndef _SELINUX_XFRM_H_ | 7 | #ifndef _SELINUX_XFRM_H_ |
8 | #define _SELINUX_XFRM_H_ | 8 | #define _SELINUX_XFRM_H_ |
9 | 9 | ||
10 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx); | 10 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, |
11 | struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); | ||
11 | int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); | 12 | int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); |
12 | void selinux_xfrm_policy_free(struct xfrm_policy *xp); | 13 | void selinux_xfrm_policy_free(struct xfrm_policy *xp); |
13 | int selinux_xfrm_policy_delete(struct xfrm_policy *xp); | 14 | int selinux_xfrm_policy_delete(struct xfrm_policy *xp); |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index c750ef7af66f..d3690f985135 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -208,10 +208,8 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, | |||
208 | 208 | ||
209 | BUG_ON(uctx && pol); | 209 | BUG_ON(uctx && pol); |
210 | 210 | ||
211 | if (pol) | 211 | if (!uctx) |
212 | goto from_policy; | 212 | goto not_from_user; |
213 | |||
214 | BUG_ON(!uctx); | ||
215 | 213 | ||
216 | if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) | 214 | if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) |
217 | return -EINVAL; | 215 | return -EINVAL; |
@@ -251,11 +249,14 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, | |||
251 | 249 | ||
252 | return rc; | 250 | return rc; |
253 | 251 | ||
254 | from_policy: | 252 | not_from_user: |
255 | BUG_ON(!pol); | 253 | if (pol) { |
256 | rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid); | 254 | rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid); |
257 | if (rc) | 255 | if (rc) |
258 | goto out; | 256 | goto out; |
257 | } | ||
258 | else | ||
259 | ctx_sid = sid; | ||
259 | 260 | ||
260 | rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len); | 261 | rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len); |
261 | if (rc) | 262 | if (rc) |
@@ -293,13 +294,23 @@ out2: | |||
293 | * LSM hook implementation that allocs and transfers uctx spec to | 294 | * LSM hook implementation that allocs and transfers uctx spec to |
294 | * xfrm_policy. | 295 | * xfrm_policy. |
295 | */ | 296 | */ |
296 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *uctx) | 297 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, |
298 | struct xfrm_user_sec_ctx *uctx, struct sock *sk) | ||
297 | { | 299 | { |
298 | int err; | 300 | int err; |
301 | u32 sid; | ||
299 | 302 | ||
300 | BUG_ON(!xp); | 303 | BUG_ON(!xp); |
304 | BUG_ON(uctx && sk); | ||
305 | |||
306 | if (sk) { | ||
307 | struct sk_security_struct *ssec = sk->sk_security; | ||
308 | sid = ssec->sid; | ||
309 | } | ||
310 | else | ||
311 | sid = SECSID_NULL; | ||
301 | 312 | ||
302 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, 0); | 313 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, sid); |
303 | return err; | 314 | return err; |
304 | } | 315 | } |
305 | 316 | ||