| From foo@baz Fri Mar 16 15:43:17 CET 2018 |
| From: Lorenzo Colitti <lorenzo@google.com> |
| Date: Mon, 20 Nov 2017 19:26:02 +0900 |
| Subject: net: xfrm: allow clearing socket xfrm policies. |
| |
| From: Lorenzo Colitti <lorenzo@google.com> |
| |
| |
| [ Upstream commit be8f8284cd897af2482d4e54fbc2bdfc15557259 ] |
| |
| Currently it is possible to add or update socket policies, but |
| not clear them. Therefore, once a socket policy has been applied, |
| the socket cannot be used for unencrypted traffic. |
| |
| This patch allows (privileged) users to clear socket policies by |
| passing in a NULL pointer and zero length argument to the |
| {IP,IPV6}_{IPSEC,XFRM}_POLICY setsockopts. This results in both |
| the incoming and outgoing policies being cleared. |
| |
| The simple approach taken in this patch cannot clear socket |
| policies in only one direction. If desired this could be added |
| in the future, for example by continuing to pass in a length of |
| zero (which currently is guaranteed to return EMSGSIZE) and |
| making the policy be a pointer to an integer that contains one |
| of the XFRM_POLICY_{IN,OUT} enum values. |
| |
| An alternative would have been to interpret the length as a |
| signed integer and use XFRM_POLICY_IN (i.e., 0) to clear the |
| input policy and -XFRM_POLICY_OUT (i.e., -1) to clear the output |
| policy. |
| |
| Tested: https://android-review.googlesource.com/539816 |
| Signed-off-by: Lorenzo Colitti <lorenzo@google.com> |
| Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/xfrm/xfrm_policy.c | 2 +- |
| net/xfrm/xfrm_state.c | 7 +++++++ |
| 2 files changed, 8 insertions(+), 1 deletion(-) |
| |
| --- a/net/xfrm/xfrm_policy.c |
| +++ b/net/xfrm/xfrm_policy.c |
| @@ -1257,7 +1257,7 @@ EXPORT_SYMBOL(xfrm_policy_delete); |
| |
| int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) |
| { |
| - struct net *net = xp_net(pol); |
| + struct net *net = sock_net(sk); |
| struct xfrm_policy *old_pol; |
| |
| #ifdef CONFIG_XFRM_SUB_POLICY |
| --- a/net/xfrm/xfrm_state.c |
| +++ b/net/xfrm/xfrm_state.c |
| @@ -2050,6 +2050,13 @@ int xfrm_user_policy(struct sock *sk, in |
| struct xfrm_mgr *km; |
| struct xfrm_policy *pol = NULL; |
| |
| + if (!optval && !optlen) { |
| + xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); |
| + xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); |
| + __sk_dst_reset(sk); |
| + return 0; |
| + } |
| + |
| if (optlen <= 0 || optlen > PAGE_SIZE) |
| return -EMSGSIZE; |
| |