History

net/tcp: Add TCP_AO_REPAIR

Add TCP_AO_REPAIR setsockopt(), getsockopt(). They let a user to repair TCP-AO ISNs/SNEs. Also let the user hack around when (tp->repair) is on and add ao_info on a socket in any supported state. As SNEs now can be read/written at any moment, use WRITE_ONCE()/READ_ONCE() to set/read them.

Dmitry Safonov committed 3 years ago

Commit faadfab1 parent 248411b4 files · +125 −11Browse files

Unified · Split

4 files
  1. include/net/tcp_ao.h +14 −0
  2. include/uapi/linux/tcp.h +8 −0
  3. net/ipv4/tcp.c +17 −7
  4. net/ipv4/tcp_ao.c +86 −4
include/net/tcp_ao.h+14−0
@@ -199,6 +199,8 @@ void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp); · 198 unmodified lines
199199 bool tcp_ao_ignore_icmp(const struct sock *sk, int family, int type, int code);
200200 int tcp_ao_get_mkts(struct sock *sk, sockptr_t optval, sockptr_t optlen);
201201 int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen);
202+int tcp_ao_get_repair(struct sock *sk, sockptr_t optval, sockptr_t optlen);
203+int tcp_ao_set_repair(struct sock *sk, sockptr_t optval, unsigned int optlen);
202204 enum skb_drop_reason tcp_inbound_ao_hash(struct sock *sk,
203205 const struct sk_buff *skb, unsigned short int family,
204206 const struct request_sock *req, int l3index,
@@ -330,6 +332,18 @@ static inline int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockpt · 125 unmodified lines
330332 {
331333 return -ENOPROTOOPT;
332334 }
335+
336+static inline int tcp_ao_get_repair(struct sock *sk,
337+ sockptr_t optval, sockptr_t optlen)
338+{
339+ return -ENOPROTOOPT;
340+}
341+
342+static inline int tcp_ao_set_repair(struct sock *sk,
343+ sockptr_t optval, unsigned int optlen)
344+{
345+ return -ENOPROTOOPT;
346+}
333347 #endif
334348
335349 #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
include/uapi/linux/tcp.h+8−0
@@ -133,6 +133,7 @@ enum { · 132 unmodified lines
133133 #define TCP_AO_DEL_KEY 39 /* Delete MKT */
134134 #define TCP_AO_INFO 40 /* Set/list TCP-AO per-socket options */
135135 #define TCP_AO_GET_KEYS 41 /* List MKT(s) */
136+#define TCP_AO_REPAIR 42 /* Get/Set SNEs and ISNs */
136137
137138 #define TCP_REPAIR_ON 1
138139 #define TCP_REPAIR_OFF 0
@@ -458,6 +459,13 @@ struct tcp_ao_getsockopt { /* getsockopt(TCP_AO_GET_KEYS) */ · 319 unmodified lines
458459 __u64 pkt_bad; /* out: segments that failed verification */
459460 } __attribute__((aligned(8)));
460461
462+struct tcp_ao_repair { /* {s,g}etsockopt(TCP_AO_REPAIR) */
463+ __be32 snt_isn;
464+ __be32 rcv_isn;
465+ __u32 snd_sne;
466+ __u32 rcv_sne;
467+} __attribute__((aligned(8)));
468+
461469 /* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */
462470
463471 #define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1
net/ipv4/tcp.c+17−7
@@ -3593,20 +3593,28 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname, · 3592 unmodified lines
35933593 __tcp_sock_set_quickack(sk, val);
35943594 break;
35953595
3596+ case TCP_AO_REPAIR:
3597+ err = tcp_ao_set_repair(sk, optval, optlen);
3598+ break;
35963599 #ifdef CONFIG_TCP_AO
35973600 case TCP_AO_ADD_KEY:
35983601 case TCP_AO_DEL_KEY:
35993602 case TCP_AO_INFO: {
36003603 /* If this is the first TCP-AO setsockopt() on the socket,
3601− * sk_state has to be LISTEN or CLOSE
3604+ * sk_state has to be LISTEN or CLOSE. Allow TCP_REPAIR
3605+ * in any state.
36023606 */
3603− if (((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) ||
3604− rcu_dereference_protected(tcp_sk(sk)->ao_info,
3607+ if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
3608+ goto ao_parse;
3609+ if (rcu_dereference_protected(tcp_sk(sk)->ao_info,
36053610 lockdep_sock_is_held(sk)))
3606− err = tp->af_specific->ao_parse(sk, optname, optval,
3607− optlen);
3608− else
3609− err = -EISCONN;
3611+ goto ao_parse;
3612+ if (tp->repair)
3613+ goto ao_parse;
3614+ err = -EISCONN;
3615+ break;
3616+ao_parse:
3617+ err = tp->af_specific->ao_parse(sk, optname, optval, optlen);
36103618 break;
36113619 }
36123620 #endif
@@ -4284,6 +4292,8 @@ zerocopy_rcv_out: · 671 unmodified lines
42844292 return err;
42854293 }
42864294 #endif
4295+ case TCP_AO_REPAIR:
4296+ return tcp_ao_get_repair(sk, optval, optlen);
42874297 case TCP_AO_GET_KEYS:
42884298 case TCP_AO_INFO: {
42894299 int err;
net/ipv4/tcp_ao.c+86−4
@@ -1490,6 +1490,16 @@ static struct tcp_ao_info *setsockopt_ao_info(struct sock *sk) · 1489 unmodified lines
14901490 return ERR_PTR(-ESOCKTNOSUPPORT);
14911491 }
14921492
1493+static struct tcp_ao_info *getsockopt_ao_info(struct sock *sk)
1494+{
1495+ if (sk_fullsock(sk))
1496+ return rcu_dereference(tcp_sk(sk)->ao_info);
1497+ else if (sk->sk_state == TCP_TIME_WAIT)
1498+ return rcu_dereference(tcp_twsk(sk)->ao_info);
1499+
1500+ return ERR_PTR(-ESOCKTNOSUPPORT);
1501+}
1502+
14931503 #define TCP_AO_KEYF_ALL (TCP_AO_KEYF_IFINDEX | TCP_AO_KEYF_EXCLUDE_OPT)
14941504 #define TCP_AO_GET_KEYF_VALID (TCP_AO_KEYF_IFINDEX)
14951505
@@ -1671,11 +1681,13 @@ static int tcp_ao_add_cmd(struct sock *sk, unsigned short int family, · 175 unmodified lines
16711681 if (ret < 0)
16721682 goto err_free_sock;
16731683
1674− /* Change this condition if we allow adding keys in states
1675− * like close_wait, syn_sent or fin_wait...
1676− */
1677− if (sk->sk_state == TCP_ESTABLISHED)
1684+ if (!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) {
16781685 tcp_ao_cache_traffic_keys(sk, ao_info, key);
1686+ if (first) {
1687+ ao_info->current_key = key;
1688+ ao_info->rnext_key = key;
1689+ }
1690+ }
16791691
16801692 tcp_ao_link_mkt(ao_info, key);
16811693 if (first) {
@@ -1926,6 +1938,8 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family, · 244 unmodified lines
19261938 if (IS_ERR(ao_info))
19271939 return PTR_ERR(ao_info);
19281940 if (!ao_info) {
1941+ if (!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)))
1942+ return -EINVAL;
19291943 ao_info = tcp_ao_alloc_info(GFP_KERNEL);
19301944 if (!ao_info)
19311945 return -ENOMEM;
@@ -2308,3 +2322,71 @@ int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen) · 376 unmodified lines
23082322 return 0;
23092323 }
23102324
2325+int tcp_ao_set_repair(struct sock *sk, sockptr_t optval, unsigned int optlen)
2326+{
2327+ struct tcp_sock *tp = tcp_sk(sk);
2328+ struct tcp_ao_repair cmd;
2329+ struct tcp_ao_key *key;
2330+ struct tcp_ao_info *ao;
2331+ int err;
2332+
2333+ if (optlen < sizeof(cmd))
2334+ return -EINVAL;
2335+
2336+ err = copy_struct_from_sockptr(&cmd, sizeof(cmd), optval, optlen);
2337+ if (err)
2338+ return err;
2339+
2340+ if (!tp->repair)
2341+ return -EPERM;
2342+
2343+ ao = setsockopt_ao_info(sk);
2344+ if (IS_ERR(ao))
2345+ return PTR_ERR(ao);
2346+ if (!ao)
2347+ return -ENOENT;
2348+
2349+ WRITE_ONCE(ao->lisn, cmd.snt_isn);
2350+ WRITE_ONCE(ao->risn, cmd.rcv_isn);
2351+ WRITE_ONCE(ao->snd_sne, cmd.snd_sne);
2352+ WRITE_ONCE(ao->rcv_sne, cmd.rcv_sne);
2353+
2354+ hlist_for_each_entry_rcu(key, &ao->head, node)
2355+ tcp_ao_cache_traffic_keys(sk, ao, key);
2356+
2357+ return 0;
2358+}
2359+
2360+int tcp_ao_get_repair(struct sock *sk, sockptr_t optval, sockptr_t optlen)
2361+{
2362+ struct tcp_sock *tp = tcp_sk(sk);
2363+ struct tcp_ao_repair opt;
2364+ struct tcp_ao_info *ao;
2365+ int len;
2366+
2367+ if (copy_from_sockptr(&len, optlen, sizeof(int)))
2368+ return -EFAULT;
2369+
2370+ if (len <= 0)
2371+ return -EINVAL;
2372+
2373+ if (!tp->repair)
2374+ return -EPERM;
2375+
2376+ rcu_read_lock();
2377+ ao = getsockopt_ao_info(sk);
2378+ if (IS_ERR_OR_NULL(ao)) {
2379+ rcu_read_unlock();
2380+ return ao ? PTR_ERR(ao) : -ENOENT;
2381+ }
2382+
2383+ opt.snt_isn = ao->lisn;
2384+ opt.rcv_isn = ao->risn;
2385+ opt.snd_sne = READ_ONCE(ao->snd_sne);
2386+ opt.rcv_sne = READ_ONCE(ao->rcv_sne);
2387+ rcu_read_unlock();
2388+
2389+ if (copy_to_sockptr(optval, &opt, min_t(int, len, sizeof(opt))))
2390+ return -EFAULT;
2391+ return 0;
2392+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t