diff options
| -rw-r--r-- | include/linux/pfkeyv2.h | 13 | ||||
| -rw-r--r-- | include/linux/security.h | 132 | ||||
| -rw-r--r-- | include/linux/xfrm.h | 29 | ||||
| -rw-r--r-- | include/net/flow.h | 7 | ||||
| -rw-r--r-- | include/net/xfrm.h | 27 | ||||
| -rw-r--r-- | net/core/flow.c | 8 | ||||
| -rw-r--r-- | net/key/af_key.c | 197 | ||||
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 88 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 9 | ||||
| -rw-r--r-- | net/xfrm/xfrm_user.c | 148 | ||||
| -rw-r--r-- | security/Kconfig | 13 | ||||
| -rw-r--r-- | security/dummy.c | 45 |
12 files changed, 655 insertions, 61 deletions
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 724066778aff..6351c4055ace 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h | |||
| @@ -216,6 +216,16 @@ struct sadb_x_nat_t_port { | |||
| 216 | } __attribute__((packed)); | 216 | } __attribute__((packed)); |
| 217 | /* sizeof(struct sadb_x_nat_t_port) == 8 */ | 217 | /* sizeof(struct sadb_x_nat_t_port) == 8 */ |
| 218 | 218 | ||
| 219 | /* Generic LSM security context */ | ||
| 220 | struct sadb_x_sec_ctx { | ||
| 221 | uint16_t sadb_x_sec_len; | ||
| 222 | uint16_t sadb_x_sec_exttype; | ||
| 223 | uint8_t sadb_x_ctx_alg; /* LSMs: e.g., selinux == 1 */ | ||
| 224 | uint8_t sadb_x_ctx_doi; | ||
| 225 | uint16_t sadb_x_ctx_len; | ||
| 226 | } __attribute__((packed)); | ||
| 227 | /* sizeof(struct sadb_sec_ctx) = 8 */ | ||
| 228 | |||
| 219 | /* Message types */ | 229 | /* Message types */ |
| 220 | #define SADB_RESERVED 0 | 230 | #define SADB_RESERVED 0 |
| 221 | #define SADB_GETSPI 1 | 231 | #define SADB_GETSPI 1 |
| @@ -325,7 +335,8 @@ struct sadb_x_nat_t_port { | |||
| 325 | #define SADB_X_EXT_NAT_T_SPORT 21 | 335 | #define SADB_X_EXT_NAT_T_SPORT 21 |
| 326 | #define SADB_X_EXT_NAT_T_DPORT 22 | 336 | #define SADB_X_EXT_NAT_T_DPORT 22 |
| 327 | #define SADB_X_EXT_NAT_T_OA 23 | 337 | #define SADB_X_EXT_NAT_T_OA 23 |
| 328 | #define SADB_EXT_MAX 23 | 338 | #define SADB_X_EXT_SEC_CTX 24 |
| 339 | #define SADB_EXT_MAX 24 | ||
| 329 | 340 | ||
| 330 | /* Identity Extension values */ | 341 | /* Identity Extension values */ |
| 331 | #define SADB_IDENTTYPE_RESERVED 0 | 342 | #define SADB_IDENTTYPE_RESERVED 0 |
diff --git a/include/linux/security.h b/include/linux/security.h index f7e0ae018712..ef753654daa5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -59,6 +59,12 @@ struct sk_buff; | |||
| 59 | struct sock; | 59 | struct sock; |
| 60 | struct sockaddr; | 60 | struct sockaddr; |
| 61 | struct socket; | 61 | struct socket; |
| 62 | struct flowi; | ||
| 63 | struct dst_entry; | ||
| 64 | struct xfrm_selector; | ||
| 65 | struct xfrm_policy; | ||
| 66 | struct xfrm_state; | ||
| 67 | struct xfrm_user_sec_ctx; | ||
| 62 | 68 | ||
| 63 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); | 69 | extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); |
| 64 | extern int cap_netlink_recv(struct sk_buff *skb); | 70 | extern int cap_netlink_recv(struct sk_buff *skb); |
| @@ -788,6 +794,52 @@ struct swap_info_struct; | |||
| 788 | * which is used to copy security attributes between local stream sockets. | 794 | * which is used to copy security attributes between local stream sockets. |
| 789 | * @sk_free_security: | 795 | * @sk_free_security: |
| 790 | * Deallocate security structure. | 796 | * Deallocate security structure. |
| 797 | * @sk_getsid: | ||
| 798 | * Retrieve the LSM-specific sid for the sock to enable caching of network | ||
| 799 | * authorizations. | ||
| 800 | * | ||
| 801 | * Security hooks for XFRM operations. | ||
| 802 | * | ||
| 803 | * @xfrm_policy_alloc_security: | ||
| 804 | * @xp contains the xfrm_policy being added to Security Policy Database | ||
| 805 | * used by the XFRM system. | ||
| 806 | * @sec_ctx contains the security context information being provided by | ||
| 807 | * the user-level policy update program (e.g., setkey). | ||
| 808 | * Allocate a security structure to the xp->selector.security field. | ||
| 809 | * The security field is initialized to NULL when the xfrm_policy is | ||
| 810 | * allocated. | ||
| 811 | * Return 0 if operation was successful (memory to allocate, legal context) | ||
| 812 | * @xfrm_policy_clone_security: | ||
| 813 | * @old contains an existing xfrm_policy in the SPD. | ||
| 814 | * @new contains a new xfrm_policy being cloned from old. | ||
| 815 | * Allocate a security structure to the new->selector.security field | ||
| 816 | * that contains the information from the old->selector.security field. | ||
| 817 | * Return 0 if operation was successful (memory to allocate). | ||
| 818 | * @xfrm_policy_free_security: | ||
| 819 | * @xp contains the xfrm_policy | ||
| 820 | * Deallocate xp->selector.security. | ||
| 821 | * @xfrm_state_alloc_security: | ||
| 822 | * @x contains the xfrm_state being added to the Security Association | ||
| 823 | * Database by the XFRM system. | ||
| 824 | * @sec_ctx contains the security context information being provided by | ||
| 825 | * the user-level SA generation program (e.g., setkey or racoon). | ||
| 826 | * Allocate a security structure to the x->sel.security field. The | ||
| 827 | * security field is initialized to NULL when the xfrm_state is | ||
| 828 | * allocated. | ||
| 829 | * Return 0 if operation was successful (memory to allocate, legal context). | ||
| 830 | * @xfrm_state_free_security: | ||
| 831 | * @x contains the xfrm_state. | ||
| 832 | * Deallocate x>sel.security. | ||
| 833 | * @xfrm_policy_lookup: | ||
| 834 | * @xp contains the xfrm_policy for which the access control is being | ||
| 835 | * checked. | ||
| 836 | * @sk_sid contains the sock security label that is used to authorize | ||
| 837 | * access to the policy xp. | ||
| 838 | * @dir contains the direction of the flow (input or output). | ||
| 839 | * Check permission when a sock selects a xfrm_policy for processing | ||
| 840 | * XFRMs on a packet. The hook is called when selecting either a | ||
| 841 | * per-socket policy or a generic xfrm policy. | ||
| 842 | * Return 0 if permission is granted. | ||
| 791 | * | 843 | * |
| 792 | * Security hooks affecting all Key Management operations | 844 | * Security hooks affecting all Key Management operations |
| 793 | * | 845 | * |
| @@ -1237,8 +1289,18 @@ struct security_operations { | |||
| 1237 | int (*socket_getpeersec) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len); | 1289 | int (*socket_getpeersec) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len); |
| 1238 | int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); | 1290 | int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); |
| 1239 | void (*sk_free_security) (struct sock *sk); | 1291 | void (*sk_free_security) (struct sock *sk); |
| 1292 | unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir); | ||
| 1240 | #endif /* CONFIG_SECURITY_NETWORK */ | 1293 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1241 | 1294 | ||
| 1295 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | ||
| 1296 | int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx); | ||
| 1297 | int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); | ||
| 1298 | void (*xfrm_policy_free_security) (struct xfrm_policy *xp); | ||
| 1299 | int (*xfrm_state_alloc_security) (struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); | ||
| 1300 | void (*xfrm_state_free_security) (struct xfrm_state *x); | ||
| 1301 | int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 sk_sid, u8 dir); | ||
| 1302 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | ||
| 1303 | |||
| 1242 | /* key management security hooks */ | 1304 | /* key management security hooks */ |
| 1243 | #ifdef CONFIG_KEYS | 1305 | #ifdef CONFIG_KEYS |
| 1244 | int (*key_alloc)(struct key *key); | 1306 | int (*key_alloc)(struct key *key); |
| @@ -2679,6 +2741,11 @@ static inline void security_sk_free(struct sock *sk) | |||
| 2679 | { | 2741 | { |
| 2680 | return security_ops->sk_free_security(sk); | 2742 | return security_ops->sk_free_security(sk); |
| 2681 | } | 2743 | } |
| 2744 | |||
| 2745 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) | ||
| 2746 | { | ||
| 2747 | return security_ops->sk_getsid(sk, fl, dir); | ||
| 2748 | } | ||
| 2682 | #else /* CONFIG_SECURITY_NETWORK */ | 2749 | #else /* CONFIG_SECURITY_NETWORK */ |
| 2683 | static inline int security_unix_stream_connect(struct socket * sock, | 2750 | static inline int security_unix_stream_connect(struct socket * sock, |
| 2684 | struct socket * other, | 2751 | struct socket * other, |
| @@ -2795,8 +2862,73 @@ static inline int security_sk_alloc(struct sock *sk, int family, gfp_t priority) | |||
| 2795 | static inline void security_sk_free(struct sock *sk) | 2862 | static inline void security_sk_free(struct sock *sk) |
| 2796 | { | 2863 | { |
| 2797 | } | 2864 | } |
| 2865 | |||
| 2866 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) | ||
| 2867 | { | ||
| 2868 | return 0; | ||
| 2869 | } | ||
| 2798 | #endif /* CONFIG_SECURITY_NETWORK */ | 2870 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 2799 | 2871 | ||
| 2872 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | ||
| 2873 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | ||
| 2874 | { | ||
| 2875 | return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); | ||
| 2876 | } | ||
| 2877 | |||
| 2878 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | ||
| 2879 | { | ||
| 2880 | return security_ops->xfrm_policy_clone_security(old, new); | ||
| 2881 | } | ||
| 2882 | |||
| 2883 | static inline void security_xfrm_policy_free(struct xfrm_policy *xp) | ||
| 2884 | { | ||
| 2885 | security_ops->xfrm_policy_free_security(xp); | ||
| 2886 | } | ||
| 2887 | |||
| 2888 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | ||
| 2889 | { | ||
| 2890 | return security_ops->xfrm_state_alloc_security(x, sec_ctx); | ||
| 2891 | } | ||
| 2892 | |||
| 2893 | static inline void security_xfrm_state_free(struct xfrm_state *x) | ||
| 2894 | { | ||
| 2895 | security_ops->xfrm_state_free_security(x); | ||
| 2896 | } | ||
| 2897 | |||
| 2898 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | ||
| 2899 | { | ||
| 2900 | return security_ops->xfrm_policy_lookup(xp, sk_sid, dir); | ||
| 2901 | } | ||
| 2902 | #else /* CONFIG_SECURITY_NETWORK_XFRM */ | ||
| 2903 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | ||
| 2904 | { | ||
| 2905 | return 0; | ||
| 2906 | } | ||
| 2907 | |||
| 2908 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | ||
| 2909 | { | ||
| 2910 | return 0; | ||
| 2911 | } | ||
| 2912 | |||
| 2913 | static inline void security_xfrm_policy_free(struct xfrm_policy *xp) | ||
| 2914 | { | ||
| 2915 | } | ||
| 2916 | |||
| 2917 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | ||
| 2918 | { | ||
| 2919 | return 0; | ||
| 2920 | } | ||
| 2921 | |||
| 2922 | static inline void security_xfrm_state_free(struct xfrm_state *x) | ||
| 2923 | { | ||
| 2924 | } | ||
| 2925 | |||
| 2926 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | ||
| 2927 | { | ||
| 2928 | return 0; | ||
| 2929 | } | ||
| 2930 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | ||
| 2931 | |||
| 2800 | #ifdef CONFIG_KEYS | 2932 | #ifdef CONFIG_KEYS |
| 2801 | #ifdef CONFIG_SECURITY | 2933 | #ifdef CONFIG_SECURITY |
| 2802 | static inline int security_key_alloc(struct key *key) | 2934 | static inline int security_key_alloc(struct key *key) |
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 0fb077d68441..82fbb758e28f 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
| @@ -27,6 +27,22 @@ struct xfrm_id | |||
| 27 | __u8 proto; | 27 | __u8 proto; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | struct xfrm_sec_ctx { | ||
| 31 | __u8 ctx_doi; | ||
| 32 | __u8 ctx_alg; | ||
| 33 | __u16 ctx_len; | ||
| 34 | __u32 ctx_sid; | ||
| 35 | char ctx_str[0]; | ||
| 36 | }; | ||
| 37 | |||
| 38 | /* Security Context Domains of Interpretation */ | ||
| 39 | #define XFRM_SC_DOI_RESERVED 0 | ||
| 40 | #define XFRM_SC_DOI_LSM 1 | ||
| 41 | |||
| 42 | /* Security Context Algorithms */ | ||
| 43 | #define XFRM_SC_ALG_RESERVED 0 | ||
| 44 | #define XFRM_SC_ALG_SELINUX 1 | ||
| 45 | |||
| 30 | /* Selector, used as selector both on policy rules (SPD) and SAs. */ | 46 | /* Selector, used as selector both on policy rules (SPD) and SAs. */ |
| 31 | 47 | ||
| 32 | struct xfrm_selector | 48 | struct xfrm_selector |
| @@ -146,6 +162,18 @@ enum { | |||
| 146 | 162 | ||
| 147 | #define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE) | 163 | #define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE) |
| 148 | 164 | ||
| 165 | /* | ||
| 166 | * Generic LSM security context for comunicating to user space | ||
| 167 | * NOTE: Same format as sadb_x_sec_ctx | ||
| 168 | */ | ||
| 169 | struct xfrm_user_sec_ctx { | ||
| 170 | __u16 len; | ||
| 171 | __u16 exttype; | ||
| 172 | __u8 ctx_alg; /* LSMs: e.g., selinux == 1 */ | ||
| 173 | __u8 ctx_doi; | ||
| 174 | __u16 ctx_len; | ||
| 175 | }; | ||
| 176 | |||
| 149 | struct xfrm_user_tmpl { | 177 | struct xfrm_user_tmpl { |
| 150 | struct xfrm_id id; | 178 | struct xfrm_id id; |
| 151 | __u16 family; | 179 | __u16 family; |
| @@ -176,6 +204,7 @@ enum xfrm_attr_type_t { | |||
| 176 | XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */ | 204 | XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */ |
| 177 | XFRMA_SA, | 205 | XFRMA_SA, |
| 178 | XFRMA_POLICY, | 206 | XFRMA_POLICY, |
| 207 | XFRMA_SEC_CTX, /* struct xfrm_sec_ctx */ | ||
| 179 | __XFRMA_MAX | 208 | __XFRMA_MAX |
| 180 | 209 | ||
| 181 | #define XFRMA_MAX (__XFRMA_MAX - 1) | 210 | #define XFRMA_MAX (__XFRMA_MAX - 1) |
diff --git a/include/net/flow.h b/include/net/flow.h index 9a5c94b1a0ec..ec7eb86eb203 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
| @@ -84,11 +84,12 @@ struct flowi { | |||
| 84 | #define FLOW_DIR_OUT 1 | 84 | #define FLOW_DIR_OUT 1 |
| 85 | #define FLOW_DIR_FWD 2 | 85 | #define FLOW_DIR_FWD 2 |
| 86 | 86 | ||
| 87 | typedef void (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir, | 87 | struct sock; |
| 88 | typedef void (*flow_resolve_t)(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | ||
| 88 | void **objp, atomic_t **obj_refp); | 89 | void **objp, atomic_t **obj_refp); |
| 89 | 90 | ||
| 90 | extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, | 91 | extern void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, |
| 91 | flow_resolve_t resolver); | 92 | flow_resolve_t resolver); |
| 92 | extern void flow_cache_flush(void); | 93 | extern void flow_cache_flush(void); |
| 93 | extern atomic_t flow_cache_genid; | 94 | extern atomic_t flow_cache_genid; |
| 94 | 95 | ||
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 1cdb87912137..487abca3ca6f 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -144,6 +144,9 @@ struct xfrm_state | |||
| 144 | * transformer. */ | 144 | * transformer. */ |
| 145 | struct xfrm_type *type; | 145 | struct xfrm_type *type; |
| 146 | 146 | ||
| 147 | /* Security context */ | ||
| 148 | struct xfrm_sec_ctx *security; | ||
| 149 | |||
| 147 | /* Private data of this transformer, format is opaque, | 150 | /* Private data of this transformer, format is opaque, |
| 148 | * interpreted by xfrm_type methods. */ | 151 | * interpreted by xfrm_type methods. */ |
| 149 | void *data; | 152 | void *data; |
| @@ -298,6 +301,7 @@ struct xfrm_policy | |||
| 298 | __u8 flags; | 301 | __u8 flags; |
| 299 | __u8 dead; | 302 | __u8 dead; |
| 300 | __u8 xfrm_nr; | 303 | __u8 xfrm_nr; |
| 304 | struct xfrm_sec_ctx *security; | ||
| 301 | struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; | 305 | struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; |
| 302 | }; | 306 | }; |
| 303 | 307 | ||
| @@ -510,6 +514,25 @@ xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, | |||
| 510 | return 0; | 514 | return 0; |
| 511 | } | 515 | } |
| 512 | 516 | ||
| 517 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | ||
| 518 | /* If neither has a context --> match | ||
| 519 | * Otherwise, both must have a context and the sids, doi, alg must match | ||
| 520 | */ | ||
| 521 | static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) | ||
| 522 | { | ||
| 523 | return ((!s1 && !s2) || | ||
| 524 | (s1 && s2 && | ||
| 525 | (s1->ctx_sid == s2->ctx_sid) && | ||
| 526 | (s1->ctx_doi == s2->ctx_doi) && | ||
| 527 | (s1->ctx_alg == s2->ctx_alg))); | ||
| 528 | } | ||
| 529 | #else | ||
| 530 | static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) | ||
| 531 | { | ||
| 532 | return 1; | ||
| 533 | } | ||
| 534 | #endif | ||
| 535 | |||
| 513 | /* A struct encoding bundle of transformations to apply to some set of flow. | 536 | /* A struct encoding bundle of transformations to apply to some set of flow. |
| 514 | * | 537 | * |
| 515 | * dst->child points to the next element of bundle. | 538 | * dst->child points to the next element of bundle. |
| @@ -878,8 +901,8 @@ static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsig | |||
| 878 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); | 901 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); |
| 879 | extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *); | 902 | extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *); |
| 880 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); | 903 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); |
| 881 | struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, | 904 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, |
| 882 | int delete); | 905 | struct xfrm_sec_ctx *ctx, int delete); |
| 883 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); | 906 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); |
| 884 | void xfrm_policy_flush(void); | 907 | void xfrm_policy_flush(void); |
| 885 | u32 xfrm_get_acqseq(void); | 908 | u32 xfrm_get_acqseq(void); |
diff --git a/net/core/flow.c b/net/core/flow.c index 7e95b39de9fd..c4f25385029f 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <net/flow.h> | 23 | #include <net/flow.h> |
| 24 | #include <asm/atomic.h> | 24 | #include <asm/atomic.h> |
| 25 | #include <asm/semaphore.h> | 25 | #include <asm/semaphore.h> |
| 26 | #include <linux/security.h> | ||
| 26 | 27 | ||
| 27 | struct flow_cache_entry { | 28 | struct flow_cache_entry { |
| 28 | struct flow_cache_entry *next; | 29 | struct flow_cache_entry *next; |
| @@ -30,6 +31,7 @@ struct flow_cache_entry { | |||
| 30 | u8 dir; | 31 | u8 dir; |
| 31 | struct flowi key; | 32 | struct flowi key; |
| 32 | u32 genid; | 33 | u32 genid; |
| 34 | u32 sk_sid; | ||
| 33 | void *object; | 35 | void *object; |
| 34 | atomic_t *object_ref; | 36 | atomic_t *object_ref; |
| 35 | }; | 37 | }; |
| @@ -162,7 +164,7 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2) | |||
| 162 | return 0; | 164 | return 0; |
| 163 | } | 165 | } |
| 164 | 166 | ||
| 165 | void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, | 167 | void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, |
| 166 | flow_resolve_t resolver) | 168 | flow_resolve_t resolver) |
| 167 | { | 169 | { |
| 168 | struct flow_cache_entry *fle, **head; | 170 | struct flow_cache_entry *fle, **head; |
| @@ -186,6 +188,7 @@ void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, | |||
| 186 | for (fle = *head; fle; fle = fle->next) { | 188 | for (fle = *head; fle; fle = fle->next) { |
| 187 | if (fle->family == family && | 189 | if (fle->family == family && |
| 188 | fle->dir == dir && | 190 | fle->dir == dir && |
| 191 | fle->sk_sid == sk_sid && | ||
| 189 | flow_key_compare(key, &fle->key) == 0) { | 192 | flow_key_compare(key, &fle->key) == 0) { |
| 190 | if (fle->genid == atomic_read(&flow_cache_genid)) { | 193 | if (fle->genid == atomic_read(&flow_cache_genid)) { |
| 191 | void *ret = fle->object; | 194 | void *ret = fle->object; |
| @@ -210,6 +213,7 @@ void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, | |||
| 210 | *head = fle; | 213 | *head = fle; |
| 211 | fle->family = family; | 214 | fle->family = family; |
| 212 | fle->dir = dir; | 215 | fle->dir = dir; |
| 216 | fle->sk_sid = sk_sid; | ||
| 213 | memcpy(&fle->key, key, sizeof(*key)); | 217 | memcpy(&fle->key, key, sizeof(*key)); |
| 214 | fle->object = NULL; | 218 | fle->object = NULL; |
| 215 | flow_count(cpu)++; | 219 | flow_count(cpu)++; |
| @@ -221,7 +225,7 @@ nocache: | |||
| 221 | void *obj; | 225 | void *obj; |
| 222 | atomic_t *obj_ref; | 226 | atomic_t *obj_ref; |
| 223 | 227 | ||
| 224 | resolver(key, family, dir, &obj, &obj_ref); | 228 | resolver(key, sk_sid, family, dir, &obj, &obj_ref); |
| 225 | 229 | ||
| 226 | if (fle) { | 230 | if (fle) { |
| 227 | fle->genid = atomic_read(&flow_cache_genid); | 231 | fle->genid = atomic_read(&flow_cache_genid); |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 39031684b65c..d32f7791f1e4 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
| @@ -336,6 +336,7 @@ static u8 sadb_ext_min_len[] = { | |||
| 336 | [SADB_X_EXT_NAT_T_SPORT] = (u8) sizeof(struct sadb_x_nat_t_port), | 336 | [SADB_X_EXT_NAT_T_SPORT] = (u8) sizeof(struct sadb_x_nat_t_port), |
| 337 | [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), | 337 | [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), |
| 338 | [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), | 338 | [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), |
| 339 | [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), | ||
| 339 | }; | 340 | }; |
| 340 | 341 | ||
| 341 | /* Verify sadb_address_{len,prefixlen} against sa_family. */ | 342 | /* Verify sadb_address_{len,prefixlen} against sa_family. */ |
| @@ -383,6 +384,55 @@ static int verify_address_len(void *p) | |||
| 383 | return 0; | 384 | return 0; |
| 384 | } | 385 | } |
| 385 | 386 | ||
| 387 | static inline int pfkey_sec_ctx_len(struct sadb_x_sec_ctx *sec_ctx) | ||
| 388 | { | ||
| 389 | int len = 0; | ||
| 390 | |||
| 391 | len += sizeof(struct sadb_x_sec_ctx); | ||
| 392 | len += sec_ctx->sadb_x_ctx_len; | ||
| 393 | len += sizeof(uint64_t) - 1; | ||
| 394 | len /= sizeof(uint64_t); | ||
| 395 | |||
| 396 | return len; | ||
| 397 | } | ||
| 398 | |||
| 399 | static inline int verify_sec_ctx_len(void *p) | ||
| 400 | { | ||
| 401 | struct sadb_x_sec_ctx *sec_ctx = (struct sadb_x_sec_ctx *)p; | ||
| 402 | int len; | ||
| 403 | |||
| 404 | if (sec_ctx->sadb_x_ctx_len > PAGE_SIZE) | ||
| 405 | return -EINVAL; | ||
| 406 | |||
| 407 | len = pfkey_sec_ctx_len(sec_ctx); | ||
| 408 | |||
| 409 | if (sec_ctx->sadb_x_sec_len != len) | ||
| 410 | return -EINVAL; | ||
| 411 | |||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(struct sadb_x_sec_ctx *sec_ctx) | ||
| 416 | { | ||
| 417 | struct xfrm_user_sec_ctx *uctx = NULL; | ||
| 418 | int ctx_size = sec_ctx->sadb_x_ctx_len; | ||
| 419 | |||
| 420 | uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL); | ||
| 421 | |||
| 422 | if (!uctx) | ||
| 423 | return NULL; | ||
| 424 | |||
| 425 | uctx->len = pfkey_sec_ctx_len(sec_ctx); | ||
| 426 | uctx->exttype = sec_ctx->sadb_x_sec_exttype; | ||
| 427 | uctx->ctx_doi = sec_ctx->sadb_x_ctx_doi; | ||
| 428 | uctx->ctx_alg = sec_ctx->sadb_x_ctx_alg; | ||
| 429 | uctx->ctx_len = sec_ctx->sadb_x_ctx_len; | ||
| 430 | memcpy(uctx + 1, sec_ctx + 1, | ||
| 431 | uctx->ctx_len); | ||
| 432 | |||
| 433 | return uctx; | ||
| 434 | } | ||
| 435 | |||
| 386 | static int present_and_same_family(struct sadb_address *src, | 436 | static int present_and_same_family(struct sadb_address *src, |
| 387 | struct sadb_address *dst) | 437 | struct sadb_address *dst) |
| 388 | { | 438 | { |
| @@ -438,6 +488,10 @@ static int parse_exthdrs(struct sk_buff *skb, struct sadb_msg *hdr, void **ext_h | |||
| 438 | if (verify_address_len(p)) | 488 | if (verify_address_len(p)) |
| 439 | return -EINVAL; | 489 | return -EINVAL; |
| 440 | } | 490 | } |
| 491 | if (ext_type == SADB_X_EXT_SEC_CTX) { | ||
| 492 | if (verify_sec_ctx_len(p)) | ||
| 493 | return -EINVAL; | ||
| 494 | } | ||
| 441 | ext_hdrs[ext_type-1] = p; | 495 | ext_hdrs[ext_type-1] = p; |
| 442 | } | 496 | } |
| 443 | p += ext_len; | 497 | p += ext_len; |
| @@ -586,6 +640,9 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, | |||
| 586 | struct sadb_key *key; | 640 | struct sadb_key *key; |
| 587 | struct sadb_x_sa2 *sa2; | 641 | struct sadb_x_sa2 *sa2; |
| 588 | struct sockaddr_in *sin; | 642 | struct sockaddr_in *sin; |
| 643 | struct sadb_x_sec_ctx *sec_ctx; | ||
| 644 | struct xfrm_sec_ctx *xfrm_ctx; | ||
| 645 | int ctx_size = 0; | ||
| 589 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 646 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 590 | struct sockaddr_in6 *sin6; | 647 | struct sockaddr_in6 *sin6; |
| 591 | #endif | 648 | #endif |
| @@ -609,6 +666,12 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, | |||
| 609 | sizeof(struct sadb_address)*2 + | 666 | sizeof(struct sadb_address)*2 + |
| 610 | sockaddr_size*2 + | 667 | sockaddr_size*2 + |
| 611 | sizeof(struct sadb_x_sa2); | 668 | sizeof(struct sadb_x_sa2); |
| 669 | |||
| 670 | if ((xfrm_ctx = x->security)) { | ||
| 671 | ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); | ||
| 672 | size += sizeof(struct sadb_x_sec_ctx) + ctx_size; | ||
| 673 | } | ||
| 674 | |||
| 612 | /* identity & sensitivity */ | 675 | /* identity & sensitivity */ |
| 613 | 676 | ||
| 614 | if ((x->props.family == AF_INET && | 677 | if ((x->props.family == AF_INET && |
| @@ -899,6 +962,20 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, | |||
| 899 | n_port->sadb_x_nat_t_port_reserved = 0; | 962 | n_port->sadb_x_nat_t_port_reserved = 0; |
| 900 | } | 963 | } |
| 901 | 964 | ||
| 965 | /* security context */ | ||
| 966 | if (xfrm_ctx) { | ||
| 967 | sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, | ||
| 968 | sizeof(struct sadb_x_sec_ctx) + ctx_size); | ||
| 969 | sec_ctx->sadb_x_sec_len = | ||
| 970 | (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t); | ||
| 971 | sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; | ||
| 972 | sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; | ||
| 973 | sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; | ||
| 974 | sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; | ||
| 975 | memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, | ||
| 976 | xfrm_ctx->ctx_len); | ||
| 977 | } | ||
| 978 | |||
| 902 | return skb; | 979 | return skb; |
| 903 | } | 980 | } |
| 904 | 981 | ||
| @@ -909,6 +986,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, | |||
| 909 | struct sadb_lifetime *lifetime; | 986 | struct sadb_lifetime *lifetime; |
| 910 | struct sadb_sa *sa; | 987 | struct sadb_sa *sa; |
| 911 | struct sadb_key *key; | 988 | struct sadb_key *key; |
| 989 | struct sadb_x_sec_ctx *sec_ctx; | ||
| 912 | uint16_t proto; | 990 | uint16_t proto; |
| 913 | int err; | 991 | int err; |
| 914 | 992 | ||
| @@ -993,6 +1071,21 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, | |||
| 993 | x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; | 1071 | x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; |
| 994 | x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; | 1072 | x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; |
| 995 | } | 1073 | } |
| 1074 | |||
| 1075 | sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; | ||
| 1076 | if (sec_ctx != NULL) { | ||
| 1077 | struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | ||
| 1078 | |||
| 1079 | if (!uctx) | ||
| 1080 | goto out; | ||
| 1081 | |||
| 1082 | err = security_xfrm_state_alloc(x, uctx); | ||
| 1083 | kfree(uctx); | ||
| 1084 | |||
| 1085 | if (err) | ||
| 1086 | goto out; | ||
| 1087 | } | ||
| 1088 | |||
| 996 | key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; | 1089 | key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; |
| 997 | if (sa->sadb_sa_auth) { | 1090 | if (sa->sadb_sa_auth) { |
| 998 | int keysize = 0; | 1091 | int keysize = 0; |
| @@ -1720,6 +1813,18 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol) | |||
| 1720 | return 0; | 1813 | return 0; |
| 1721 | } | 1814 | } |
| 1722 | 1815 | ||
| 1816 | static inline int pfkey_xfrm_policy2sec_ctx_size(struct xfrm_policy *xp) | ||
| 1817 | { | ||
| 1818 | struct xfrm_sec_ctx *xfrm_ctx = xp->security; | ||
| 1819 | |||
| 1820 | if (xfrm_ctx) { | ||
| 1821 | int len = sizeof(struct sadb_x_sec_ctx); | ||
| 1822 | len += xfrm_ctx->ctx_len; | ||
| 1823 | return PFKEY_ALIGN8(len); | ||
| 1824 | } | ||
| 1825 | return 0; | ||
| 1826 | } | ||
| 1827 | |||
| 1723 | static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp) | 1828 | static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp) |
| 1724 | { | 1829 | { |
| 1725 | int sockaddr_size = pfkey_sockaddr_size(xp->family); | 1830 | int sockaddr_size = pfkey_sockaddr_size(xp->family); |
| @@ -1733,7 +1838,8 @@ static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp) | |||
| 1733 | (sockaddr_size * 2) + | 1838 | (sockaddr_size * 2) + |
| 1734 | sizeof(struct sadb_x_policy) + | 1839 | sizeof(struct sadb_x_policy) + |
| 1735 | (xp->xfrm_nr * (sizeof(struct sadb_x_ipsecrequest) + | 1840 | (xp->xfrm_nr * (sizeof(struct sadb_x_ipsecrequest) + |
| 1736 | (socklen * 2))); | 1841 | (socklen * 2))) + |
| 1842 | pfkey_xfrm_policy2sec_ctx_size(xp); | ||
| 1737 | } | 1843 | } |
| 1738 | 1844 | ||
| 1739 | static struct sk_buff * pfkey_xfrm_policy2msg_prep(struct xfrm_policy *xp) | 1845 | static struct sk_buff * pfkey_xfrm_policy2msg_prep(struct xfrm_policy *xp) |
| @@ -1757,6 +1863,8 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i | |||
| 1757 | struct sadb_lifetime *lifetime; | 1863 | struct sadb_lifetime *lifetime; |
| 1758 | struct sadb_x_policy *pol; | 1864 | struct sadb_x_policy *pol; |
| 1759 | struct sockaddr_in *sin; | 1865 | struct sockaddr_in *sin; |
| 1866 | struct sadb_x_sec_ctx *sec_ctx; | ||
| 1867 | struct xfrm_sec_ctx *xfrm_ctx; | ||
| 1760 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 1868 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 1761 | struct sockaddr_in6 *sin6; | 1869 | struct sockaddr_in6 *sin6; |
| 1762 | #endif | 1870 | #endif |
| @@ -1941,6 +2049,21 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i | |||
| 1941 | } | 2049 | } |
| 1942 | } | 2050 | } |
| 1943 | } | 2051 | } |
| 2052 | |||
| 2053 | /* security context */ | ||
| 2054 | if ((xfrm_ctx = xp->security)) { | ||
| 2055 | int ctx_size = pfkey_xfrm_policy2sec_ctx_size(xp); | ||
| 2056 | |||
| 2057 | sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, ctx_size); | ||
| 2058 | sec_ctx->sadb_x_sec_len = ctx_size / sizeof(uint64_t); | ||
| 2059 | sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; | ||
| 2060 | sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; | ||
| 2061 | sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; | ||
| 2062 | sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; | ||
| 2063 | memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, | ||
| 2064 | xfrm_ctx->ctx_len); | ||
| 2065 | } | ||
| 2066 | |||
| 1944 | hdr->sadb_msg_len = size / sizeof(uint64_t); | 2067 | hdr->sadb_msg_len = size / sizeof(uint64_t); |
| 1945 | hdr->sadb_msg_reserved = atomic_read(&xp->refcnt); | 2068 | hdr->sadb_msg_reserved = atomic_read(&xp->refcnt); |
| 1946 | } | 2069 | } |
| @@ -1976,12 +2099,13 @@ out: | |||
| 1976 | 2099 | ||
| 1977 | static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 2100 | static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
| 1978 | { | 2101 | { |
| 1979 | int err; | 2102 | int err = 0; |
| 1980 | struct sadb_lifetime *lifetime; | 2103 | struct sadb_lifetime *lifetime; |
| 1981 | struct sadb_address *sa; | 2104 | struct sadb_address *sa; |
| 1982 | struct sadb_x_policy *pol; | 2105 | struct sadb_x_policy *pol; |
| 1983 | struct xfrm_policy *xp; | 2106 | struct xfrm_policy *xp; |
| 1984 | struct km_event c; | 2107 | struct km_event c; |
| 2108 | struct sadb_x_sec_ctx *sec_ctx; | ||
| 1985 | 2109 | ||
| 1986 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], | 2110 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], |
| 1987 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || | 2111 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || |
| @@ -2028,6 +2152,22 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
| 2028 | if (xp->selector.dport) | 2152 | if (xp->selector.dport) |
| 2029 | xp->selector.dport_mask = ~0; | 2153 | xp->selector.dport_mask = ~0; |
| 2030 | 2154 | ||
| 2155 | sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; | ||
| 2156 | if (sec_ctx != NULL) { | ||
| 2157 | struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | ||
| 2158 | |||
| 2159 | if (!uctx) { | ||
| 2160 | err = -ENOBUFS; | ||
| 2161 | goto out; | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | err = security_xfrm_policy_alloc(xp, uctx); | ||
| 2165 | kfree(uctx); | ||
| 2166 | |||
| 2167 | if (err) | ||
| 2168 | goto out; | ||
| 2169 | } | ||
| 2170 | |||
| 2031 | xp->lft.soft_byte_limit = XFRM_INF; | 2171 | xp->lft.soft_byte_limit = XFRM_INF; |
| 2032 | xp->lft.hard_byte_limit = XFRM_INF; | 2172 | xp->lft.hard_byte_limit = XFRM_INF; |
| 2033 | xp->lft.soft_packet_limit = XFRM_INF; | 2173 | xp->lft.soft_packet_limit = XFRM_INF; |
| @@ -2051,10 +2191,9 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
| 2051 | 2191 | ||
| 2052 | err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, | 2192 | err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, |
| 2053 | hdr->sadb_msg_type != SADB_X_SPDUPDATE); | 2193 | hdr->sadb_msg_type != SADB_X_SPDUPDATE); |
| 2054 | if (err) { | 2194 | |
| 2055 | kfree(xp); | 2195 | if (err) |
| 2056 | return err; | 2196 | goto out; |
| 2057 | } | ||
| 2058 | 2197 | ||
| 2059 | if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) | 2198 | if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) |
| 2060 | c.event = XFRM_MSG_UPDPOLICY; | 2199 | c.event = XFRM_MSG_UPDPOLICY; |
| @@ -2069,6 +2208,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
| 2069 | return 0; | 2208 | return 0; |
| 2070 | 2209 | ||
| 2071 | out: | 2210 | out: |
| 2211 | security_xfrm_policy_free(xp); | ||
| 2072 | kfree(xp); | 2212 | kfree(xp); |
| 2073 | return err; | 2213 | return err; |
| 2074 | } | 2214 | } |
| @@ -2078,9 +2218,10 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
| 2078 | int err; | 2218 | int err; |
| 2079 | struct sadb_address *sa; | 2219 | struct sadb_address *sa; |
| 2080 | struct sadb_x_policy *pol; | 2220 | struct sadb_x_policy *pol; |
| 2081 | struct xfrm_policy *xp; | 2221 | struct xfrm_policy *xp, tmp; |
| 2082 | struct xfrm_selector sel; | 2222 | struct xfrm_selector sel; |
| 2083 | struct km_event c; | 2223 | struct km_event c; |
| 2224 | struct sadb_x_sec_ctx *sec_ctx; | ||
| 2084 | 2225 | ||
| 2085 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], | 2226 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], |
| 2086 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || | 2227 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || |
| @@ -2109,7 +2250,24 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
| 2109 | if (sel.dport) | 2250 | if (sel.dport) |
| 2110 | sel.dport_mask = ~0; | 2251 | sel.dport_mask = ~0; |
| 2111 | 2252 | ||
| 2112 | xp = xfrm_policy_bysel(pol->sadb_x_policy_dir-1, &sel, 1); | 2253 | sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; |
| 2254 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
| 2255 | |||
| 2256 | if (sec_ctx != NULL) { | ||
| 2257 | struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | ||
| 2258 | |||
| 2259 | if (!uctx) | ||
| 2260 | return -ENOMEM; | ||
| 2261 | |||
| 2262 | err = security_xfrm_policy_alloc(&tmp, uctx); | ||
| 2263 | kfree(uctx); | ||
| 2264 | |||
| 2265 | if (err) | ||
| 2266 | return err; | ||
| 2267 | } | ||
| 2268 | |||
| 2269 | xp = xfrm_policy_bysel_ctx(pol->sadb_x_policy_dir-1, &sel, tmp.security, 1); | ||
| 2270 | security_xfrm_policy_free(&tmp); | ||
| 2113 | if (xp == NULL) | 2271 | if (xp == NULL) |
| 2114 | return -ENOENT; | 2272 | return -ENOENT; |
| 2115 | 2273 | ||
| @@ -2660,6 +2818,7 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
| 2660 | { | 2818 | { |
| 2661 | struct xfrm_policy *xp; | 2819 | struct xfrm_policy *xp; |
| 2662 | struct sadb_x_policy *pol = (struct sadb_x_policy*)data; | 2820 | struct sadb_x_policy *pol = (struct sadb_x_policy*)data; |
| 2821 | struct sadb_x_sec_ctx *sec_ctx; | ||
| 2663 | 2822 | ||
| 2664 | switch (family) { | 2823 | switch (family) { |
| 2665 | case AF_INET: | 2824 | case AF_INET: |
| @@ -2709,10 +2868,32 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
| 2709 | (*dir = parse_ipsecrequests(xp, pol)) < 0) | 2868 | (*dir = parse_ipsecrequests(xp, pol)) < 0) |
| 2710 | goto out; | 2869 | goto out; |
| 2711 | 2870 | ||
| 2871 | /* security context too */ | ||
| 2872 | if (len >= (pol->sadb_x_policy_len*8 + | ||
| 2873 | sizeof(struct sadb_x_sec_ctx))) { | ||
| 2874 | char *p = (char *)pol; | ||
| 2875 | struct xfrm_user_sec_ctx *uctx; | ||
| 2876 | |||
| 2877 | p += pol->sadb_x_policy_len*8; | ||
| 2878 | sec_ctx = (struct sadb_x_sec_ctx *)p; | ||
| 2879 | if (len < pol->sadb_x_policy_len*8 + | ||
| 2880 | sec_ctx->sadb_x_sec_len) | ||
| 2881 | goto out; | ||
| 2882 | if ((*dir = verify_sec_ctx_len(p))) | ||
| 2883 | goto out; | ||
| 2884 | uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | ||
| 2885 | *dir = security_xfrm_policy_alloc(xp, uctx); | ||
| 2886 | kfree(uctx); | ||
| 2887 | |||
| 2888 | if (*dir) | ||
| 2889 | goto out; | ||
| 2890 | } | ||
| 2891 | |||
| 2712 | *dir = pol->sadb_x_policy_dir-1; | 2892 | *dir = pol->sadb_x_policy_dir-1; |
| 2713 | return xp; | 2893 | return xp; |
| 2714 | 2894 | ||
| 2715 | out: | 2895 | out: |
| 2896 | security_xfrm_policy_free(xp); | ||
| 2716 | kfree(xp); | 2897 | kfree(xp); |
| 2717 | return NULL; | 2898 | return NULL; |
| 2718 | } | 2899 | } |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d19e274b9c4a..64a447375fdb 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | * YOSHIFUJI Hideaki | 10 | * YOSHIFUJI Hideaki |
| 11 | * Split up af-specific portion | 11 | * Split up af-specific portion |
| 12 | * Derek Atkins <derek@ihtfp.com> Add the post_input processor | 12 | * Derek Atkins <derek@ihtfp.com> Add the post_input processor |
| 13 | * | 13 | * |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <asm/bug.h> | 16 | #include <asm/bug.h> |
| @@ -256,6 +256,7 @@ void __xfrm_policy_destroy(struct xfrm_policy *policy) | |||
| 256 | if (del_timer(&policy->timer)) | 256 | if (del_timer(&policy->timer)) |
| 257 | BUG(); | 257 | BUG(); |
| 258 | 258 | ||
| 259 | security_xfrm_policy_free(policy); | ||
| 259 | kfree(policy); | 260 | kfree(policy); |
| 260 | } | 261 | } |
| 261 | EXPORT_SYMBOL(__xfrm_policy_destroy); | 262 | EXPORT_SYMBOL(__xfrm_policy_destroy); |
| @@ -350,7 +351,8 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 350 | 351 | ||
| 351 | write_lock_bh(&xfrm_policy_lock); | 352 | write_lock_bh(&xfrm_policy_lock); |
| 352 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 353 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { |
| 353 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) { | 354 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && |
| 355 | xfrm_sec_ctx_match(pol->security, policy->security)) { | ||
| 354 | if (excl) { | 356 | if (excl) { |
| 355 | write_unlock_bh(&xfrm_policy_lock); | 357 | write_unlock_bh(&xfrm_policy_lock); |
| 356 | return -EEXIST; | 358 | return -EEXIST; |
| @@ -416,14 +418,15 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 416 | } | 418 | } |
| 417 | EXPORT_SYMBOL(xfrm_policy_insert); | 419 | EXPORT_SYMBOL(xfrm_policy_insert); |
| 418 | 420 | ||
| 419 | struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, | 421 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, |
| 420 | int delete) | 422 | struct xfrm_sec_ctx *ctx, int delete) |
| 421 | { | 423 | { |
| 422 | struct xfrm_policy *pol, **p; | 424 | struct xfrm_policy *pol, **p; |
| 423 | 425 | ||
| 424 | write_lock_bh(&xfrm_policy_lock); | 426 | write_lock_bh(&xfrm_policy_lock); |
| 425 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 427 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { |
| 426 | if (memcmp(sel, &pol->selector, sizeof(*sel)) == 0) { | 428 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && |
| 429 | (xfrm_sec_ctx_match(ctx, pol->security))) { | ||
| 427 | xfrm_pol_hold(pol); | 430 | xfrm_pol_hold(pol); |
| 428 | if (delete) | 431 | if (delete) |
| 429 | *p = pol->next; | 432 | *p = pol->next; |
| @@ -438,7 +441,7 @@ struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, | |||
| 438 | } | 441 | } |
| 439 | return pol; | 442 | return pol; |
| 440 | } | 443 | } |
| 441 | EXPORT_SYMBOL(xfrm_policy_bysel); | 444 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
| 442 | 445 | ||
| 443 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 446 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) |
| 444 | { | 447 | { |
| @@ -519,7 +522,7 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
| 519 | 522 | ||
| 520 | /* Find policy to apply to this flow. */ | 523 | /* Find policy to apply to this flow. */ |
| 521 | 524 | ||
| 522 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | 525 | static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, |
| 523 | void **objp, atomic_t **obj_refp) | 526 | void **objp, atomic_t **obj_refp) |
| 524 | { | 527 | { |
| 525 | struct xfrm_policy *pol; | 528 | struct xfrm_policy *pol; |
| @@ -533,9 +536,12 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
| 533 | continue; | 536 | continue; |
| 534 | 537 | ||
| 535 | match = xfrm_selector_match(sel, fl, family); | 538 | match = xfrm_selector_match(sel, fl, family); |
| 539 | |||
| 536 | if (match) { | 540 | if (match) { |
| 537 | xfrm_pol_hold(pol); | 541 | if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) { |
| 538 | break; | 542 | xfrm_pol_hold(pol); |
| 543 | break; | ||
| 544 | } | ||
| 539 | } | 545 | } |
| 540 | } | 546 | } |
| 541 | read_unlock_bh(&xfrm_policy_lock); | 547 | read_unlock_bh(&xfrm_policy_lock); |
| @@ -543,15 +549,37 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
| 543 | *obj_refp = &pol->refcnt; | 549 | *obj_refp = &pol->refcnt; |
| 544 | } | 550 | } |
| 545 | 551 | ||
| 546 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl) | 552 | static inline int policy_to_flow_dir(int dir) |
| 553 | { | ||
| 554 | if (XFRM_POLICY_IN == FLOW_DIR_IN && | ||
| 555 | XFRM_POLICY_OUT == FLOW_DIR_OUT && | ||
| 556 | XFRM_POLICY_FWD == FLOW_DIR_FWD) | ||
| 557 | return dir; | ||
| 558 | switch (dir) { | ||
| 559 | default: | ||
| 560 | case XFRM_POLICY_IN: | ||
| 561 | return FLOW_DIR_IN; | ||
| 562 | case XFRM_POLICY_OUT: | ||
| 563 | return FLOW_DIR_OUT; | ||
| 564 | case XFRM_POLICY_FWD: | ||
| 565 | return FLOW_DIR_FWD; | ||
| 566 | }; | ||
| 567 | } | ||
| 568 | |||
| 569 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) | ||
| 547 | { | 570 | { |
| 548 | struct xfrm_policy *pol; | 571 | struct xfrm_policy *pol; |
| 549 | 572 | ||
| 550 | read_lock_bh(&xfrm_policy_lock); | 573 | read_lock_bh(&xfrm_policy_lock); |
| 551 | if ((pol = sk->sk_policy[dir]) != NULL) { | 574 | if ((pol = sk->sk_policy[dir]) != NULL) { |
| 552 | int match = xfrm_selector_match(&pol->selector, fl, | 575 | int match = xfrm_selector_match(&pol->selector, fl, |
| 553 | sk->sk_family); | 576 | sk->sk_family); |
| 577 | int err = 0; | ||
| 578 | |||
| 554 | if (match) | 579 | if (match) |
| 580 | err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir)); | ||
| 581 | |||
| 582 | if (match && !err) | ||
| 555 | xfrm_pol_hold(pol); | 583 | xfrm_pol_hold(pol); |
| 556 | else | 584 | else |
| 557 | pol = NULL; | 585 | pol = NULL; |
| @@ -624,6 +652,10 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
| 624 | 652 | ||
| 625 | if (newp) { | 653 | if (newp) { |
| 626 | newp->selector = old->selector; | 654 | newp->selector = old->selector; |
| 655 | if (security_xfrm_policy_clone(old, newp)) { | ||
| 656 | kfree(newp); | ||
| 657 | return NULL; /* ENOMEM */ | ||
| 658 | } | ||
| 627 | newp->lft = old->lft; | 659 | newp->lft = old->lft; |
| 628 | newp->curlft = old->curlft; | 660 | newp->curlft = old->curlft; |
| 629 | newp->action = old->action; | 661 | newp->action = old->action; |
| @@ -735,22 +767,6 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, | |||
| 735 | return err; | 767 | return err; |
| 736 | } | 768 | } |
| 737 | 769 | ||
| 738 | static inline int policy_to_flow_dir(int dir) | ||
| 739 | { | ||
| 740 | if (XFRM_POLICY_IN == FLOW_DIR_IN && | ||
| 741 | XFRM_POLICY_OUT == FLOW_DIR_OUT && | ||
| 742 | XFRM_POLICY_FWD == FLOW_DIR_FWD) | ||
| 743 | return dir; | ||
| 744 | switch (dir) { | ||
| 745 | default: | ||
| 746 | case XFRM_POLICY_IN: | ||
| 747 | return FLOW_DIR_IN; | ||
| 748 | case XFRM_POLICY_OUT: | ||
| 749 | return FLOW_DIR_OUT; | ||
| 750 | case XFRM_POLICY_FWD: | ||
| 751 | return FLOW_DIR_FWD; | ||
| 752 | }; | ||
| 753 | } | ||
| 754 | 770 | ||
| 755 | static int stale_bundle(struct dst_entry *dst); | 771 | static int stale_bundle(struct dst_entry *dst); |
| 756 | 772 | ||
| @@ -769,19 +785,20 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
| 769 | int err; | 785 | int err; |
| 770 | u32 genid; | 786 | u32 genid; |
| 771 | u16 family = dst_orig->ops->family; | 787 | u16 family = dst_orig->ops->family; |
| 788 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | ||
| 789 | u32 sk_sid = security_sk_sid(sk, fl, dir); | ||
| 772 | restart: | 790 | restart: |
| 773 | genid = atomic_read(&flow_cache_genid); | 791 | genid = atomic_read(&flow_cache_genid); |
| 774 | policy = NULL; | 792 | policy = NULL; |
| 775 | if (sk && sk->sk_policy[1]) | 793 | if (sk && sk->sk_policy[1]) |
| 776 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | 794 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid); |
| 777 | 795 | ||
| 778 | if (!policy) { | 796 | if (!policy) { |
| 779 | /* To accelerate a bit... */ | 797 | /* To accelerate a bit... */ |
| 780 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 798 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) |
| 781 | return 0; | 799 | return 0; |
| 782 | 800 | ||
| 783 | policy = flow_cache_lookup(fl, family, | 801 | policy = flow_cache_lookup(fl, sk_sid, family, dir, |
| 784 | policy_to_flow_dir(XFRM_POLICY_OUT), | ||
| 785 | xfrm_policy_lookup); | 802 | xfrm_policy_lookup); |
| 786 | } | 803 | } |
| 787 | 804 | ||
| @@ -962,16 +979,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 962 | { | 979 | { |
| 963 | struct xfrm_policy *pol; | 980 | struct xfrm_policy *pol; |
| 964 | struct flowi fl; | 981 | struct flowi fl; |
| 982 | u8 fl_dir = policy_to_flow_dir(dir); | ||
| 983 | u32 sk_sid; | ||
| 965 | 984 | ||
| 966 | if (_decode_session(skb, &fl, family) < 0) | 985 | if (_decode_session(skb, &fl, family) < 0) |
| 967 | return 0; | 986 | return 0; |
| 968 | 987 | ||
| 988 | sk_sid = security_sk_sid(sk, &fl, fl_dir); | ||
| 989 | |||
| 969 | /* First, check used SA against their selectors. */ | 990 | /* First, check used SA against their selectors. */ |
| 970 | if (skb->sp) { | 991 | if (skb->sp) { |
| 971 | int i; | 992 | int i; |
| 972 | 993 | ||
| 973 | for (i=skb->sp->len-1; i>=0; i--) { | 994 | for (i=skb->sp->len-1; i>=0; i--) { |
| 974 | struct sec_decap_state *xvec = &(skb->sp->x[i]); | 995 | struct sec_decap_state *xvec = &(skb->sp->x[i]); |
| 975 | if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) | 996 | if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) |
| 976 | return 0; | 997 | return 0; |
| 977 | 998 | ||
| @@ -986,11 +1007,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 986 | 1007 | ||
| 987 | pol = NULL; | 1008 | pol = NULL; |
| 988 | if (sk && sk->sk_policy[dir]) | 1009 | if (sk && sk->sk_policy[dir]) |
| 989 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); | 1010 | pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid); |
| 990 | 1011 | ||
| 991 | if (!pol) | 1012 | if (!pol) |
| 992 | pol = flow_cache_lookup(&fl, family, | 1013 | pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir, |
| 993 | policy_to_flow_dir(dir), | ||
| 994 | xfrm_policy_lookup); | 1014 | xfrm_policy_lookup); |
| 995 | 1015 | ||
| 996 | if (!pol) | 1016 | if (!pol) |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 479effc97666..e12d0be5f976 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | * Split up af-specific functions | 10 | * Split up af-specific functions |
| 11 | * Derek Atkins <derek@ihtfp.com> | 11 | * Derek Atkins <derek@ihtfp.com> |
| 12 | * Add UDP Encapsulation | 12 | * Add UDP Encapsulation |
| 13 | * | 13 | * |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/workqueue.h> | 16 | #include <linux/workqueue.h> |
| @@ -70,6 +70,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
| 70 | x->type->destructor(x); | 70 | x->type->destructor(x); |
| 71 | xfrm_put_type(x->type); | 71 | xfrm_put_type(x->type); |
| 72 | } | 72 | } |
| 73 | security_xfrm_state_free(x); | ||
| 73 | kfree(x); | 74 | kfree(x); |
| 74 | } | 75 | } |
| 75 | 76 | ||
| @@ -343,7 +344,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 343 | selector. | 344 | selector. |
| 344 | */ | 345 | */ |
| 345 | if (x->km.state == XFRM_STATE_VALID) { | 346 | if (x->km.state == XFRM_STATE_VALID) { |
| 346 | if (!xfrm_selector_match(&x->sel, fl, family)) | 347 | if (!xfrm_selector_match(&x->sel, fl, family) || |
| 348 | !xfrm_sec_ctx_match(pol->security, x->security)) | ||
| 347 | continue; | 349 | continue; |
| 348 | if (!best || | 350 | if (!best || |
| 349 | best->km.dying > x->km.dying || | 351 | best->km.dying > x->km.dying || |
| @@ -354,7 +356,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 354 | acquire_in_progress = 1; | 356 | acquire_in_progress = 1; |
| 355 | } else if (x->km.state == XFRM_STATE_ERROR || | 357 | } else if (x->km.state == XFRM_STATE_ERROR || |
| 356 | x->km.state == XFRM_STATE_EXPIRED) { | 358 | x->km.state == XFRM_STATE_EXPIRED) { |
| 357 | if (xfrm_selector_match(&x->sel, fl, family)) | 359 | if (xfrm_selector_match(&x->sel, fl, family) && |
| 360 | xfrm_sec_ctx_match(pol->security, x->security)) | ||
| 358 | error = -ESRCH; | 361 | error = -ESRCH; |
| 359 | } | 362 | } |
| 360 | } | 363 | } |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0cdd9a07e043..92e2b804c606 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | * Kazunori MIYAZAWA @USAGI | 7 | * Kazunori MIYAZAWA @USAGI |
| 8 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 8 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
| 9 | * IPv6 support | 9 | * IPv6 support |
| 10 | * | 10 | * |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| @@ -88,6 +88,34 @@ static int verify_encap_tmpl(struct rtattr **xfrma) | |||
| 88 | return 0; | 88 | return 0; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | |||
| 92 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | ||
| 93 | { | ||
| 94 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1]; | ||
| 95 | struct xfrm_user_sec_ctx *uctx; | ||
| 96 | int len = 0; | ||
| 97 | |||
| 98 | if (!rt) | ||
| 99 | return 0; | ||
| 100 | |||
| 101 | if (rt->rta_len < sizeof(*uctx)) | ||
| 102 | return -EINVAL; | ||
| 103 | |||
| 104 | uctx = RTA_DATA(rt); | ||
| 105 | |||
| 106 | if (uctx->ctx_len > PAGE_SIZE) | ||
| 107 | return -EINVAL; | ||
| 108 | |||
| 109 | len += sizeof(struct xfrm_user_sec_ctx); | ||
| 110 | len += uctx->ctx_len; | ||
| 111 | |||
| 112 | if (uctx->len != len) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 91 | static int verify_newsa_info(struct xfrm_usersa_info *p, | 119 | static int verify_newsa_info(struct xfrm_usersa_info *p, |
| 92 | struct rtattr **xfrma) | 120 | struct rtattr **xfrma) |
| 93 | { | 121 | { |
| @@ -145,6 +173,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
| 145 | goto out; | 173 | goto out; |
| 146 | if ((err = verify_encap_tmpl(xfrma))) | 174 | if ((err = verify_encap_tmpl(xfrma))) |
| 147 | goto out; | 175 | goto out; |
| 176 | if ((err = verify_sec_ctx_len(xfrma))) | ||
| 177 | goto out; | ||
| 148 | 178 | ||
| 149 | err = -EINVAL; | 179 | err = -EINVAL; |
| 150 | switch (p->mode) { | 180 | switch (p->mode) { |
| @@ -209,6 +239,30 @@ static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_a | |||
| 209 | return 0; | 239 | return 0; |
| 210 | } | 240 | } |
| 211 | 241 | ||
| 242 | |||
| 243 | static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp) | ||
| 244 | { | ||
| 245 | struct xfrm_sec_ctx *xfrm_ctx = xp->security; | ||
| 246 | int len = 0; | ||
| 247 | |||
| 248 | if (xfrm_ctx) { | ||
| 249 | len += sizeof(struct xfrm_user_sec_ctx); | ||
| 250 | len += xfrm_ctx->ctx_len; | ||
| 251 | } | ||
| 252 | return len; | ||
| 253 | } | ||
| 254 | |||
| 255 | static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) | ||
| 256 | { | ||
| 257 | struct xfrm_user_sec_ctx *uctx; | ||
| 258 | |||
| 259 | if (!u_arg) | ||
| 260 | return 0; | ||
| 261 | |||
| 262 | uctx = RTA_DATA(u_arg); | ||
| 263 | return security_xfrm_state_alloc(x, uctx); | ||
| 264 | } | ||
| 265 | |||
| 212 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 266 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
| 213 | { | 267 | { |
| 214 | memcpy(&x->id, &p->id, sizeof(x->id)); | 268 | memcpy(&x->id, &p->id, sizeof(x->id)); |
| @@ -253,6 +307,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
| 253 | if (err) | 307 | if (err) |
| 254 | goto error; | 308 | goto error; |
| 255 | 309 | ||
| 310 | if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1]))) | ||
| 311 | goto error; | ||
| 312 | |||
| 256 | x->km.seq = p->seq; | 313 | x->km.seq = p->seq; |
| 257 | 314 | ||
| 258 | return x; | 315 | return x; |
| @@ -272,11 +329,11 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
| 272 | int err; | 329 | int err; |
| 273 | struct km_event c; | 330 | struct km_event c; |
| 274 | 331 | ||
| 275 | err = verify_newsa_info(p, (struct rtattr **) xfrma); | 332 | err = verify_newsa_info(p, (struct rtattr **)xfrma); |
| 276 | if (err) | 333 | if (err) |
| 277 | return err; | 334 | return err; |
| 278 | 335 | ||
| 279 | x = xfrm_state_construct(p, (struct rtattr **) xfrma, &err); | 336 | x = xfrm_state_construct(p, (struct rtattr **)xfrma, &err); |
| 280 | if (!x) | 337 | if (!x) |
| 281 | return err; | 338 | return err; |
| 282 | 339 | ||
| @@ -390,6 +447,19 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
| 390 | if (x->encap) | 447 | if (x->encap) |
| 391 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 448 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
| 392 | 449 | ||
| 450 | if (x->security) { | ||
| 451 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | ||
| 452 | x->security->ctx_len; | ||
| 453 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | ||
| 454 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
| 455 | |||
| 456 | uctx->exttype = XFRMA_SEC_CTX; | ||
| 457 | uctx->len = ctx_size; | ||
| 458 | uctx->ctx_doi = x->security->ctx_doi; | ||
| 459 | uctx->ctx_alg = x->security->ctx_alg; | ||
| 460 | uctx->ctx_len = x->security->ctx_len; | ||
| 461 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); | ||
| 462 | } | ||
| 393 | nlh->nlmsg_len = skb->tail - b; | 463 | nlh->nlmsg_len = skb->tail - b; |
| 394 | out: | 464 | out: |
| 395 | sp->this_idx++; | 465 | sp->this_idx++; |
| @@ -603,6 +673,18 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | |||
| 603 | return verify_policy_dir(p->dir); | 673 | return verify_policy_dir(p->dir); |
| 604 | } | 674 | } |
| 605 | 675 | ||
| 676 | static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma) | ||
| 677 | { | ||
| 678 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; | ||
| 679 | struct xfrm_user_sec_ctx *uctx; | ||
| 680 | |||
| 681 | if (!rt) | ||
| 682 | return 0; | ||
| 683 | |||
| 684 | uctx = RTA_DATA(rt); | ||
| 685 | return security_xfrm_policy_alloc(pol, uctx); | ||
| 686 | } | ||
| 687 | |||
| 606 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | 688 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, |
| 607 | int nr) | 689 | int nr) |
| 608 | { | 690 | { |
| @@ -681,7 +763,10 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
| 681 | } | 763 | } |
| 682 | 764 | ||
| 683 | copy_from_user_policy(xp, p); | 765 | copy_from_user_policy(xp, p); |
| 684 | err = copy_from_user_tmpl(xp, xfrma); | 766 | |
| 767 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | ||
| 768 | err = copy_from_user_sec_ctx(xp, xfrma); | ||
| 769 | |||
| 685 | if (err) { | 770 | if (err) { |
| 686 | *errp = err; | 771 | *errp = err; |
| 687 | kfree(xp); | 772 | kfree(xp); |
| @@ -702,8 +787,11 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
| 702 | err = verify_newpolicy_info(p); | 787 | err = verify_newpolicy_info(p); |
| 703 | if (err) | 788 | if (err) |
| 704 | return err; | 789 | return err; |
| 790 | err = verify_sec_ctx_len((struct rtattr **)xfrma); | ||
| 791 | if (err) | ||
| 792 | return err; | ||
| 705 | 793 | ||
| 706 | xp = xfrm_policy_construct(p, (struct rtattr **) xfrma, &err); | 794 | xp = xfrm_policy_construct(p, (struct rtattr **)xfrma, &err); |
| 707 | if (!xp) | 795 | if (!xp) |
| 708 | return err; | 796 | return err; |
| 709 | 797 | ||
| @@ -761,6 +849,27 @@ rtattr_failure: | |||
| 761 | return -1; | 849 | return -1; |
| 762 | } | 850 | } |
| 763 | 851 | ||
| 852 | static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) | ||
| 853 | { | ||
| 854 | if (xp->security) { | ||
| 855 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | ||
| 856 | xp->security->ctx_len; | ||
| 857 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | ||
| 858 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
| 859 | |||
| 860 | uctx->exttype = XFRMA_SEC_CTX; | ||
| 861 | uctx->len = ctx_size; | ||
| 862 | uctx->ctx_doi = xp->security->ctx_doi; | ||
| 863 | uctx->ctx_alg = xp->security->ctx_alg; | ||
| 864 | uctx->ctx_len = xp->security->ctx_len; | ||
| 865 | memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len); | ||
| 866 | } | ||
| 867 | return 0; | ||
| 868 | |||
| 869 | rtattr_failure: | ||
| 870 | return -1; | ||
| 871 | } | ||
| 872 | |||
| 764 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) | 873 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) |
| 765 | { | 874 | { |
| 766 | struct xfrm_dump_info *sp = ptr; | 875 | struct xfrm_dump_info *sp = ptr; |
| @@ -782,6 +891,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
| 782 | copy_to_user_policy(xp, p, dir); | 891 | copy_to_user_policy(xp, p, dir); |
| 783 | if (copy_to_user_tmpl(xp, skb) < 0) | 892 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 784 | goto nlmsg_failure; | 893 | goto nlmsg_failure; |
| 894 | if (copy_to_user_sec_ctx(xp, skb)) | ||
| 895 | goto nlmsg_failure; | ||
| 785 | 896 | ||
| 786 | nlh->nlmsg_len = skb->tail - b; | 897 | nlh->nlmsg_len = skb->tail - b; |
| 787 | out: | 898 | out: |
| @@ -852,8 +963,25 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
| 852 | 963 | ||
| 853 | if (p->index) | 964 | if (p->index) |
| 854 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 965 | xp = xfrm_policy_byid(p->dir, p->index, delete); |
| 855 | else | 966 | else { |
| 856 | xp = xfrm_policy_bysel(p->dir, &p->sel, delete); | 967 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
| 968 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | ||
| 969 | struct xfrm_policy tmp; | ||
| 970 | |||
| 971 | err = verify_sec_ctx_len(rtattrs); | ||
| 972 | if (err) | ||
| 973 | return err; | ||
| 974 | |||
| 975 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
| 976 | if (rt) { | ||
| 977 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
| 978 | |||
| 979 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | ||
| 980 | return err; | ||
| 981 | } | ||
| 982 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete); | ||
| 983 | security_xfrm_policy_free(&tmp); | ||
| 984 | } | ||
| 857 | if (xp == NULL) | 985 | if (xp == NULL) |
| 858 | return -ENOENT; | 986 | return -ENOENT; |
| 859 | 987 | ||
| @@ -1224,6 +1352,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
| 1224 | 1352 | ||
| 1225 | if (copy_to_user_tmpl(xp, skb) < 0) | 1353 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 1226 | goto nlmsg_failure; | 1354 | goto nlmsg_failure; |
| 1355 | if (copy_to_user_sec_ctx(xp, skb)) | ||
| 1356 | goto nlmsg_failure; | ||
| 1227 | 1357 | ||
| 1228 | nlh->nlmsg_len = skb->tail - b; | 1358 | nlh->nlmsg_len = skb->tail - b; |
| 1229 | return skb->len; | 1359 | return skb->len; |
| @@ -1241,6 +1371,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
| 1241 | 1371 | ||
| 1242 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 1372 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
| 1243 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); | 1373 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); |
| 1374 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | ||
| 1244 | skb = alloc_skb(len, GFP_ATOMIC); | 1375 | skb = alloc_skb(len, GFP_ATOMIC); |
| 1245 | if (skb == NULL) | 1376 | if (skb == NULL) |
| 1246 | return -ENOMEM; | 1377 | return -ENOMEM; |
| @@ -1324,6 +1455,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
| 1324 | copy_to_user_policy(xp, &upe->pol, dir); | 1455 | copy_to_user_policy(xp, &upe->pol, dir); |
| 1325 | if (copy_to_user_tmpl(xp, skb) < 0) | 1456 | if (copy_to_user_tmpl(xp, skb) < 0) |
| 1326 | goto nlmsg_failure; | 1457 | goto nlmsg_failure; |
| 1458 | if (copy_to_user_sec_ctx(xp, skb)) | ||
| 1459 | goto nlmsg_failure; | ||
| 1327 | upe->hard = !!hard; | 1460 | upe->hard = !!hard; |
| 1328 | 1461 | ||
| 1329 | nlh->nlmsg_len = skb->tail - b; | 1462 | nlh->nlmsg_len = skb->tail - b; |
| @@ -1341,6 +1474,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve | |||
| 1341 | 1474 | ||
| 1342 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 1475 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
| 1343 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); | 1476 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); |
| 1477 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | ||
| 1344 | skb = alloc_skb(len, GFP_ATOMIC); | 1478 | skb = alloc_skb(len, GFP_ATOMIC); |
| 1345 | if (skb == NULL) | 1479 | if (skb == NULL) |
| 1346 | return -ENOMEM; | 1480 | return -ENOMEM; |
diff --git a/security/Kconfig b/security/Kconfig index 64d3f1e9ca85..34f593410d57 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
| @@ -54,6 +54,19 @@ config SECURITY_NETWORK | |||
| 54 | implement socket and networking access controls. | 54 | implement socket and networking access controls. |
| 55 | If you are unsure how to answer this question, answer N. | 55 | If you are unsure how to answer this question, answer N. |
| 56 | 56 | ||
| 57 | config SECURITY_NETWORK_XFRM | ||
| 58 | bool "XFRM (IPSec) Networking Security Hooks" | ||
| 59 | depends on XFRM && SECURITY_NETWORK | ||
| 60 | help | ||
| 61 | This enables the XFRM (IPSec) networking security hooks. | ||
| 62 | If enabled, a security module can use these hooks to | ||
| 63 | implement per-packet access controls based on labels | ||
| 64 | derived from IPSec policy. Non-IPSec communications are | ||
| 65 | designated as unlabelled, and only sockets authorized | ||
| 66 | to communicate unlabelled data can send without using | ||
| 67 | IPSec. | ||
| 68 | If you are unsure how to answer this question, answer N. | ||
| 69 | |||
| 57 | config SECURITY_CAPABILITIES | 70 | config SECURITY_CAPABILITIES |
| 58 | tristate "Default Linux Capabilities" | 71 | tristate "Default Linux Capabilities" |
| 59 | depends on SECURITY | 72 | depends on SECURITY |
diff --git a/security/dummy.c b/security/dummy.c index 3ca5f2b828a0..a15c54709fde 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
| @@ -776,8 +776,42 @@ static inline int dummy_sk_alloc_security (struct sock *sk, int family, gfp_t pr | |||
| 776 | static inline void dummy_sk_free_security (struct sock *sk) | 776 | static inline void dummy_sk_free_security (struct sock *sk) |
| 777 | { | 777 | { |
| 778 | } | 778 | } |
| 779 | |||
| 780 | static unsigned int dummy_sk_getsid(struct sock *sk, struct flowi *fl, u8 dir) | ||
| 781 | { | ||
| 782 | return 0; | ||
| 783 | } | ||
| 779 | #endif /* CONFIG_SECURITY_NETWORK */ | 784 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 780 | 785 | ||
| 786 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | ||
| 787 | static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | ||
| 788 | { | ||
| 789 | return 0; | ||
| 790 | } | ||
| 791 | |||
| 792 | static inline int dummy_xfrm_policy_clone_security(struct xfrm_policy *old, struct xfrm_policy *new) | ||
| 793 | { | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | static void dummy_xfrm_policy_free_security(struct xfrm_policy *xp) | ||
| 798 | { | ||
| 799 | } | ||
| 800 | |||
| 801 | static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | ||
| 802 | { | ||
| 803 | return 0; | ||
| 804 | } | ||
| 805 | |||
| 806 | static void dummy_xfrm_state_free_security(struct xfrm_state *x) | ||
| 807 | { | ||
| 808 | } | ||
| 809 | |||
| 810 | static int dummy_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | ||
| 811 | { | ||
| 812 | return 0; | ||
| 813 | } | ||
| 814 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | ||
| 781 | static int dummy_register_security (const char *name, struct security_operations *ops) | 815 | static int dummy_register_security (const char *name, struct security_operations *ops) |
| 782 | { | 816 | { |
| 783 | return -EINVAL; | 817 | return -EINVAL; |
| @@ -970,7 +1004,16 @@ void security_fixup_ops (struct security_operations *ops) | |||
| 970 | set_to_dummy_if_null(ops, socket_getpeersec); | 1004 | set_to_dummy_if_null(ops, socket_getpeersec); |
| 971 | set_to_dummy_if_null(ops, sk_alloc_security); | 1005 | set_to_dummy_if_null(ops, sk_alloc_security); |
| 972 | set_to_dummy_if_null(ops, sk_free_security); | 1006 | set_to_dummy_if_null(ops, sk_free_security); |
| 973 | #endif /* CONFIG_SECURITY_NETWORK */ | 1007 | set_to_dummy_if_null(ops, sk_getsid); |
| 1008 | #endif /* CONFIG_SECURITY_NETWORK */ | ||
| 1009 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | ||
| 1010 | set_to_dummy_if_null(ops, xfrm_policy_alloc_security); | ||
| 1011 | set_to_dummy_if_null(ops, xfrm_policy_clone_security); | ||
| 1012 | set_to_dummy_if_null(ops, xfrm_policy_free_security); | ||
| 1013 | set_to_dummy_if_null(ops, xfrm_state_alloc_security); | ||
| 1014 | set_to_dummy_if_null(ops, xfrm_state_free_security); | ||
| 1015 | set_to_dummy_if_null(ops, xfrm_policy_lookup); | ||
| 1016 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | ||
| 974 | #ifdef CONFIG_KEYS | 1017 | #ifdef CONFIG_KEYS |
| 975 | set_to_dummy_if_null(ops, key_alloc); | 1018 | set_to_dummy_if_null(ops, key_alloc); |
| 976 | set_to_dummy_if_null(ops, key_free); | 1019 | set_to_dummy_if_null(ops, key_free); |
