tcp: annotate sk->sk_sndbuf lockless reads
[linux-2.6-block.git] / net / core / filter.c
index 7878f918b8c057b7b90ca0afcf2d5773cfb55e15..3fed5755494bd39cf55ca1806ead67609ae8b587 100644 (file)
@@ -3517,7 +3517,8 @@ static int __bpf_tx_xdp_map(struct net_device *dev_rx, void *fwd,
        int err;
 
        switch (map->map_type) {
-       case BPF_MAP_TYPE_DEVMAP: {
+       case BPF_MAP_TYPE_DEVMAP:
+       case BPF_MAP_TYPE_DEVMAP_HASH: {
                struct bpf_dtab_netdev *dst = fwd;
 
                err = dev_map_enqueue(dst, xdp, dev_rx);
@@ -3554,6 +3555,7 @@ void xdp_do_flush_map(void)
        if (map) {
                switch (map->map_type) {
                case BPF_MAP_TYPE_DEVMAP:
+               case BPF_MAP_TYPE_DEVMAP_HASH:
                        __dev_map_flush(map);
                        break;
                case BPF_MAP_TYPE_CPUMAP:
@@ -3574,6 +3576,8 @@ static inline void *__xdp_map_lookup_elem(struct bpf_map *map, u32 index)
        switch (map->map_type) {
        case BPF_MAP_TYPE_DEVMAP:
                return __dev_map_lookup_elem(map, index);
+       case BPF_MAP_TYPE_DEVMAP_HASH:
+               return __dev_map_hash_lookup_elem(map, index);
        case BPF_MAP_TYPE_CPUMAP:
                return __cpu_map_lookup_elem(map, index);
        case BPF_MAP_TYPE_XSKMAP:
@@ -3655,7 +3659,8 @@ static int xdp_do_generic_redirect_map(struct net_device *dev,
        ri->tgt_value = NULL;
        WRITE_ONCE(ri->map, NULL);
 
-       if (map->map_type == BPF_MAP_TYPE_DEVMAP) {
+       if (map->map_type == BPF_MAP_TYPE_DEVMAP ||
+           map->map_type == BPF_MAP_TYPE_DEVMAP_HASH) {
                struct bpf_dtab_netdev *dst = fwd;
 
                err = dev_map_generic_redirect(dst, skb, xdp_prog);
@@ -4247,12 +4252,14 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
                case SO_RCVBUF:
                        val = min_t(u32, val, sysctl_rmem_max);
                        sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
-                       sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF);
+                       WRITE_ONCE(sk->sk_rcvbuf,
+                                  max_t(int, val * 2, SOCK_MIN_RCVBUF));
                        break;
                case SO_SNDBUF:
                        val = min_t(u32, val, sysctl_wmem_max);
                        sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
-                       sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF);
+                       WRITE_ONCE(sk->sk_sndbuf,
+                                  max_t(int, val * 2, SOCK_MIN_SNDBUF));
                        break;
                case SO_MAX_PACING_RATE: /* 32bit version */
                        if (val != ~0U)
@@ -4269,7 +4276,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
                case SO_RCVLOWAT:
                        if (val < 0)
                                val = INT_MAX;
-                       sk->sk_rcvlowat = val ? : 1;
+                       WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
                        break;
                case SO_MARK:
                        if (sk->sk_mark != val) {
@@ -5850,6 +5857,75 @@ static const struct bpf_func_proto bpf_tcp_check_syncookie_proto = {
        .arg5_type      = ARG_CONST_SIZE,
 };
 
+BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
+          struct tcphdr *, th, u32, th_len)
+{
+#ifdef CONFIG_SYN_COOKIES
+       u32 cookie;
+       u16 mss;
+
+       if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
+               return -EINVAL;
+
+       if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
+               return -EINVAL;
+
+       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies)
+               return -ENOENT;
+
+       if (!th->syn || th->ack || th->fin || th->rst)
+               return -EINVAL;
+
+       if (unlikely(iph_len < sizeof(struct iphdr)))
+               return -EINVAL;
+
+       /* Both struct iphdr and struct ipv6hdr have the version field at the
+        * same offset so we can cast to the shorter header (struct iphdr).
+        */
+       switch (((struct iphdr *)iph)->version) {
+       case 4:
+               if (sk->sk_family == AF_INET6 && sk->sk_ipv6only)
+                       return -EINVAL;
+
+               mss = tcp_v4_get_syncookie(sk, iph, th, &cookie);
+               break;
+
+#if IS_BUILTIN(CONFIG_IPV6)
+       case 6:
+               if (unlikely(iph_len < sizeof(struct ipv6hdr)))
+                       return -EINVAL;
+
+               if (sk->sk_family != AF_INET6)
+                       return -EINVAL;
+
+               mss = tcp_v6_get_syncookie(sk, iph, th, &cookie);
+               break;
+#endif /* CONFIG_IPV6 */
+
+       default:
+               return -EPROTONOSUPPORT;
+       }
+       if (mss == 0)
+               return -ENOENT;
+
+       return cookie | ((u64)mss << 32);
+#else
+       return -EOPNOTSUPP;
+#endif /* CONFIG_SYN_COOKIES */
+}
+
+static const struct bpf_func_proto bpf_tcp_gen_syncookie_proto = {
+       .func           = bpf_tcp_gen_syncookie,
+       .gpl_only       = true, /* __cookie_v*_init_sequence() is GPL */
+       .pkt_access     = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_SOCK_COMMON,
+       .arg2_type      = ARG_PTR_TO_MEM,
+       .arg3_type      = ARG_CONST_SIZE,
+       .arg4_type      = ARG_PTR_TO_MEM,
+       .arg5_type      = ARG_CONST_SIZE,
+};
+
 #endif /* CONFIG_INET */
 
 bool bpf_helper_changes_pkt_data(void *func)
@@ -5999,6 +6075,8 @@ sk_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_get_socket_cookie_proto;
        case BPF_FUNC_get_socket_uid:
                return &bpf_get_socket_uid_proto;
+       case BPF_FUNC_perf_event_output:
+               return &bpf_skb_event_output_proto;
        default:
                return bpf_base_func_proto(func_id);
        }
@@ -6019,6 +6097,8 @@ cg_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_sk_storage_get_proto;
        case BPF_FUNC_sk_storage_delete:
                return &bpf_sk_storage_delete_proto;
+       case BPF_FUNC_perf_event_output:
+               return &bpf_skb_event_output_proto;
 #ifdef CONFIG_SOCK_CGROUP_DATA
        case BPF_FUNC_skb_cgroup_id:
                return &bpf_skb_cgroup_id_proto;
@@ -6135,6 +6215,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_tcp_check_syncookie_proto;
        case BPF_FUNC_skb_ecn_set_ce:
                return &bpf_skb_ecn_set_ce_proto;
+       case BPF_FUNC_tcp_gen_syncookie:
+               return &bpf_tcp_gen_syncookie_proto;
 #endif
        default:
                return bpf_base_func_proto(func_id);
@@ -6174,6 +6256,8 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_xdp_skc_lookup_tcp_proto;
        case BPF_FUNC_tcp_check_syncookie:
                return &bpf_tcp_check_syncookie_proto;
+       case BPF_FUNC_tcp_gen_syncookie:
+               return &bpf_tcp_gen_syncookie_proto;
 #endif
        default:
                return bpf_base_func_proto(func_id);
@@ -6267,6 +6351,8 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_sk_redirect_map_proto;
        case BPF_FUNC_sk_redirect_hash:
                return &bpf_sk_redirect_hash_proto;
+       case BPF_FUNC_perf_event_output:
+               return &bpf_skb_event_output_proto;
 #ifdef CONFIG_INET
        case BPF_FUNC_sk_lookup_tcp:
                return &bpf_sk_lookup_tcp_proto;
@@ -8757,13 +8843,13 @@ sk_reuseport_is_valid_access(int off, int size,
                return size == size_default;
 
        /* Fields that allow narrowing */
-       case offsetof(struct sk_reuseport_md, eth_protocol):
+       case bpf_ctx_range(struct sk_reuseport_md, eth_protocol):
                if (size < FIELD_SIZEOF(struct sk_buff, protocol))
                        return false;
                /* fall through */
-       case offsetof(struct sk_reuseport_md, ip_protocol):
-       case offsetof(struct sk_reuseport_md, bind_inany):
-       case offsetof(struct sk_reuseport_md, len):
+       case bpf_ctx_range(struct sk_reuseport_md, ip_protocol):
+       case bpf_ctx_range(struct sk_reuseport_md, bind_inany):
+       case bpf_ctx_range(struct sk_reuseport_md, len):
                bpf_ctx_record_field_size(info, size_default);
                return bpf_ctx_narrow_access_ok(off, size, size_default);