]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: Add syscall common attributes support for prog_load
authorLeon Hwang <leon.hwang@linux.dev>
Tue, 12 May 2026 15:31:53 +0000 (23:31 +0800)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 12 May 2026 19:44:41 +0000 (12:44 -0700)
BPF_PROG_LOAD can now take log parameters from both union bpf_attr and
struct bpf_common_attr. The merge rules are:

- if both sides provide a complete log tuple (buf/size/level) and they
  match, use it;
- if only one side provides log parameters, use that one;
- if both sides provide complete tuples but they differ, return -EINVAL.

Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
Link: https://lore.kernel.org/r/20260512153157.28382-5-leon.hwang@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf_verifier.h
kernel/bpf/log.c
kernel/bpf/syscall.c

index 8d27ad1f9f9458009aa521c12d30d9c67f805512..8433430dedb7abef15e2f8443751743fccccc110 100644 (file)
@@ -764,7 +764,8 @@ struct bpf_log_attr {
 };
 
 int bpf_log_attr_init(struct bpf_log_attr *log, u64 log_buf, u32 log_size, u32 log_level,
-                     u32 offsetof_log_true_size, bpfptr_t uattr);
+                     u32 offsetof_log_true_size, bpfptr_t uattr, struct bpf_common_attr *common,
+                     bpfptr_t uattr_common, u32 size_common);
 int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log *log);
 
 #define BPF_MAX_SUBPROGS 256
index 1b1efe75398b7702fcadfa9f7c96c34c93b64d91..fd12ad5a0338d84804f18e8f020a8fb9671245ee 100644 (file)
 
 #define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args)
 
-static bool bpf_verifier_log_attr_valid(const struct bpf_verifier_log *log)
+static bool bpf_verifier_log_attr_valid(u32 log_level, char __user *log_buf, u32 log_size)
 {
        /* ubuf and len_total should both be specified (or not) together */
-       if (!!log->ubuf != !!log->len_total)
+       if (!!log_buf != !!log_size)
                return false;
        /* log buf without log_level is meaningless */
-       if (log->ubuf && log->level == 0)
+       if (log_buf && log_level == 0)
                return false;
-       if (log->level & ~BPF_LOG_MASK)
+       if (log_level & ~BPF_LOG_MASK)
                return false;
-       if (log->len_total > UINT_MAX >> 2)
+       if (log_size > UINT_MAX >> 2)
                return false;
        return true;
 }
@@ -36,7 +36,7 @@ int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level,
        log->len_total = log_size;
 
        /* log attributes have to be sane */
-       if (!bpf_verifier_log_attr_valid(log))
+       if (!bpf_verifier_log_attr_valid(log_level, log_buf, log_size))
                return -EINVAL;
 
        return 0;
@@ -827,16 +827,36 @@ void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_st
 }
 
 int bpf_log_attr_init(struct bpf_log_attr *log, u64 log_buf, u32 log_size, u32 log_level,
-                     u32 offsetof_log_true_size, bpfptr_t uattr)
+                     u32 offsetof_log_true_size, bpfptr_t uattr, struct bpf_common_attr *common,
+                     bpfptr_t uattr_common, u32 size_common)
 {
+       char __user *ubuf_common = u64_to_user_ptr(common->log_buf);
        char __user *ubuf = u64_to_user_ptr(log_buf);
 
+       if (!bpf_verifier_log_attr_valid(common->log_level, ubuf_common, common->log_size) ||
+           !bpf_verifier_log_attr_valid(log_level, ubuf, log_size))
+               return -EINVAL;
+
+       if (ubuf && ubuf_common && (ubuf != ubuf_common || log_size != common->log_size ||
+                                   log_level != common->log_level))
+               return -EINVAL;
+
        memset(log, 0, sizeof(*log));
        log->ubuf = ubuf;
        log->size = log_size;
        log->level = log_level;
        log->offsetof_true_size = offsetof_log_true_size;
        log->uattr = uattr;
+
+       if (!ubuf && ubuf_common) {
+               log->ubuf = ubuf_common;
+               log->size = common->log_size;
+               log->level = common->log_level;
+               log->uattr = uattr_common;
+               log->offsetof_true_size = 0;
+               if (size_common >= offsetofend(struct bpf_common_attr, log_true_size))
+                       log->offsetof_true_size = offsetof(struct bpf_common_attr, log_true_size);
+       }
        return 0;
 }
 
index 70b78ddcdedbe98cc8203e9a896dad4ff5252d46..db893cae826c47b4b77308663920e215205daea1 100644 (file)
@@ -6271,7 +6271,8 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size,
                if (size >= offsetofend(union bpf_attr, log_true_size))
                        offsetof_log_true_size = offsetof(union bpf_attr, log_true_size);
                err = bpf_log_attr_init(&attr_log, attr.log_buf, attr.log_size, attr.log_level,
-                                       offsetof_log_true_size, uattr);
+                                       offsetof_log_true_size, uattr, &attr_common, uattr_common,
+                                       size_common);
                err = err ?: bpf_prog_load(&attr, uattr, &attr_log);
                break;
        case BPF_OBJ_PIN: