Commit b8c62fe2 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'Support direct writes to nf_conn:mark'

Daniel Xu says:

====================

Support direct writes to nf_conn:mark from TC and XDP prog types. This
is useful when applications want to store per-connection metadata. This
is also particularly useful for applications that run both bpf and
iptables/nftables because the latter can trivially access this metadata.

One example use case would be if a bpf prog is responsible for advanced
packet classification and iptables/nftables is later used for routing
due to pre-existing/legacy code.

Past discussion:
- v4: https://lore.kernel.org/bpf/cover.1661192455.git.dxu@dxuuu.xyz/
- v3: https://lore.kernel.org/bpf/cover.1660951028.git.dxu@dxuuu.xyz/
- v2: https://lore.kernel.org/bpf/CAP01T74Sgn354dXGiFWFryu4vg+o8b9s9La1d9zEbC4LGvH4qg@mail.gmail.com/T/
- v1: https://lore.kernel.org/bpf/cover.1660592020.git.dxu@dxuuu.xyz/



Changes since v4:
- Use exported function pointer + mutex to handle CONFIG_NF_CONNTRACK=m
  case

Changes since v3:
- Use a mutex to protect module load/unload critical section

Changes since v2:
- Remove use of NOT_INIT for btf_struct_access write path
- Disallow nf_conn writing when nf_conntrack module not loaded
- Support writing to nf_conn___init:mark

Changes since v1:
- Add unimplemented stub for when !CONFIG_BPF_SYSCALL
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 57c92f11 e2d75e95
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -2211,6 +2211,15 @@ static inline struct bpf_prog *bpf_prog_by_id(u32 id)
	return ERR_PTR(-ENOTSUPP);
}

static inline int btf_struct_access(struct bpf_verifier_log *log,
				    const struct btf *btf,
				    const struct btf_type *t, int off, int size,
				    enum bpf_access_type atype,
				    u32 *next_btf_id, enum bpf_type_flag *flag)
{
	return -EACCES;
}

static inline const struct bpf_func_proto *
bpf_base_func_proto(enum bpf_func_id func_id)
{
+23 −0
Original line number Diff line number Diff line
@@ -3,13 +3,22 @@
#ifndef _NF_CONNTRACK_BPF_H
#define _NF_CONNTRACK_BPF_H

#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/kconfig.h>
#include <linux/mutex.h>

#if (IS_BUILTIN(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) || \
    (IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES))

extern int register_nf_conntrack_bpf(void);
extern void cleanup_nf_conntrack_bpf(void);

extern struct mutex nf_conn_btf_access_lock;
extern int (*nfct_bsa)(struct bpf_verifier_log *log, const struct btf *btf,
		       const struct btf_type *t, int off, int size,
		       enum bpf_access_type atype, u32 *next_btf_id,
		       enum bpf_type_flag *flag);

#else

@@ -18,6 +27,20 @@ static inline int register_nf_conntrack_bpf(void)
	return 0;
}

static inline void cleanup_nf_conntrack_bpf(void)
{
}

static inline int nf_conntrack_btf_struct_access(struct bpf_verifier_log *log,
						 const struct btf *btf,
						 const struct btf_type *t, int off,
						 int size, enum bpf_access_type atype,
						 u32 *next_btf_id,
						 enum bpf_type_flag *flag)
{
	return -EACCES;
}

#endif

#endif /* _NF_CONNTRACK_BPF_H */
+1 −0
Original line number Diff line number Diff line
@@ -818,6 +818,7 @@ const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
		return NULL;
	return btf->types[type_id];
}
EXPORT_SYMBOL_GPL(btf_type_by_id);

/*
 * Regular int is not a bit field and it must be either
+1 −3
Original line number Diff line number Diff line
@@ -370,6 +370,7 @@ __printf(2, 3) void bpf_log(struct bpf_verifier_log *log,
	bpf_verifier_vlog(log, fmt, args);
	va_end(args);
}
EXPORT_SYMBOL_GPL(bpf_log);

static const char *ltrim(const char *s)
{
@@ -13406,9 +13407,6 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
				insn->code = BPF_LDX | BPF_PROBE_MEM |
					BPF_SIZE((insn)->code);
				env->prog->aux->num_exentries++;
			} else if (resolve_prog_type(env->prog) != BPF_PROG_TYPE_STRUCT_OPS) {
				verbose(env, "Writes through BTF pointers are not allowed\n");
				return -EINVAL;
			}
			continue;
		default:
+54 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
 */

#include <linux/atomic.h>
#include <linux/bpf_verifier.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
@@ -8604,6 +8605,36 @@ static bool tc_cls_act_is_valid_access(int off, int size,
	return bpf_skb_is_valid_access(off, size, type, prog, info);
}

DEFINE_MUTEX(nf_conn_btf_access_lock);
EXPORT_SYMBOL_GPL(nf_conn_btf_access_lock);

int (*nfct_bsa)(struct bpf_verifier_log *log, const struct btf *btf,
		const struct btf_type *t, int off, int size,
		enum bpf_access_type atype, u32 *next_btf_id,
		enum bpf_type_flag *flag);
EXPORT_SYMBOL_GPL(nfct_bsa);

static int tc_cls_act_btf_struct_access(struct bpf_verifier_log *log,
					const struct btf *btf,
					const struct btf_type *t, int off,
					int size, enum bpf_access_type atype,
					u32 *next_btf_id,
					enum bpf_type_flag *flag)
{
	int ret = -EACCES;

	if (atype == BPF_READ)
		return btf_struct_access(log, btf, t, off, size, atype, next_btf_id,
					 flag);

	mutex_lock(&nf_conn_btf_access_lock);
	if (nfct_bsa)
		ret = nfct_bsa(log, btf, t, off, size, atype, next_btf_id, flag);
	mutex_unlock(&nf_conn_btf_access_lock);

	return ret;
}

static bool __is_valid_xdp_access(int off, int size)
{
	if (off < 0 || off >= sizeof(struct xdp_md))
@@ -8663,6 +8694,27 @@ void bpf_warn_invalid_xdp_action(struct net_device *dev, struct bpf_prog *prog,
}
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action);

static int xdp_btf_struct_access(struct bpf_verifier_log *log,
				 const struct btf *btf,
				 const struct btf_type *t, int off,
				 int size, enum bpf_access_type atype,
				 u32 *next_btf_id,
				 enum bpf_type_flag *flag)
{
	int ret = -EACCES;

	if (atype == BPF_READ)
		return btf_struct_access(log, btf, t, off, size, atype, next_btf_id,
					 flag);

	mutex_lock(&nf_conn_btf_access_lock);
	if (nfct_bsa)
		ret = nfct_bsa(log, btf, t, off, size, atype, next_btf_id, flag);
	mutex_unlock(&nf_conn_btf_access_lock);

	return ret;
}

static bool sock_addr_is_valid_access(int off, int size,
				      enum bpf_access_type type,
				      const struct bpf_prog *prog,
@@ -10557,6 +10609,7 @@ const struct bpf_verifier_ops tc_cls_act_verifier_ops = {
	.convert_ctx_access	= tc_cls_act_convert_ctx_access,
	.gen_prologue		= tc_cls_act_prologue,
	.gen_ld_abs		= bpf_gen_ld_abs,
	.btf_struct_access	= tc_cls_act_btf_struct_access,
};

const struct bpf_prog_ops tc_cls_act_prog_ops = {
@@ -10568,6 +10621,7 @@ const struct bpf_verifier_ops xdp_verifier_ops = {
	.is_valid_access	= xdp_is_valid_access,
	.convert_ctx_access	= xdp_convert_ctx_access,
	.gen_prologue		= bpf_noop_prologue,
	.btf_struct_access	= xdp_btf_struct_access,
};

const struct bpf_prog_ops xdp_prog_ops = {
Loading