diff options
-rw-r--r-- | include/linux/security.h | 24 | ||||
-rw-r--r-- | include/net/xfrm.h | 3 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 2 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 2 | ||||
-rw-r--r-- | net/key/af_key.c | 5 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 7 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 9 | ||||
-rw-r--r-- | security/dummy.c | 3 | ||||
-rw-r--r-- | security/selinux/include/xfrm.h | 3 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 53 |
10 files changed, 62 insertions, 49 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index 9b5fea81f55..b200b9856f3 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -882,7 +882,8 @@ struct request_sock; | |||
882 | * Check permission when a flow selects a xfrm_policy for processing | 882 | * Check permission when a flow selects a xfrm_policy for processing |
883 | * XFRMs on a packet. The hook is called when selecting either a | 883 | * XFRMs on a packet. The hook is called when selecting either a |
884 | * per-socket policy or a generic xfrm policy. | 884 | * per-socket policy or a generic xfrm policy. |
885 | * Return 0 if permission is granted. | 885 | * Return 0 if permission is granted, -ESRCH otherwise, or -errno |
886 | * on other errors. | ||
886 | * @xfrm_state_pol_flow_match: | 887 | * @xfrm_state_pol_flow_match: |
887 | * @x contains the state to match. | 888 | * @x contains the state to match. |
888 | * @xp contains the policy to check for a match. | 889 | * @xp contains the policy to check for a match. |
@@ -891,6 +892,7 @@ struct request_sock; | |||
891 | * @xfrm_flow_state_match: | 892 | * @xfrm_flow_state_match: |
892 | * @fl contains the flow key to match. | 893 | * @fl contains the flow key to match. |
893 | * @xfrm points to the xfrm_state to match. | 894 | * @xfrm points to the xfrm_state to match. |
895 | * @xp points to the xfrm_policy to match. | ||
894 | * Return 1 if there is a match. | 896 | * Return 1 if there is a match. |
895 | * @xfrm_decode_session: | 897 | * @xfrm_decode_session: |
896 | * @skb points to skb to decode. | 898 | * @skb points to skb to decode. |
@@ -1388,7 +1390,8 @@ struct security_operations { | |||
1388 | int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); | 1390 | int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); |
1389 | int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, | 1391 | int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, |
1390 | struct xfrm_policy *xp, struct flowi *fl); | 1392 | struct xfrm_policy *xp, struct flowi *fl); |
1391 | int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm); | 1393 | int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm, |
1394 | struct xfrm_policy *xp); | ||
1392 | int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); | 1395 | int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); |
1393 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 1396 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
1394 | 1397 | ||
@@ -3120,11 +3123,6 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm | |||
3120 | return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL); | 3123 | return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL); |
3121 | } | 3124 | } |
3122 | 3125 | ||
3123 | static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) | ||
3124 | { | ||
3125 | return security_ops->xfrm_policy_alloc_security(xp, NULL, sk); | ||
3126 | } | ||
3127 | |||
3128 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | 3126 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) |
3129 | { | 3127 | { |
3130 | return security_ops->xfrm_policy_clone_security(old, new); | 3128 | return security_ops->xfrm_policy_clone_security(old, new); |
@@ -3175,9 +3173,10 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, | |||
3175 | return security_ops->xfrm_state_pol_flow_match(x, xp, fl); | 3173 | return security_ops->xfrm_state_pol_flow_match(x, xp, fl); |
3176 | } | 3174 | } |
3177 | 3175 | ||
3178 | static inline int security_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | 3176 | static inline int security_xfrm_flow_state_match(struct flowi *fl, |
3177 | struct xfrm_state *xfrm, struct xfrm_policy *xp) | ||
3179 | { | 3178 | { |
3180 | return security_ops->xfrm_flow_state_match(fl, xfrm); | 3179 | return security_ops->xfrm_flow_state_match(fl, xfrm, xp); |
3181 | } | 3180 | } |
3182 | 3181 | ||
3183 | static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) | 3182 | static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) |
@@ -3197,11 +3196,6 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm | |||
3197 | return 0; | 3196 | return 0; |
3198 | } | 3197 | } |
3199 | 3198 | ||
3200 | static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) | ||
3201 | { | ||
3202 | return 0; | ||
3203 | } | ||
3204 | |||
3205 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | 3199 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) |
3206 | { | 3200 | { |
3207 | return 0; | 3201 | return 0; |
@@ -3249,7 +3243,7 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, | |||
3249 | } | 3243 | } |
3250 | 3244 | ||
3251 | static inline int security_xfrm_flow_state_match(struct flowi *fl, | 3245 | static inline int security_xfrm_flow_state_match(struct flowi *fl, |
3252 | struct xfrm_state *xfrm) | 3246 | struct xfrm_state *xfrm, struct xfrm_policy *xp) |
3253 | { | 3247 | { |
3254 | return 1; | 3248 | return 1; |
3255 | } | 3249 | } |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 1e2a4ddec96..737fdb2ee8a 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -995,7 +995,8 @@ struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | |||
995 | int create, unsigned short family); | 995 | int create, unsigned short family); |
996 | extern void xfrm_policy_flush(u8 type); | 996 | extern void xfrm_policy_flush(u8 type); |
997 | extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); | 997 | extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); |
998 | extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family, int strict); | 998 | extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, |
999 | struct flowi *fl, int family, int strict); | ||
999 | extern void xfrm_init_pmtu(struct dst_entry *dst); | 1000 | extern void xfrm_init_pmtu(struct dst_entry *dst); |
1000 | 1001 | ||
1001 | extern wait_queue_head_t km_waitq; | 1002 | extern wait_queue_head_t km_waitq; |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 7a7a00147e5..1bed0cdf53e 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -52,7 +52,7 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
52 | xdst->u.rt.fl.fl4_dst == fl->fl4_dst && | 52 | xdst->u.rt.fl.fl4_dst == fl->fl4_dst && |
53 | xdst->u.rt.fl.fl4_src == fl->fl4_src && | 53 | xdst->u.rt.fl.fl4_src == fl->fl4_src && |
54 | xdst->u.rt.fl.fl4_tos == fl->fl4_tos && | 54 | xdst->u.rt.fl.fl4_tos == fl->fl4_tos && |
55 | xfrm_bundle_ok(xdst, fl, AF_INET, 0)) { | 55 | xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) { |
56 | dst_clone(dst); | 56 | dst_clone(dst); |
57 | break; | 57 | break; |
58 | } | 58 | } |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 6a252e2134d..73cee2ec07e 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -73,7 +73,7 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
73 | xdst->u.rt6.rt6i_src.plen); | 73 | xdst->u.rt6.rt6i_src.plen); |
74 | if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && | 74 | if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && |
75 | ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && | 75 | ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && |
76 | xfrm_bundle_ok(xdst, fl, AF_INET6, | 76 | xfrm_bundle_ok(policy, xdst, fl, AF_INET6, |
77 | (xdst->u.rt6.rt6i_dst.plen != 128 || | 77 | (xdst->u.rt6.rt6i_dst.plen != 128 || |
78 | xdst->u.rt6.rt6i_src.plen != 128))) { | 78 | xdst->u.rt6.rt6i_src.plen != 128))) { |
79 | dst_clone(dst); | 79 | dst_clone(dst); |
diff --git a/net/key/af_key.c b/net/key/af_key.c index ff98e70b093..20ff7cca1d0 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -2928,11 +2928,6 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, | |||
2928 | if (*dir) | 2928 | if (*dir) |
2929 | goto out; | 2929 | goto out; |
2930 | } | 2930 | } |
2931 | else { | ||
2932 | *dir = security_xfrm_sock_policy_alloc(xp, sk); | ||
2933 | if (*dir) | ||
2934 | goto out; | ||
2935 | } | ||
2936 | 2931 | ||
2937 | *dir = pol->sadb_x_policy_dir-1; | 2932 | *dir = pol->sadb_x_policy_dir-1; |
2938 | return xp; | 2933 | return xp; |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index fffdd34f3ba..695761ff132 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -1744,7 +1744,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) | |||
1744 | 1744 | ||
1745 | static int stale_bundle(struct dst_entry *dst) | 1745 | static int stale_bundle(struct dst_entry *dst) |
1746 | { | 1746 | { |
1747 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); | 1747 | return !xfrm_bundle_ok(NULL, (struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); |
1748 | } | 1748 | } |
1749 | 1749 | ||
1750 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) | 1750 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) |
@@ -1866,7 +1866,8 @@ EXPORT_SYMBOL(xfrm_init_pmtu); | |||
1866 | * still valid. | 1866 | * still valid. |
1867 | */ | 1867 | */ |
1868 | 1868 | ||
1869 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict) | 1869 | int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, |
1870 | struct flowi *fl, int family, int strict) | ||
1870 | { | 1871 | { |
1871 | struct dst_entry *dst = &first->u.dst; | 1872 | struct dst_entry *dst = &first->u.dst; |
1872 | struct xfrm_dst *last; | 1873 | struct xfrm_dst *last; |
@@ -1883,7 +1884,7 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int str | |||
1883 | 1884 | ||
1884 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) | 1885 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) |
1885 | return 0; | 1886 | return 0; |
1886 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm)) | 1887 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol)) |
1887 | return 0; | 1888 | return 0; |
1888 | if (dst->xfrm->km.state != XFRM_STATE_VALID) | 1889 | if (dst->xfrm->km.state != XFRM_STATE_VALID) |
1889 | return 0; | 1890 | return 0; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index d54b3a70d5d..2b2e59d8ffb 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1992,15 +1992,6 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, | |||
1992 | xp->type = XFRM_POLICY_TYPE_MAIN; | 1992 | xp->type = XFRM_POLICY_TYPE_MAIN; |
1993 | copy_templates(xp, ut, nr); | 1993 | copy_templates(xp, ut, nr); |
1994 | 1994 | ||
1995 | if (!xp->security) { | ||
1996 | int err = security_xfrm_sock_policy_alloc(xp, sk); | ||
1997 | if (err) { | ||
1998 | kfree(xp); | ||
1999 | *dir = err; | ||
2000 | return NULL; | ||
2001 | } | ||
2002 | } | ||
2003 | |||
2004 | *dir = p->dir; | 1995 | *dir = p->dir; |
2005 | 1996 | ||
2006 | return xp; | 1997 | return xp; |
diff --git a/security/dummy.c b/security/dummy.c index aeee7056550..43874c1e6e2 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -881,7 +881,8 @@ static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x, | |||
881 | return 1; | 881 | return 1; |
882 | } | 882 | } |
883 | 883 | ||
884 | static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | 884 | static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, |
885 | struct xfrm_policy *xp) | ||
885 | { | 886 | { |
886 | return 1; | 887 | return 1; |
887 | } | 888 | } |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 81eb5989016..526b28019ac 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
@@ -19,7 +19,8 @@ int selinux_xfrm_state_delete(struct xfrm_state *x); | |||
19 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); | 19 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); |
20 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, | 20 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, |
21 | struct xfrm_policy *xp, struct flowi *fl); | 21 | struct xfrm_policy *xp, struct flowi *fl); |
22 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm); | 22 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, |
23 | struct xfrm_policy *xp); | ||
23 | 24 | ||
24 | 25 | ||
25 | /* | 26 | /* |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 3e742b850af..675b995a67c 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -77,8 +77,8 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) | |||
77 | */ | 77 | */ |
78 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) | 78 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) |
79 | { | 79 | { |
80 | int rc = 0; | 80 | int rc; |
81 | u32 sel_sid = SECINITSID_UNLABELED; | 81 | u32 sel_sid; |
82 | struct xfrm_sec_ctx *ctx; | 82 | struct xfrm_sec_ctx *ctx; |
83 | 83 | ||
84 | /* Context sid is either set to label or ANY_ASSOC */ | 84 | /* Context sid is either set to label or ANY_ASSOC */ |
@@ -88,11 +88,21 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) | |||
88 | 88 | ||
89 | sel_sid = ctx->ctx_sid; | 89 | sel_sid = ctx->ctx_sid; |
90 | } | 90 | } |
91 | else | ||
92 | /* | ||
93 | * All flows should be treated as polmatch'ing an | ||
94 | * otherwise applicable "non-labeled" policy. This | ||
95 | * would prevent inadvertent "leaks". | ||
96 | */ | ||
97 | return 0; | ||
91 | 98 | ||
92 | rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, | 99 | rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, |
93 | ASSOCIATION__POLMATCH, | 100 | ASSOCIATION__POLMATCH, |
94 | NULL); | 101 | NULL); |
95 | 102 | ||
103 | if (rc == -EACCES) | ||
104 | rc = -ESRCH; | ||
105 | |||
96 | return rc; | 106 | return rc; |
97 | } | 107 | } |
98 | 108 | ||
@@ -108,15 +118,20 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * | |||
108 | u32 pol_sid; | 118 | u32 pol_sid; |
109 | int err; | 119 | int err; |
110 | 120 | ||
111 | if (x->security) | 121 | if (xp->security) { |
112 | state_sid = x->security->ctx_sid; | 122 | if (!x->security) |
113 | else | 123 | /* unlabeled SA and labeled policy can't match */ |
114 | state_sid = SECINITSID_UNLABELED; | 124 | return 0; |
115 | 125 | else | |
116 | if (xp->security) | 126 | state_sid = x->security->ctx_sid; |
117 | pol_sid = xp->security->ctx_sid; | 127 | pol_sid = xp->security->ctx_sid; |
118 | else | 128 | } else |
119 | pol_sid = SECINITSID_UNLABELED; | 129 | if (x->security) |
130 | /* unlabeled policy and labeled SA can't match */ | ||
131 | return 0; | ||
132 | else | ||
133 | /* unlabeled policy and unlabeled SA match all flows */ | ||
134 | return 1; | ||
120 | 135 | ||
121 | err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, | 136 | err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, |
122 | ASSOCIATION__POLMATCH, | 137 | ASSOCIATION__POLMATCH, |
@@ -125,7 +140,11 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * | |||
125 | if (err) | 140 | if (err) |
126 | return 0; | 141 | return 0; |
127 | 142 | ||
128 | return selinux_xfrm_flow_state_match(fl, x); | 143 | err = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, |
144 | ASSOCIATION__SENDTO, | ||
145 | NULL)? 0:1; | ||
146 | |||
147 | return err; | ||
129 | } | 148 | } |
130 | 149 | ||
131 | /* | 150 | /* |
@@ -133,12 +152,22 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * | |||
133 | * can use a given security association. | 152 | * can use a given security association. |
134 | */ | 153 | */ |
135 | 154 | ||
136 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | 155 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, |
156 | struct xfrm_policy *xp) | ||
137 | { | 157 | { |
138 | int rc = 0; | 158 | int rc = 0; |
139 | u32 sel_sid = SECINITSID_UNLABELED; | 159 | u32 sel_sid = SECINITSID_UNLABELED; |
140 | struct xfrm_sec_ctx *ctx; | 160 | struct xfrm_sec_ctx *ctx; |
141 | 161 | ||
162 | if (!xp->security) | ||
163 | if (!xfrm->security) | ||
164 | return 1; | ||
165 | else | ||
166 | return 0; | ||
167 | else | ||
168 | if (!xfrm->security) | ||
169 | return 0; | ||
170 | |||
142 | /* Context sid is either set to label or ANY_ASSOC */ | 171 | /* Context sid is either set to label or ANY_ASSOC */ |
143 | if ((ctx = xfrm->security)) { | 172 | if ((ctx = xfrm->security)) { |
144 | if (!selinux_authorizable_ctx(ctx)) | 173 | if (!selinux_authorizable_ctx(ctx)) |