lkml.org 
[lkml]   [2021]   [Nov]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 14/25] tcp: ipv4: Add AO signing for skb-less replies
    Date
    The code in tcp_v4_send_ack and tcp_v4_send_reset does not allocate a
    full skb so special handling is required for tcp-authopt handling.

    Signed-off-by: Leonard Crestez <cdleonard@gmail.com>
    ---
    net/ipv4/tcp_ipv4.c | 82 +++++++++++++++++++++++++++++++++++++++++++--
    1 file changed, 79 insertions(+), 3 deletions(-)

    diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
    index da43567c3753..21971f5fa40e 100644
    --- a/net/ipv4/tcp_ipv4.c
    +++ b/net/ipv4/tcp_ipv4.c
    @@ -644,10 +644,50 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb)

    __tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr);
    }
    EXPORT_SYMBOL(tcp_v4_send_check);

    +#ifdef CONFIG_TCP_AUTHOPT
    +/** tcp_v4_authopt_handle_reply - Insert TCPOPT_AUTHOPT if required
    + *
    + * returns number of bytes (always aligned to 4) or zero
    + */
    +static int tcp_v4_authopt_handle_reply(const struct sock *sk,
    + struct sk_buff *skb,
    + __be32 *optptr,
    + struct tcphdr *th)
    +{
    + struct tcp_authopt_info *info;
    + struct tcp_authopt_key_info *key_info;
    + u8 rnextkeyid;
    +
    + if (sk->sk_state == TCP_TIME_WAIT)
    + info = tcp_twsk(sk)->tw_authopt_info;
    + else
    + info = tcp_sk(sk)->authopt_info;
    + if (!info)
    + return 0;
    + key_info = __tcp_authopt_select_key(sk, info, sk, &rnextkeyid);
    + if (!key_info)
    + return 0;
    + *optptr = htonl((TCPOPT_AUTHOPT << 24) |
    + (TCPOLEN_AUTHOPT_OUTPUT << 16) |
    + (key_info->send_id << 8) |
    + (rnextkeyid));
    + /* must update doff before signature computation */
    + th->doff += TCPOLEN_AUTHOPT_OUTPUT / 4;
    + tcp_v4_authopt_hash_reply((char *)(optptr + 1),
    + info,
    + key_info,
    + ip_hdr(skb)->daddr,
    + ip_hdr(skb)->saddr,
    + th);
    +
    + return TCPOLEN_AUTHOPT_OUTPUT;
    +}
    +#endif
    +
    /*
    * This routine will send an RST to the other tcp.
    *
    * Someone asks: why I NEVER use socket parameters (TOS, TTL etc.)
    * for reset.
    @@ -659,10 +699,12 @@ EXPORT_SYMBOL(tcp_v4_send_check);
    * Exception: precedence violation. We do not implement it in any case.
    */

    #ifdef CONFIG_TCP_MD5SIG
    #define OPTION_BYTES TCPOLEN_MD5SIG_ALIGNED
    +#elif defined(OPTION_BYTES_TCP_AUTHOPT)
    +#define OPTION_BYTES TCPOLEN_AUTHOPT_OUTPUT
    #else
    #define OPTION_BYTES sizeof(__be32)
    #endif

    static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
    @@ -712,12 +754,29 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
    memset(&arg, 0, sizeof(arg));
    arg.iov[0].iov_base = (unsigned char *)&rep;
    arg.iov[0].iov_len = sizeof(rep.th);

    net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev);
    -#ifdef CONFIG_TCP_MD5SIG
    +#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
    rcu_read_lock();
    +#endif
    +#ifdef CONFIG_TCP_AUTHOPT
    + /* Unlike TCP-MD5 the signatures for TCP-AO depend on initial sequence
    + * numbers so we can only handle established and time-wait sockets.
    + */
    + if (static_branch_unlikely(&tcp_authopt_needed) && sk &&
    + sk->sk_state != TCP_NEW_SYN_RECV &&
    + sk->sk_state != TCP_LISTEN) {
    + int tcp_authopt_ret = tcp_v4_authopt_handle_reply(sk, skb, rep.opt, &rep.th);
    +
    + if (tcp_authopt_ret) {
    + arg.iov[0].iov_len += tcp_authopt_ret;
    + goto skip_md5sig;
    + }
    + }
    +#endif
    +#ifdef CONFIG_TCP_MD5SIG
    hash_location = tcp_parse_md5sig_option(th);
    if (sk && sk_fullsock(sk)) {
    const union tcp_md5_addr *addr;
    int l3index;

    @@ -755,11 +814,10 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
    addr = (union tcp_md5_addr *)&ip_hdr(skb)->saddr;
    key = tcp_md5_do_lookup(sk1, l3index, addr, AF_INET);
    if (!key)
    goto out;

    -
    genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, skb);
    if (genhash || memcmp(hash_location, newhash, 16) != 0)
    goto out;

    }
    @@ -775,10 +833,13 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)

    tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1],
    key, ip_hdr(skb)->saddr,
    ip_hdr(skb)->daddr, &rep.th);
    }
    +#endif
    +#ifdef CONFIG_TCP_AUTHOPT
    +skip_md5sig:
    #endif
    /* Can't co-exist with TCPMD5, hence check rep.opt[0] */
    if (rep.opt[0] == 0) {
    __be32 mrst = mptcp_reset_option(skb);

    @@ -828,12 +889,14 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
    ctl_sk->sk_mark = 0;
    __TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
    __TCP_INC_STATS(net, TCP_MIB_OUTRSTS);
    local_bh_enable();

    -#ifdef CONFIG_TCP_MD5SIG
    +#if defined(CONFIG_TCP_MD5SIG)
    out:
    +#endif
    +#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
    rcu_read_unlock();
    #endif
    }

    /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states
    @@ -850,10 +913,12 @@ static void tcp_v4_send_ack(const struct sock *sk,
    struct {
    struct tcphdr th;
    __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)
    #ifdef CONFIG_TCP_MD5SIG
    + (TCPOLEN_MD5SIG_ALIGNED >> 2)
    +#elif defined(CONFIG_TCP_AUTHOPT)
    + + (TCPOLEN_AUTHOPT_OUTPUT >> 2)
    #endif
    ];
    } rep;
    struct net *net = sock_net(sk);
    struct ip_reply_arg arg;
    @@ -881,10 +946,21 @@ static void tcp_v4_send_ack(const struct sock *sk,
    rep.th.seq = htonl(seq);
    rep.th.ack_seq = htonl(ack);
    rep.th.ack = 1;
    rep.th.window = htons(win);

    +#ifdef CONFIG_TCP_AUTHOPT
    + if (static_branch_unlikely(&tcp_authopt_needed)) {
    + int aoret, offset = (tsecr) ? 3 : 0;
    +
    + aoret = tcp_v4_authopt_handle_reply(sk, skb, &rep.opt[offset], &rep.th);
    + if (aoret) {
    + arg.iov[0].iov_len += aoret;
    + key = NULL;
    + }
    + }
    +#endif
    #ifdef CONFIG_TCP_MD5SIG
    if (key) {
    int offset = (tsecr) ? 3 : 0;

    rep.opt[offset++] = htonl((TCPOPT_NOP << 24) |
    --
    2.25.1
    \
     
     \ /
      Last update: 2021-11-01 17:37    [W:5.339 / U:0.560 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site