Merge tag 'powerpc-5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-microblaze.git] / include / linux / filter.h
index 0b01447..0a355b0 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/kallsyms.h>
 #include <linux/if_vlan.h>
 #include <linux/vmalloc.h>
+#include <linux/sockptr.h>
 #include <crypto/sha.h>
 
 #include <net/sch_generic.h>
@@ -502,13 +503,11 @@ static inline bool insn_is_zext(const struct bpf_insn *insn)
                offsetof(TYPE, MEMBER);                                         \
        })
 
-#ifdef CONFIG_COMPAT
 /* A struct sock_filter is architecture independent. */
 struct compat_sock_fprog {
        u16             len;
        compat_uptr_t   filter; /* struct sock_filter * */
 };
-#endif
 
 struct sock_fprog_kern {
        u16                     len;
@@ -534,7 +533,8 @@ struct bpf_prog {
                                is_func:1,      /* program is a bpf function */
                                kprobe_override:1, /* Do we override a kprobe? */
                                has_callchain_buf:1, /* callchain buffer allocated? */
-                               enforce_expected_attach_type:1; /* Enforce expected_attach_type checking at attach time */
+                               enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */
+                               call_get_stack:1; /* Do we call bpf_get_stack() or bpf_get_stackid() */
        enum bpf_prog_type      type;           /* Type of BPF program */
        enum bpf_attach_type    expected_attach_type; /* For some prog types */
        u32                     len;            /* Number of filter blocks */
@@ -1278,4 +1278,153 @@ struct bpf_sockopt_kern {
        s32             retval;
 };
 
+int copy_bpf_fprog_from_user(struct sock_fprog *dst, sockptr_t src, int len);
+
+struct bpf_sk_lookup_kern {
+       u16             family;
+       u16             protocol;
+       struct {
+               __be32 saddr;
+               __be32 daddr;
+       } v4;
+       struct {
+               const struct in6_addr *saddr;
+               const struct in6_addr *daddr;
+       } v6;
+       __be16          sport;
+       u16             dport;
+       struct sock     *selected_sk;
+       bool            no_reuseport;
+};
+
+extern struct static_key_false bpf_sk_lookup_enabled;
+
+/* Runners for BPF_SK_LOOKUP programs to invoke on socket lookup.
+ *
+ * Allowed return values for a BPF SK_LOOKUP program are SK_PASS and
+ * SK_DROP. Their meaning is as follows:
+ *
+ *  SK_PASS && ctx.selected_sk != NULL: use selected_sk as lookup result
+ *  SK_PASS && ctx.selected_sk == NULL: continue to htable-based socket lookup
+ *  SK_DROP                           : terminate lookup with -ECONNREFUSED
+ *
+ * This macro aggregates return values and selected sockets from
+ * multiple BPF programs according to following rules in order:
+ *
+ *  1. If any program returned SK_PASS and a non-NULL ctx.selected_sk,
+ *     macro result is SK_PASS and last ctx.selected_sk is used.
+ *  2. If any program returned SK_DROP return value,
+ *     macro result is SK_DROP.
+ *  3. Otherwise result is SK_PASS and ctx.selected_sk is NULL.
+ *
+ * Caller must ensure that the prog array is non-NULL, and that the
+ * array as well as the programs it contains remain valid.
+ */
+#define BPF_PROG_SK_LOOKUP_RUN_ARRAY(array, ctx, func)                 \
+       ({                                                              \
+               struct bpf_sk_lookup_kern *_ctx = &(ctx);               \
+               struct bpf_prog_array_item *_item;                      \
+               struct sock *_selected_sk = NULL;                       \
+               bool _no_reuseport = false;                             \
+               struct bpf_prog *_prog;                                 \
+               bool _all_pass = true;                                  \
+               u32 _ret;                                               \
+                                                                       \
+               migrate_disable();                                      \
+               _item = &(array)->items[0];                             \
+               while ((_prog = READ_ONCE(_item->prog))) {              \
+                       /* restore most recent selection */             \
+                       _ctx->selected_sk = _selected_sk;               \
+                       _ctx->no_reuseport = _no_reuseport;             \
+                                                                       \
+                       _ret = func(_prog, _ctx);                       \
+                       if (_ret == SK_PASS && _ctx->selected_sk) {     \
+                               /* remember last non-NULL socket */     \
+                               _selected_sk = _ctx->selected_sk;       \
+                               _no_reuseport = _ctx->no_reuseport;     \
+                       } else if (_ret == SK_DROP && _all_pass) {      \
+                               _all_pass = false;                      \
+                       }                                               \
+                       _item++;                                        \
+               }                                                       \
+               _ctx->selected_sk = _selected_sk;                       \
+               _ctx->no_reuseport = _no_reuseport;                     \
+               migrate_enable();                                       \
+               _all_pass || _selected_sk ? SK_PASS : SK_DROP;          \
+        })
+
+static inline bool bpf_sk_lookup_run_v4(struct net *net, int protocol,
+                                       const __be32 saddr, const __be16 sport,
+                                       const __be32 daddr, const u16 dport,
+                                       struct sock **psk)
+{
+       struct bpf_prog_array *run_array;
+       struct sock *selected_sk = NULL;
+       bool no_reuseport = false;
+
+       rcu_read_lock();
+       run_array = rcu_dereference(net->bpf.run_array[NETNS_BPF_SK_LOOKUP]);
+       if (run_array) {
+               struct bpf_sk_lookup_kern ctx = {
+                       .family         = AF_INET,
+                       .protocol       = protocol,
+                       .v4.saddr       = saddr,
+                       .v4.daddr       = daddr,
+                       .sport          = sport,
+                       .dport          = dport,
+               };
+               u32 act;
+
+               act = BPF_PROG_SK_LOOKUP_RUN_ARRAY(run_array, ctx, BPF_PROG_RUN);
+               if (act == SK_PASS) {
+                       selected_sk = ctx.selected_sk;
+                       no_reuseport = ctx.no_reuseport;
+               } else {
+                       selected_sk = ERR_PTR(-ECONNREFUSED);
+               }
+       }
+       rcu_read_unlock();
+       *psk = selected_sk;
+       return no_reuseport;
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static inline bool bpf_sk_lookup_run_v6(struct net *net, int protocol,
+                                       const struct in6_addr *saddr,
+                                       const __be16 sport,
+                                       const struct in6_addr *daddr,
+                                       const u16 dport,
+                                       struct sock **psk)
+{
+       struct bpf_prog_array *run_array;
+       struct sock *selected_sk = NULL;
+       bool no_reuseport = false;
+
+       rcu_read_lock();
+       run_array = rcu_dereference(net->bpf.run_array[NETNS_BPF_SK_LOOKUP]);
+       if (run_array) {
+               struct bpf_sk_lookup_kern ctx = {
+                       .family         = AF_INET6,
+                       .protocol       = protocol,
+                       .v6.saddr       = saddr,
+                       .v6.daddr       = daddr,
+                       .sport          = sport,
+                       .dport          = dport,
+               };
+               u32 act;
+
+               act = BPF_PROG_SK_LOOKUP_RUN_ARRAY(run_array, ctx, BPF_PROG_RUN);
+               if (act == SK_PASS) {
+                       selected_sk = ctx.selected_sk;
+                       no_reuseport = ctx.no_reuseport;
+               } else {
+                       selected_sk = ERR_PTR(-ECONNREFUSED);
+               }
+       }
+       rcu_read_unlock();
+       *psk = selected_sk;
+       return no_reuseport;
+}
+#endif /* IS_ENABLED(CONFIG_IPV6) */
+
 #endif /* __LINUX_FILTER_H__ */