mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git
This commit is contained in:
@@ -104,6 +104,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb,
|
||||
struct aead_request *req;
|
||||
struct scatterlist *sg;
|
||||
|
||||
/* Managed frags are owned by the zerocopy ubuf; the skb holds no
|
||||
* per-frag page reference, so we must not drop one here. Mirrors
|
||||
* the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data().
|
||||
*/
|
||||
if (skb_zcopy_managed(skb))
|
||||
return;
|
||||
|
||||
if (x->props.flags & XFRM_STATE_ESN)
|
||||
extralen += sizeof(struct esp_output_extra);
|
||||
|
||||
|
||||
+18
-11
@@ -232,26 +232,28 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des
|
||||
* Rearrange the destination address in @iph and the addresses in @rthdr
|
||||
* so that they appear in the order they will at the final destination.
|
||||
* See Appendix A2 of RFC 2402 for details.
|
||||
*
|
||||
* Return: 0 on success, -EINVAL if segments_left exceeds the number of
|
||||
* addresses described by hdrlen.
|
||||
*/
|
||||
static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
|
||||
static int ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
|
||||
{
|
||||
int segments, segments_left;
|
||||
unsigned int segments, segments_left;
|
||||
struct in6_addr *addrs;
|
||||
struct in6_addr final_addr;
|
||||
|
||||
segments_left = rthdr->segments_left;
|
||||
if (segments_left == 0)
|
||||
return;
|
||||
rthdr->segments_left = 0;
|
||||
return 0;
|
||||
|
||||
/* The value of rthdr->hdrlen has been verified either by the system
|
||||
* call if it is locally generated, or by ipv6_rthdr_rcv() for incoming
|
||||
* packets. So we can assume that it is even and that segments is
|
||||
* greater than or equal to segments_left.
|
||||
*
|
||||
* For the same reason we can assume that this option is of type 0.
|
||||
/* Raw locally generated packets can reach AH6 without the invariant
|
||||
* required by the rt0-style address rearrangement below.
|
||||
*/
|
||||
segments = rthdr->hdrlen >> 1;
|
||||
if (segments_left > segments)
|
||||
return -EINVAL;
|
||||
|
||||
rthdr->segments_left = 0;
|
||||
|
||||
addrs = ((struct rt0_hdr *)rthdr)->addr;
|
||||
final_addr = addrs[segments - 1];
|
||||
@@ -261,6 +263,8 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
|
||||
|
||||
addrs[0] = iph->daddr;
|
||||
iph->daddr = final_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
|
||||
@@ -273,6 +277,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
|
||||
} exthdr = { .iph = iph };
|
||||
char *end = exthdr.raw + len;
|
||||
int nexthdr = iph->nexthdr;
|
||||
int err;
|
||||
|
||||
exthdr.iph++;
|
||||
|
||||
@@ -292,7 +297,9 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
|
||||
break;
|
||||
|
||||
case NEXTHDR_ROUTING:
|
||||
ipv6_rearrange_rthdr(iph, exthdr.rth);
|
||||
err = ipv6_rearrange_rthdr(iph, exthdr.rth);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -121,6 +121,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb,
|
||||
struct aead_request *req;
|
||||
struct scatterlist *sg;
|
||||
|
||||
/* Managed frags are owned by the zerocopy ubuf; the skb holds no
|
||||
* per-frag page reference, so we must not drop one here. Mirrors
|
||||
* the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data().
|
||||
*/
|
||||
if (skb_zcopy_managed(skb))
|
||||
return;
|
||||
|
||||
if (x->props.flags & XFRM_STATE_ESN)
|
||||
extralen += sizeof(struct esp_output_extra);
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (1 + sp->len == XFRM_MAX_DEPTH) {
|
||||
if (sp->len >= XFRM_MAX_DEPTH) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
+8
-1
@@ -37,6 +37,11 @@ static void handle_esp(struct sk_buff *skb, struct sock *sk)
|
||||
|
||||
rcu_read_lock();
|
||||
skb->dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);
|
||||
if (!skb->dev) {
|
||||
XFRM_INC_STATS(sock_net(sk), LINUX_MIB_XFRMINERROR);
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
local_bh_disable();
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (sk->sk_family == AF_INET6)
|
||||
@@ -45,6 +50,7 @@ static void handle_esp(struct sk_buff *skb, struct sock *sk)
|
||||
#endif
|
||||
xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, TCP_ENCAP_ESPINTCP);
|
||||
local_bh_enable();
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@@ -515,7 +521,8 @@ static void espintcp_close(struct sock *sk, long timeout)
|
||||
strp_stop(&ctx->strp);
|
||||
|
||||
sk->sk_prot = &tcp_prot;
|
||||
barrier();
|
||||
|
||||
synchronize_rcu();
|
||||
|
||||
disable_work_sync(&ctx->work);
|
||||
strp_done(&ctx->strp);
|
||||
|
||||
@@ -156,24 +156,51 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
|
||||
}
|
||||
|
||||
struct nat_keepalive_work_ctx {
|
||||
struct list_head states;
|
||||
time64_t next_run;
|
||||
time64_t now;
|
||||
};
|
||||
|
||||
static int nat_keepalive_work_single(struct xfrm_state *x, int count, void *ptr)
|
||||
struct nat_keepalive_state {
|
||||
struct list_head list;
|
||||
struct xfrm_state *x;
|
||||
};
|
||||
|
||||
static int nat_keepalive_work_collect(struct xfrm_state *x, int count, void *ptr)
|
||||
{
|
||||
struct nat_keepalive_work_ctx *ctx = ptr;
|
||||
struct nat_keepalive_state *state;
|
||||
|
||||
if (!READ_ONCE(x->nat_keepalive_interval))
|
||||
return 0;
|
||||
|
||||
state = kmalloc_obj(*state, GFP_ATOMIC);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
xfrm_state_hold(x);
|
||||
state->x = x;
|
||||
list_add_tail(&state->list, &ctx->states);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nat_keepalive_work_single(struct xfrm_state *x,
|
||||
struct nat_keepalive_work_ctx *ctx)
|
||||
{
|
||||
bool send_keepalive = false;
|
||||
struct nat_keepalive ka;
|
||||
time64_t next_run;
|
||||
time64_t next_run = 0;
|
||||
u32 interval;
|
||||
int delta;
|
||||
|
||||
spin_lock_bh(&x->lock);
|
||||
|
||||
if (x->km.state == XFRM_STATE_DEAD)
|
||||
goto out;
|
||||
|
||||
interval = x->nat_keepalive_interval;
|
||||
if (!interval)
|
||||
return 0;
|
||||
|
||||
spin_lock(&x->lock);
|
||||
goto out;
|
||||
|
||||
delta = (int)(ctx->now - x->lastused);
|
||||
if (delta < interval) {
|
||||
@@ -187,29 +214,41 @@ static int nat_keepalive_work_single(struct xfrm_state *x, int count, void *ptr)
|
||||
send_keepalive = true;
|
||||
}
|
||||
|
||||
spin_unlock(&x->lock);
|
||||
out:
|
||||
spin_unlock_bh(&x->lock);
|
||||
|
||||
if (send_keepalive)
|
||||
nat_keepalive_send(&ka);
|
||||
|
||||
if (!ctx->next_run || next_run < ctx->next_run)
|
||||
if (next_run && (!ctx->next_run || next_run < ctx->next_run))
|
||||
ctx->next_run = next_run;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nat_keepalive_work(struct work_struct *work)
|
||||
{
|
||||
struct nat_keepalive_state *state, *tmp;
|
||||
struct nat_keepalive_work_ctx ctx;
|
||||
struct xfrm_state_walk walk;
|
||||
struct net *net;
|
||||
int err;
|
||||
|
||||
INIT_LIST_HEAD(&ctx.states);
|
||||
ctx.next_run = 0;
|
||||
ctx.now = ktime_get_real_seconds();
|
||||
|
||||
net = container_of(work, struct net, xfrm.nat_keepalive_work.work);
|
||||
xfrm_state_walk_init(&walk, IPPROTO_ESP, NULL);
|
||||
xfrm_state_walk(net, &walk, nat_keepalive_work_single, &ctx);
|
||||
err = xfrm_state_walk(net, &walk, nat_keepalive_work_collect, &ctx);
|
||||
xfrm_state_walk_done(&walk, net);
|
||||
list_for_each_entry_safe(state, tmp, &ctx.states, list) {
|
||||
nat_keepalive_work_single(state->x, &ctx);
|
||||
xfrm_state_put(state->x);
|
||||
kfree(state);
|
||||
}
|
||||
if (err == -ENOMEM) {
|
||||
schedule_delayed_work(&net->xfrm.nat_keepalive_work, 0);
|
||||
return;
|
||||
}
|
||||
if (ctx.next_run)
|
||||
schedule_delayed_work(&net->xfrm.nat_keepalive_work,
|
||||
(ctx.next_run - ctx.now) * HZ);
|
||||
|
||||
@@ -636,10 +636,8 @@ static int xfrm_dev_direct_output(struct sock *sk, struct xfrm_state *x,
|
||||
nf_reset_ct(skb);
|
||||
|
||||
err = skb_dst(skb)->ops->local_out(net, sk, skb);
|
||||
if (unlikely(err != 1)) {
|
||||
kfree_skb(skb);
|
||||
if (unlikely(err != 1))
|
||||
return err;
|
||||
}
|
||||
|
||||
/* In transport mode, network destination is
|
||||
* directly reachable, while in tunnel mode,
|
||||
|
||||
@@ -940,7 +940,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
|
||||
if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
|
||||
attrs[XFRMA_ALG_AUTH_TRUNC], extack)))
|
||||
goto error;
|
||||
if (!x->props.aalgo) {
|
||||
if (!x->aalg) {
|
||||
if ((err = attach_auth(&x->aalg, &x->props.aalgo,
|
||||
attrs[XFRMA_ALG_AUTH], extack)))
|
||||
goto error;
|
||||
|
||||
Reference in New Issue
Block a user