From nobody Tue Apr 7 19:55:53 2026 Received: from mail-oo1-f42.google.com (mail-oo1-f42.google.com [209.85.161.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3EF8931F9B7 for ; Wed, 11 Mar 2026 21:31:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264687; cv=none; b=blU0rJunuR10NwVdldncCf9UiP/1spa3lzWwdo33BGLmfieq2SwUdm27X8ZdXmhl5mD4+M2oRgbY1HnRqYmaWhO7XKXBShMBbMGsjD35WLYz8M2fbYaZKA/Mjiy/FRacsozv+Hzrg1tURO8ZBZn+2GcBMzxXBh0Nh/aHAgQRGjs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264687; c=relaxed/simple; bh=6R7DImnsXBYJQBnefaWTz+XuDxYsvyJzUXRjb8C9Zz0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BKnufDyYapcw2CEabM3WBokT7fSS3ARpHTM9Lq8Jbn47I5Ro9jL92sgqNwVpYsGt0nSg3+9JRzlNR2odC6uAN9bO+XFyvKSywfXR6dw0C3w/KJVCGLC/Z4Sb4CCbU5CXLoyzvHh4JDHXOOrAcsBe9s0Y3ZknLZ4v4UiRBl4B5Dc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com; spf=pass smtp.mailfrom=cloudflare.com; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b=bjVo+zPT; arc=none smtp.client-ip=209.85.161.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="bjVo+zPT" Received: by mail-oo1-f42.google.com with SMTP id 006d021491bc7-67bad873c3eso224917eaf.3 for ; Wed, 11 Mar 2026 14:31:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google09082023; t=1773264685; x=1773869485; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=IX29AT46QQIcV+IR2GwkNddbkT1RbF8B8LfUKka7CdA=; b=bjVo+zPTtgTxZPoN2j4ZrV+iBff4bksbpLHcrtPELGuKCmkpxUfSGJmdGdEON+oHtn 4uLSK7fXRN8ywnaEgvehDJHVGtsNp0pqx3tJ9V4h59fVZSWSIH1xLo2Ft7Lk6GnAw/Nl 5UxFzudW1xw+DQXGctCzzQXBFW1NVXnPyIBwdVZMrc0Ba2hdnSXAvO1k2koOmNnj6TQu UfD9ViEg3qy4slBIGQnPgs29a7tOjaT29Sc9t/wZW0sn4NZGyM6Kh3xJia6A/iOWrg7M dyCge7jSksFpQs1qgRjtAcG+bJ+wol7cXMGfvolpBSSjvJKVEVjn4s2g3r6/N0Ut9Xpm T3HQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773264685; x=1773869485; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=IX29AT46QQIcV+IR2GwkNddbkT1RbF8B8LfUKka7CdA=; b=OXG+61AILibJrRo1O2GV4360zFKpfIcF3/sd14p0pSw84YDOF7EYztxgBbUzEbqZFz CfCULAAWx2BFyYjVOLlV2YmTEYgc3Uvpfe/aRReisNGtUkBtxYWH8zljNKzsqv/jSw4J 9db57b0/7hbm9XLkPcBLUrxzYcwDBubY2RO/nguyBCtLn6jJ+N9CR7xv95tlrFpIMsLD DcibLDl1hL1tXzu4v7uHssXeMrDa18+U275Bt0j3l24qp64OzWeuRnszwmKT8NjnVpKt HPbqw0nbOIgiIGd9nrSuuCg7OGWMSHXhdPcjEARt45CSwI3ENRLd7Wo7EMw3j9Cty2Sk mapA== X-Gm-Message-State: AOJu0YznNyDQFfBfKxhBKxlWWsn4DS3LXUthQF1KC8gjtEDSu+OhQ3HI 9hlXWd1AQV7lrUrlajoGZ3ZU4hGgjIhVXiKn3FzkFCcDcJ58MYFeyWAsXEZ+C5nO0GY= X-Gm-Gg: ATEYQzy8r9bAvb3lCNsrTbBPavpTU5v6XyoxtQs10aV1FV0OTvxAOrHs4L/e0Kl2xdE XKnjgdgA185HmF72tqm4XHrBgyVFvK1F0on5Mee4X1QSJmWXMbs5/pBy6l+E5ix/g/FOpNdgBBB 97QOHV8zhlELXA74trOnfEg2U+dSras9NoAdQ/D6obnN6eODc/+/YIJwb2O7kYcXVl/hZM3WBO/ v0aMLYvZbtsGGhgXrrEW1G304VYWZtOD4DTvVZA+MmB+HBK3N5H2B6R8ieKC+Zadbfwx3OsNeRS fIPaq8EwtunXGg1Pc1v1yfwTvLZxoCbb99wnbqhwOlji868yo3fv4LwNY40VgB8VRt5IQ5WthAZ Wgz/wraesgJjghEzN4f5wLlVgQUe0aXMCsG1oV76UIrlVuopJJ4Sfi/86unOLGCDRwx9MrnRXwN QmydAystY= X-Received: by 2002:a05:6820:1a06:b0:679:be0c:8b54 with SMTP id 006d021491bc7-67bc88780f7mr2728421eaf.5.1773264684867; Wed, 11 Mar 2026 14:31:24 -0700 (PDT) Received: from [127.0.1.1] ([2a09:bac5:947d:4e6::7d:82]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4177e1fb90csm3530413fac.4.2026.03.11.14.31.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Mar 2026 14:31:24 -0700 (PDT) From: Frederick Lawler Date: Wed, 11 Mar 2026 16:31:17 -0500 Subject: [PATCH RFC bpf-next 1/4] audit: Implement bpf_audit_log_*() wrappers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260311-bpf-auditd-send-message-v1-1-10a62db5c92f@cloudflare.com> References: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> In-Reply-To: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> To: Paul Moore , James Morris , "Serge E. Hallyn" , Eric Paris , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , =?utf-8?q?G=C3=BCnther_Noack?= Cc: linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, audit@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@cloudflare.com, Frederick Lawler X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=11097; i=fred@cloudflare.com; h=from:subject:message-id; bh=6R7DImnsXBYJQBnefaWTz+XuDxYsvyJzUXRjb8C9Zz0=; b=owEBbQKS/ZANAwAKAasltHYDktNtAcsmYgBpsd8nAVEDVeVoA/J51G/He85tYdUpq8FlBqjPK SMUHy6glcuJAjMEAAEKAB0WIQTLNBqMVmu1PHvjOe2rJbR2A5LTbQUCabHfJwAKCRCrJbR2A5LT bQiREACSw+lxbX7Na2XyaP4JiFdPIVB3jQEUE3BFi2o72reP0VE75EdCWz2P+GZxt9jR6K+SEp1 yM1a1xuwuNeAsZvHqz1qkKk15vflf0f2f1At7nmGsnYNAmBgK0J0Vx9sXnAAZDVi1fR0FLA1Zgd uv0NYhT0tgb/y6V70YfKT5ylbKq0sHh+syok7+Ty/fW69q/a6lxKI4BvqKcV2V2o09ub1mmlWka siyS9tkx9CtRm0j9GFJw80z4XxuZGI67/qkFzAwthhL5kEN3zm9mo3hPAj2DnhJu4OmYKCejgen elbVQWB3OgdTd2cZtIqiq/uij6FjFjOjeFH7XAWDUMt1dtE5z9vk2rdHG0fIJKBdQi7f6A61Zgq j9FS0VVJq/rCxMiX9LPLSr2bsjzY2gbaitUF5BwmY83hV1PXG5NgOHIiIH4Tdy9tz9Uo+ztznIU SpxZLB/E/W8UoochkcNWBkgc9S5o8lLCLDbGnWuRF/77Khwu8BlNpn8UHxGdTpCwM/iU9q9gvU1 K2/gFoeon2B5RLVkdce3dYF2oxyD7Ybdjcl4fu9lXM7uNLYr4ccvGlvQrungOKUDHhPNDQM+fH+ Ky6bvS1Cj9VVeXSaBS6k3UIh6cEj2GIP/nwxqPFiE5GGWZaXi0Hw4AOCCPff5LAOmL0bTd9KQa7 c4I7tNtZQ8kOioQ== X-Developer-Key: i=fred@cloudflare.com; a=openpgp; fpr=CB341A8C566BB53C7BE339EDAB25B4760392D36D The primary use case is to provide LSM designers a direct API to report access allow/denies through the audit subsystem similar to how LSM's traditionally log their accesses. Left out from this API are functions that are potentially abuseable such as audit_log_format() where users may fill any field=3Dvalue pair. Instead, the API mostly follows what is exposed through security/lsm_audit.c for consistency with user space audit expectations. Further calls to functions report once to avoid repeated-call abuse. Lastly, each audit record corresponds to the loaded BPF program's ID to track which program reported the log entry. This helps remove ambiguity in the event multiple programs are registered to the same security hook. Exposed functions: bpf_audit_log_start() bpf_audit_log_end() bpf_audit_log_cause() bpf_audit_log_cap() bpf_audit_log_path() bpf_audit_log_file() bpf_audit_log_ioctl_op() bpf_audit_log_dentry() bpf_audit_log_inode() bpf_audit_log_task() bpf_audit_log_net_sock() bpf_audit_log_net_sockaddr() Signed-off-by: Frederick Lawler --- include/linux/lsm_audit.h | 1 + include/uapi/linux/audit.h | 1 + security/lsm_audit_kfuncs.c | 306 ++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 308 insertions(+) diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 382c56a97bba1d0e5efe082553338229d541e267..859f51590de417ac246309eb75a= 760b8632224be 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -78,6 +78,7 @@ struct common_audit_data { #define LSM_AUDIT_DATA_NOTIFICATION 16 #define LSM_AUDIT_DATA_ANONINODE 17 #define LSM_AUDIT_DATA_NLMSGTYPE 18 +#define LSM_AUDIT_DATA_CAUSE 19 /* unused */ union { struct path path; struct dentry *dentry; diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 14a1c1fe013acecb12ea6bf81690965421baa7ff..7a22e214fe3e421decfc4109d2e= 6a3cee996fe51 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -150,6 +150,7 @@ #define AUDIT_LANDLOCK_DOMAIN 1424 /* Landlock domain status */ #define AUDIT_MAC_TASK_CONTEXTS 1425 /* Multiple LSM task contexts */ #define AUDIT_MAC_OBJ_CONTEXTS 1426 /* Multiple LSM objext contexts */ +#define AUDIT_BPF_LSM_ACCESS 1427 /* LSM BPF MAC events */ =20 #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 diff --git a/security/lsm_audit_kfuncs.c b/security/lsm_audit_kfuncs.c new file mode 100644 index 0000000000000000000000000000000000000000..0d4fb20be34a61db29aa2c48d2a= efc39131e73bf --- /dev/null +++ b/security/lsm_audit_kfuncs.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2026 Cloudflare */ + +#include +#include +#include +#include +#include +#include +#include + +struct bpf_audit_context { + struct audit_buffer *ab; + u64 log_once_mask; +}; + +static struct bpf_mem_alloc bpf_audit_context_ma; + +static inline u64 log_once(struct bpf_audit_context *ac, u64 mask) +{ + u64 set =3D (ac->log_once_mask & mask); + + ac->log_once_mask |=3D mask; + return set; +} + +static inline int __audit_log_lsm_data(struct bpf_audit_context *ac, + struct common_audit_data *ad) +{ + if (log_once(ac, BIT_ULL(ad->type))) + return -EINVAL; + + audit_log_lsm_data(ac->ab, ad); + return 0; +} + +__bpf_kfunc_start_defs(); + +__bpf_kfunc +struct bpf_audit_context *bpf_audit_log_start(struct bpf_prog_aux *aux) +{ + char comm[sizeof(current->comm)]; + struct bpf_audit_context *ac; + + ac =3D bpf_mem_cache_alloc(&bpf_audit_context_ma); + if (!ac) + return NULL; + + memset(ac, 0, sizeof(*ac)); + ac->ab =3D audit_log_start(audit_context(), + (aux->might_sleep) ? GFP_KERNEL : GFP_ATOMIC, + AUDIT_BPF_LSM_ACCESS); + if (!ac->ab) { + bpf_mem_cache_free(&bpf_audit_context_ma, ac); + return NULL; + } + + audit_log_format(ac->ab, "prog-id=3D%d", aux->id); + + /* Audit may not have a filter configured for syscalls. Include + * potentionally redundant pid & comm information + */ + audit_log_format(ac->ab, " pid=3D%d comm=3D", task_tgid_nr(current)); + audit_log_untrustedstring(ac->ab, get_task_comm(comm, current)); + + return ac; +} + +__bpf_kfunc void bpf_audit_log_end(struct bpf_audit_context *ac) +{ + audit_log_end(ac->ab); + bpf_mem_cache_free(&bpf_audit_context_ma, ac); +} + +__bpf_kfunc int bpf_audit_log_cause(struct bpf_audit_context *ac, + const char *cause__str) +{ + if (log_once(ac, BIT_ULL(LSM_AUDIT_DATA_CAUSE))) + return -EINVAL; + + audit_log_format(ac->ab, " cause=3D"); + audit_log_untrustedstring(ac->ab, cause__str); + return 0; +} + +__bpf_kfunc int bpf_audit_log_cap(struct bpf_audit_context *ac, int cap) +{ + struct common_audit_data ad; + + ad.type =3D LSM_AUDIT_DATA_CAP; + ad.u.cap =3D cap; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int bpf_audit_log_path(struct bpf_audit_context *ac, + const struct path *path) +{ + struct common_audit_data ad; + + /* DATA_PATH prints similar to DATA_FILE */ + if (log_once(ac, BIT_ULL(LSM_AUDIT_DATA_FILE))) + return -EINVAL; + + ad.type =3D LSM_AUDIT_DATA_PATH; + ad.u.path =3D *path; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int bpf_audit_log_file(struct bpf_audit_context *ac, + struct file *file) +{ + struct common_audit_data ad; + + /* DATA_PATH prints similar to DATA_FILE */ + if (log_once(ac, BIT_ULL(LSM_AUDIT_DATA_PATH))) + return -EINVAL; + + ad.type =3D LSM_AUDIT_DATA_FILE; + ad.u.file =3D file; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int bpf_audit_log_ioctl_op(struct bpf_audit_context *ac, + struct file *file, u16 cmd) +{ + struct lsm_ioctlop_audit op =3D { .path =3D file->f_path, .cmd =3D cmd }; + struct common_audit_data ad; + + ad.type =3D LSM_AUDIT_DATA_IOCTL_OP; + ad.u.op =3D &op; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int bpf_audit_log_dentry(struct bpf_audit_context *ac, + struct dentry *dentry) +{ + struct common_audit_data ad; + + /* DATA_DENTRY prints similar to DATA_INODE */ + if (log_once(ac, BIT_ULL(LSM_AUDIT_DATA_INODE))) + return -EINVAL; + + ad.type =3D LSM_AUDIT_DATA_DENTRY; + ad.u.dentry =3D dentry; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int bpf_audit_log_inode(struct bpf_audit_context *ac, + struct inode *inode) +{ + struct common_audit_data ad; + + /* DATA_DENTRY prints similar to DATA_INODE */ + if (log_once(ac, BIT_ULL(LSM_AUDIT_DATA_DENTRY))) + return -EINVAL; + + ad.type =3D LSM_AUDIT_DATA_INODE; + ad.u.inode =3D inode; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int bpf_audit_log_task(struct bpf_audit_context *ac, + struct task_struct *tsk) +{ + struct common_audit_data ad; + + ad.type =3D LSM_AUDIT_DATA_TASK; + ad.u.tsk =3D tsk; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int bpf_audit_log_net_sock(struct bpf_audit_context *ac, int n= etif, + const struct socket *sock) +{ + struct lsm_network_audit net =3D { .sk =3D sock->sk, .netif =3D netif }; + struct common_audit_data ad; + + ad.type =3D LSM_AUDIT_DATA_NET; + ad.u.net =3D &net; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc int +bpf_audit_log_net_sockaddr(struct bpf_audit_context *ac, int netif, + const struct sockaddr *saddr__nullable, + const struct sockaddr *daddr__nullable, int addrlen) +{ + struct lsm_network_audit net; + struct common_audit_data ad; + + net.netif =3D netif; + + if (!saddr__nullable && !daddr__nullable) + return -EINVAL; + + if (saddr__nullable && daddr__nullable && + saddr__nullable->sa_family !=3D daddr__nullable->sa_family) + return -EINVAL; + + if (saddr__nullable) + net.family =3D saddr__nullable->sa_family; + else + net.family =3D daddr__nullable->sa_family; + + switch (net.family) { +#if IS_ENABLED(CONFIG_IPV6) + case AF_INET6: + if (addrlen < SIN6_LEN_RFC2133) + return -EINVAL; + + if (saddr__nullable) { + struct sockaddr_in6 *saddr =3D + (struct sockaddr_in6 *)saddr__nullable; + net.fam.v6.saddr =3D saddr->sin6_addr; + net.sport =3D saddr->sin6_port; + } + + if (daddr__nullable) { + struct sockaddr_in6 *daddr =3D + (struct sockaddr_in6 *)daddr__nullable; + net.fam.v6.daddr =3D daddr->sin6_addr; + net.dport =3D daddr->sin6_port; + } + break; +#endif + case AF_INET: + if (addrlen < sizeof(struct sockaddr_in)) + return -EINVAL; + + if (saddr__nullable) { + struct sockaddr_in *saddr =3D + (struct sockaddr_in *)saddr__nullable; + net.fam.v4.saddr =3D saddr->sin_addr.s_addr; + net.sport =3D saddr->sin_port; + } + + if (daddr__nullable) { + struct sockaddr_in *daddr =3D + (struct sockaddr_in *)daddr__nullable; + net.fam.v4.daddr =3D daddr->sin_addr.s_addr; + net.dport =3D daddr->sin_port; + } + break; + default: + return -EAFNOSUPPORT; + } + + ad.type =3D LSM_AUDIT_DATA_NET; + ad.u.net =3D &net; + return __audit_log_lsm_data(ac, &ad); +} + +__bpf_kfunc_end_defs(); + +BTF_KFUNCS_START(lsm_audit_set_ids) + +BTF_ID_FLAGS(func, bpf_audit_log_start, + KF_ACQUIRE | KF_DESTRUCTIVE | KF_IMPLICIT_ARGS | KF_RET_NULL); + +BTF_ID_FLAGS(func, bpf_audit_log_end, KF_DESTRUCTIVE | KF_RELEASE); + +/* The following have a recursion opportunity if a LSM is attached to any = of + * the following functions, and a bpf_audit_log_*() is called. + * security_current_getlsmprop_subj, + * security_lsmprop_to_secctx, or + * security_release_secctx + */ +BTF_ID_FLAGS(func, bpf_audit_log_cause, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_cap, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_path, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_file, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_ioctl_op, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_dentry, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_inode, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_task, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_net_sock, KF_DESTRUCTIVE); +BTF_ID_FLAGS(func, bpf_audit_log_net_sockaddr, KF_DESTRUCTIVE); + +BTF_KFUNCS_END(lsm_audit_set_ids) + +static int bpf_lsm_audit_kfuncs_filter(const struct bpf_prog *prog, + u32 kfunc_id) +{ + if (!btf_id_set8_contains(&lsm_audit_set_ids, kfunc_id)) + return 0; + + return prog->type !=3D BPF_PROG_TYPE_LSM ? -EACCES : 0; +} + +static const struct btf_kfunc_id_set bpf_lsm_audit_set =3D { + .owner =3D THIS_MODULE, + .set =3D &lsm_audit_set_ids, + .filter =3D bpf_lsm_audit_kfuncs_filter, +}; + +static int lsm_audit_init_bpf(void) +{ + int ret; + + ret =3D bpf_mem_alloc_init(&bpf_audit_context_ma, + sizeof(struct bpf_audit_context), false); + return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, + &bpf_lsm_audit_set); +} + +late_initcall(lsm_audit_init_bpf) --=20 2.43.0 From nobody Tue Apr 7 19:55:53 2026 Received: from mail-oo1-f52.google.com (mail-oo1-f52.google.com [209.85.161.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 190DC32573F for ; Wed, 11 Mar 2026 21:31:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264689; cv=none; b=rnVLaXT+kl7DgDsiUI4SLeQMiGtc9b7Y5z9y91U1vVNjn3r4Ig2KI2Lm2iBOxCUN3kB0FSaQbLLFz6647iGbHBbjH1gw8mjNvzvAJAnYPcJUW0+rN0wRFSUzbjFDKKN8gvHiA/nDpPECEuhmIfn0gILkfdLEfdgItd3zSjPw8j4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264689; c=relaxed/simple; bh=eQt62HsmlTFVTH5oNb/cY4ErhLI9UlUZljEQgShBvag=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=CUdAqNR4zn+IxLHSThkPQzYqU8ZHtqiCylsG02/Is73zlSbcZHmzW0zruD5+2xmJaUbjEwjS3Bkii6xFKJJfvYuia11fgJhwonGM6CJBKbJ/2uejjU0KkPekmDbXTUee9UsP22XAK9es4DlAlP2wTvoaf3OWEHSfR+OpllMEDPQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com; spf=pass smtp.mailfrom=cloudflare.com; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b=QoL5RXaA; arc=none smtp.client-ip=209.85.161.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="QoL5RXaA" Received: by mail-oo1-f52.google.com with SMTP id 006d021491bc7-67bb5e4cf5aso235351eaf.2 for ; Wed, 11 Mar 2026 14:31:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google09082023; t=1773264687; x=1773869487; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=2qDl6PloJMJcPj6HCRptSktfhbQmRESXzBgsnYOGnNs=; b=QoL5RXaAdisyAHfVSsrxB0gT4OfRwZyl3Oz1RLYShW58vlpfOOQKGdrhsNazgz6yp0 u4/y5EYb09Hckje8Plwul/howQ9l06JVTPtjwumj+IycDnF/RQqb7bVr+hlP/psLCer+ HEXngnEyiMF7QfWvZDnxUNz7mPiUyuKeUMq3cNyjUC4ltzS9KPybVViL3VVvx4WZkEHb +NRs5lNQ3QhGUJnQ5iHYwky/8/jcrXy6D2Ys19erbLTftAOFfIpRapNXNkBPGnYmJ0Lj p9v/mrnwj06PUrb7DTrg8pqQfAHIMk5KIsYvxy0N/yA2SjM3Wzkh6OiJbJuPm4FO88RS EIeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773264687; x=1773869487; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=2qDl6PloJMJcPj6HCRptSktfhbQmRESXzBgsnYOGnNs=; b=ShZWBdXLCYzTSVlN4bn5JY01cg7w1l4KASk79QzQZnkxFEehZVjiNzrbAZiGbriO/9 xs1l19E3n4/8WAl9943y/0VB8QnfLZ+E78ySrdKRnTVqhLaSE2oPD9afc9vPGGxlcc4w Sl67nFAZSWswTHmNXn4vjoNM+LQ6idtyLXkzD3Jr9KJO0Z6Y62+1uzF3A2SUZ0ktK6h9 cGbpITgg5UqNyZ4FrXs08LpQBO/tMg1kH01prHH5PLJjAapsDm7qf4/wqqnqDJrHSrS4 Jv05hJCF3kM4S4OcOeLZ4glRd7vf/p0yCQOegMBnHJxioRPsUk918QBpH/++Zg+H+0LO Krug== X-Gm-Message-State: AOJu0YyszZaZ0XelfoxiUAeh5dnqJOUrR306Ui2+6aU4MKwo8glqM7z/ eVVPft19wjEd13pm92lXm8SWQP8X+MfUiUhvKq0JHpbxG8AJYAHk4etWJNSqtdH28J8= X-Gm-Gg: ATEYQzyMLamBVeJ+LAfLRzWqTpUAC0PLNabzt3HD5eF3k8aKYecrt92dqgtDDiXIJvu fMQ4lGnoPP8p+rP6svEdillNJMY/o0VpNrfOp0yRAtaF/YerhYZxM+pf4t6r8X9TFO5LQYILObn VRvL9/WXPpSd73Ct4PkOfXgGxoenQ82LGDMNd/udnIQCmyHlw6h8X4hK0/vPd/xsL0ARIeTuXh3 0yzTU4zyppHmo558jOVkfzuk9c0Ze9Lksv7jBo3qnCcwZYu1qK5UC2a2yhoRRNZa74oP5LA3nxB SggVewcmaMA2U98jCZIUkuXqlwYt1sX8G66oC4LFxifeayYXnEiVxug4hSrrVTTlH2F0iJ/hmMF fslnRn8yqV1jlZeTEOrGMZJ+AY0OYz0tK5XFxLnGl88eV+eDun7UL/Oihta3PQTUenn6dDsKULO Wn4i7VVTc= X-Received: by 2002:a05:6820:151b:b0:67a:4b7:e2f2 with SMTP id 006d021491bc7-67bc887c20bmr2621254eaf.13.1773264686966; Wed, 11 Mar 2026 14:31:26 -0700 (PDT) Received: from [127.0.1.1] ([2a09:bac5:947d:4e6::7d:82]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4177e1fb90csm3530413fac.4.2026.03.11.14.31.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Mar 2026 14:31:26 -0700 (PDT) From: Frederick Lawler Date: Wed, 11 Mar 2026 16:31:18 -0500 Subject: [PATCH RFC bpf-next 2/4] audit/security: Enable audit BPF kfuncs Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260311-bpf-auditd-send-message-v1-2-10a62db5c92f@cloudflare.com> References: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> In-Reply-To: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> To: Paul Moore , James Morris , "Serge E. Hallyn" , Eric Paris , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , =?utf-8?q?G=C3=BCnther_Noack?= Cc: linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, audit@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@cloudflare.com, Frederick Lawler X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=772; i=fred@cloudflare.com; h=from:subject:message-id; bh=eQt62HsmlTFVTH5oNb/cY4ErhLI9UlUZljEQgShBvag=; b=owEBbQKS/ZANAwAKAasltHYDktNtAcsmYgBpsd8nHtYAwDOKsh7v5Z8COhYgAMpZ89hrDGxJo dWCyvAjSb2JAjMEAAEKAB0WIQTLNBqMVmu1PHvjOe2rJbR2A5LTbQUCabHfJwAKCRCrJbR2A5LT bVIMEADWlLWYc1BGIY/Op7LIIQwz4iXlQTcEtGoZoMi8RyXxGWw3zQTzB54FBrz++KVJcff/T5P D2NypWH5O/5x03D6avJKCwmkpQ/4oCxLoUhRw4jIL9EPxIwVtfHte6/nVrUAl6V/3iKaWdXGxbz voxsyf56R0ell/5T0hzshR96qxaZ5JvwDJXq69Wz3fAdTV8SRlLrwOMRWyj2CjkoY32MTukvYlJ UzyGJy4U2GDhbqY8+4hK+M9JbG4Nz/1kF9RdYiX7Th3UgS3fA1j5Y/dqt3IQ7tG2pA/m2+mtKuE kqLMQOGyHc3nOzwsgD60OWiCP6rw4Y4xNrFBLWWc8IctP41VBK9tnYNPMvmOVh8cydjU5tIz4vZ UuK7lRarHPz5MoY0nhIGuqyroEA+hsIUGHwx2janCfXQAFHiA+xgDHSCqUKPHZ0tzBjxmMKjlR2 YIliXWA5ByQNg7C4EgR0jYFb7WAGY62aedg6uFkCfZpMq9akxbkG9Ew4+LTvOp95sZUaUw9cUU7 l0K8PROsBJnZV0rVrU1VMz0if153iuwIZ/KX6noYWB3VT41Osq8KBvXSFA3n6x01iqBVnVX0G/8 p3P1EhGtNLutvXs+7C65fmVdPMM0/9PGXPpZ0I/qTwPQ88d0PsQww+WGkxInk71S9HkDNBFylCG 61IrateNCqzPS0A== X-Developer-Key: i=fred@cloudflare.com; a=openpgp; fpr=CB341A8C566BB53C7BE339EDAB25B4760392D36D Enable audit BPF kfuncs. Signed-off-by: Frederick Lawler --- security/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/Makefile b/security/Makefile index 4601230ba442a1bcedc3f999b74a7796ac72894d..de980b2797c1f8f8d0eaeb1be94= 9c41e6ecb8fc1 100644 --- a/security/Makefile +++ b/security/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_SECURITYFS) +=3D inode.o obj-$(CONFIG_SECURITY_SELINUX) +=3D selinux/ obj-$(CONFIG_SECURITY_SMACK) +=3D smack/ obj-$(CONFIG_HAS_SECURITY_AUDIT) +=3D lsm_audit.o +lsm_audit-y +=3D lsm_audit.o +lsm_audit-$(CONFIG_BPF_LSM) +=3D lsm_audit_kfuncs.o obj-$(CONFIG_SECURITY_TOMOYO) +=3D tomoyo/ obj-$(CONFIG_SECURITY_APPARMOR) +=3D apparmor/ obj-$(CONFIG_SECURITY_YAMA) +=3D yama/ --=20 2.43.0 From nobody Tue Apr 7 19:55:53 2026 Received: from mail-ot1-f42.google.com (mail-ot1-f42.google.com [209.85.210.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 304B322126C for ; Wed, 11 Mar 2026 21:31:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264693; cv=none; b=E+r4kmkO+GMWkQq2s3VHS4+aVF4pCW6FzDpA5hd/pzTZRjNzzGVZ4D4PVRZ6p3Uey7TIzCnjqJMOs+ZmA/o8jgTfCihMcofbP6Fbz94DEGiBlFxyngFKf3oyUnawfLikTLwBNnZUb/+cB+nhmznNCbH1Z8AAaUh+1KIGJcGVJbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264693; c=relaxed/simple; bh=DGC/mnZQhpz5il2Tzb09RQpPXoCNmn0gakwBC8UxatM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rujgnHZu4Cj8EP5e0NaZwKmmNVCC40kb/gJr4MfIPFRKqU6Uky5/+tcJnJHnzCFJPAcsMoAwQXWn442vn6eH/0okh/ogQp36nhkGxAwyPE8uqBp5cZ8pyxZ204P44vZG/9WUC5fgz4F4O/W0Vf1u0m/xGo56UI8H6Ym17KGOT7o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com; spf=pass smtp.mailfrom=cloudflare.com; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b=NJQJuuSc; arc=none smtp.client-ip=209.85.210.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="NJQJuuSc" Received: by mail-ot1-f42.google.com with SMTP id 46e09a7af769-7d74a59262fso359445a34.0 for ; Wed, 11 Mar 2026 14:31:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google09082023; t=1773264689; x=1773869489; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=Q7OoBOcJoXPvGUFfb7j19iEOnfHgf2KamFxcvgKSJ7g=; b=NJQJuuScGbvRVrQxFkZGCJwKD2zrtapQOpU1M0BfgzC2ugBUUBX14Tkj79swyAPfLK 7bHkBHCir6ninelOfUWOGXPiwfIxJFTE66smcg+7gbCGO17t0ACbac/p4msP/AjsSXTp GthjlRE9jVX8tmCp4xrnh50igeB35pyNd03bC0L6tGZ7Vk/FN1CmTO2COxtKNf/Uc3HU Jj/UjZJKPegrMbiOm/Bu/Rg+GUiROCCVAl3gKirxv7/vs0ii4VPf2i1tNht+GfDliHYj gn28/YlKRSCQ7LUY6YzY+plb9TPDaA5x4/+2Cazwi6TZBeoIVJJaoZQGRUE7eAFRqPwl /dkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773264689; x=1773869489; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=Q7OoBOcJoXPvGUFfb7j19iEOnfHgf2KamFxcvgKSJ7g=; b=TymCbrWgLdy7Zj94n1qFcTdLYWijQYTqmYcsAizVa3ouqBajjZI1h9tnRBreObRF8u vvRiqwZQ7Y5uTXaBoi6wPFxJQ6xkelSsZ0gr3i6zt0fJNf+sAXh27TR3EfkAxnmnEHEM TjVGenwF50Q2hQOP9ulS3Ewf9CXVN/uQX+JL9UM74pRJCdBfCKsSIwyEBFI9V2AtTSOM nOo4/Aq0CHUHB13Wg9t2HXnCShiaGi2x9nN/DToM5xL8FLNBoWxhQdnw4BkhbzFuM8wq iY3zYHs7VMZB8aLD65XUNUHViSDTX5ENnNwhDomc8WYwFUegeuyGmvS9OPg1kGyTkMDN 9nMw== X-Gm-Message-State: AOJu0YxAv9KAim1gPSAOJecuvBJwuTadCSx1Yv52JZOJbrb9mkw1c1my +oKUS1kSUGuYuvcpyb0SjrWNfs6e2Et72TzAaqEPxXqyQqXUe7fon0FkrdjYLrVQQf8= X-Gm-Gg: ATEYQzy0zyARcl2kwpAv0vuNvcAG72tFRNrmkiIU0ZhrNP4Z4ZH7TyJuAKoUPPym/+G vhhzTeazafNyP98Z68DU1YhoCIfKS3bmqS3RTzFtvbfSzgdkFf6aDFmJx+sHlK9WOunrixY8DkO WuTLVRgYHBtO6NrOU9iU9Cok0UxrHOr1Vq6c0NHEe6+pHOeQFQhL6Kr+8wMBRovqBtEsJaLbEfu 8k+jJ0iJTH/78AZGXGgaga7p2wsapd3fqhRPRwt4U5HOIU213f73FF6UE0rL4bIDHfjcFliBrhc qT4nowbbBlILU74T8DfXhcdQ1d8PLjVG28YqOwb0iu39/mQij8uJg5gp8SKz4VfabIJTOYYiJKB FNy74hw2wzDaInq8sKN2SSzOWUHtwL6AnHfK2G+EfjgeCTyMyw0sYxGEz/Ynwc9SSmGzCaE9JpJ 4qu6hh0mfb5ssJlzJBuA== X-Received: by 2002:a05:6820:1c95:b0:67b:c02e:beaf with SMTP id 006d021491bc7-67bc899efb5mr2873342eaf.46.1773264689029; Wed, 11 Mar 2026 14:31:29 -0700 (PDT) Received: from [127.0.1.1] ([2a09:bac5:947d:4e6::7d:82]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4177e1fb90csm3530413fac.4.2026.03.11.14.31.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Mar 2026 14:31:28 -0700 (PDT) From: Frederick Lawler Date: Wed, 11 Mar 2026 16:31:19 -0500 Subject: [PATCH RFC bpf-next 3/4] selftests/bpf: Add audit helpers for BPF tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260311-bpf-auditd-send-message-v1-3-10a62db5c92f@cloudflare.com> References: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> In-Reply-To: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> To: Paul Moore , James Morris , "Serge E. Hallyn" , Eric Paris , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , =?utf-8?q?G=C3=BCnther_Noack?= Cc: linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, audit@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@cloudflare.com, Frederick Lawler X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=9858; i=fred@cloudflare.com; h=from:subject:message-id; bh=DGC/mnZQhpz5il2Tzb09RQpPXoCNmn0gakwBC8UxatM=; b=owEBbQKS/ZANAwAKAasltHYDktNtAcsmYgBpsd8oz+Df/5XjCq+ZqxcHfOCD1Tz7FPfL9FGSK aztPlKvqGyJAjMEAAEKAB0WIQTLNBqMVmu1PHvjOe2rJbR2A5LTbQUCabHfKAAKCRCrJbR2A5LT bWdXD/9vtXXedAlWtmww8GfZdgRYhjIz9pZJd7DgiG8RavUkAGh6cWGHsxcEo+39V6DpKjypgWj 9cL5rtup8mDIDik5tyDmsuNghbnLXN9iSoJ+Rt5ybo3/oxlKK669C2x3KfnZl9+/ITXvCxoX+Nf ZFC6X6CTSuq0ofTCegcbu/chrwUjMPAV5ep0Kg51x18OuRYBhrVPz6GEO0nWzLATHAk+Jl42jAP AYpgaArcehazglHhfUBgHOXVpMRcvhjEtOR15BNDCZULPeW6ECCWN2uoDJ/wkXPhiQWCCRHDMjB 4fWMpbt0sdHGylOY4NhnSsyUU7h1TXCP88E9vwPKRmwWIXG4tPUY/3TPaASNeC7b5eN70yCtoq/ a6Y/FI7a+Q5W3ev/2M+zBes8hyUxIK49iHlYzdeNnsypAekKmuWWVdacu1TQxDaXHf59nSTesfp MdzwW7NbRWkZE173ramzq/oqdWleDtSSl0TBAKqJUiLj8AUeoNy8c45DqNTDUeepHZTeEz4wI/H kIwPm+VVc8m/kiqIZAUTYjEhAzw/tj3Bc7hCTsbLsfb53we89I7uG5KVLE/MCvBt5LdiUBVb2xc xgXirYZ5Uz0Hai5LsoI0XKXjyCi7eoG/aIf+Cbm2QdTP+R6V//yfCivd3NirSZxwx9qjG5+qtnf OVi4HMH5iNFbhPw== X-Developer-Key: i=fred@cloudflare.com; a=openpgp; fpr=CB341A8C566BB53C7BE339EDAB25B4760392D36D Add audit helper utilities for reading and parsing audit messages in BPF selftests. Assisted-by: Claude:claude-4.5-opus Signed-off-by: Frederick Lawler --- tools/testing/selftests/bpf/Makefile | 3 +- tools/testing/selftests/bpf/audit_helpers.c | 281 ++++++++++++++++++++++++= ++++ tools/testing/selftests/bpf/audit_helpers.h | 55 ++++++ 3 files changed, 338 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests= /bpf/Makefile index 869b582b1d1ff496fb07736597708487be3438ed..76a428539add5e03fe3811b41c5= 5005c22f5cead 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -754,7 +754,8 @@ TRUNNER_EXTRA_SOURCES :=3D test_progs.c \ flow_dissector_load.h \ ip_check_defrag_frags.h \ bpftool_helpers.c \ - usdt_1.c usdt_2.c + usdt_1.c usdt_2.c \ + audit_helpers.c TRUNNER_LIB_SOURCES :=3D find_bit.c TRUNNER_EXTRA_FILES :=3D $(OUTPUT)/urandom_read \ $(OUTPUT)/liburandom_read.so \ diff --git a/tools/testing/selftests/bpf/audit_helpers.c b/tools/testing/se= lftests/bpf/audit_helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..a105136a581f92a1af73b9456b1= e85dc88176678 --- /dev/null +++ b/tools/testing/selftests/bpf/audit_helpers.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * BPF audit helpers + * + * Borrowed code from tools/selftests/landlock/audit.h + * + * Copyright (C) 2024-2025 Microsoft Corporation + * Copyright (c) 2026 Cloudflare + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audit_helpers.h" + +static __u32 seq; + +int audit_init(void) +{ + int bufsize =3D 1024 * 1024; /* 1MB receive buffer */ + struct audit_message msg; + int fd, err; + + fd =3D socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT); + if (fd < 0) + return -errno; + + /* + * Increase receive buffer to reduce kernel-side queueing. + * When the socket buffer fills up, audit records get queued in + * the kernel's hold/retry queues and delivered on subsequent runs. + */ + setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)); + + seq =3D 0; + err =3D audit_send(fd, AUDIT_SET, AUDIT_STATUS_ENABLED, 1); + if (err) + goto out_close; + + do { + err =3D audit_recv(fd, &msg, 0); + if (err < 0) + goto out_close; + } while (msg.nlh.nlmsg_type !=3D NLMSG_ERROR); + + if (msg.err.error) + goto out_close; + + err =3D audit_send(fd, AUDIT_SET, AUDIT_STATUS_PID, getpid()); + if (err) + goto out_close; + + do { + err =3D audit_recv(fd, &msg, 0); + if (err < 0) + goto out_close; + } while (msg.nlh.nlmsg_type !=3D NLMSG_ERROR); + + if (msg.err.error) + goto out_close; + + return fd; + +out_close: + close(fd); + return err; +} + +void audit_cleanup(int fd) +{ + if (fd > 0) + close(fd); +} + +int audit_send(int fd, __u16 type, __u32 key, __u32 val) +{ + struct audit_message msg =3D { + .nlh =3D { + .nlmsg_len =3D NLMSG_SPACE(sizeof(msg.status)), + .nlmsg_type =3D type, + .nlmsg_flags =3D NLM_F_REQUEST | NLM_F_ACK, + .nlmsg_seq =3D ++seq, + }, + .status =3D { + .mask =3D key, + .enabled =3D key =3D=3D AUDIT_STATUS_ENABLED ? val : 0, + .pid =3D key =3D=3D AUDIT_STATUS_PID ? val : 0, + }, + }; + struct sockaddr_nl addr =3D { .nl_family =3D AF_NETLINK }; + int ret; + + do { + ret =3D sendto(fd, &msg, msg.nlh.nlmsg_len, 0, + (struct sockaddr *)&addr, sizeof(addr)); + } while (ret < 0 && errno =3D=3D EINTR); + + return ret =3D=3D msg.nlh.nlmsg_len ? 0 : -errno; +} + +/* + * Receive an audit message from the netlink socket. + * Returns: + * > 0: message type on success + * 0: ACK received (NLMSG_ERROR with error=3D0) + * < 0: negative errno on error + */ +int audit_recv(int fd, struct audit_message *msg, int flags) +{ + struct sockaddr_nl addr; + socklen_t addrlen =3D sizeof(addr); + int ret; + + do { + ret =3D recvfrom(fd, msg, sizeof(*msg), flags, + (struct sockaddr *)&addr, &addrlen); + } while (ret < 0 && errno =3D=3D EINTR); + + if (ret < 0) + return -errno; + + /* Must be from kernel (pid 0) */ + if (addrlen !=3D sizeof(addr) || addr.nl_pid !=3D 0) + return -EINVAL; + + /* + * NLMSG_ERROR with error=3D0 is an ACK. The kernel sends this in + * response to messages with NLM_F_ACK flag set. + */ + if (msg->nlh.nlmsg_type =3D=3D NLMSG_ERROR) { + if (msg->err.error =3D=3D 0) + return 0; /* ACK */ + return msg->err.error; + } + + return msg->nlh.nlmsg_type; +} + +__printf(2, 3) static inline void +debug(struct audit_observer *obs, const char *fmt, ...) +{ + va_list args; + + if (!obs || !obs->log) + return; + + va_start(args, fmt); + vfprintf(obs->log, fmt, args); + va_end(args); +} + +void audit_observer_init(struct audit_observer *obs, int audit_fd, FILE *l= og, + int wait_timeout_ms) +{ + obs->audit_fd =3D audit_fd; + obs->wait_timeout =3D wait_timeout_ms; + + if (log) + obs->log =3D log; + + audit_observer_reset(obs); +} + +void audit_observer_reset(struct audit_observer *obs) +{ + memset(obs->expects, 0, sizeof(obs->expects)); + obs->num_expects =3D 0; +} + +int audit_observer_expect(struct audit_observer *obs, int audit_type, + const char *pattern, int count) +{ + struct audit_expectation *exp; + + if (obs->num_expects >=3D AUDIT_EXPECT_MAX) + return -EINVAL; + + exp =3D &obs->expects[obs->num_expects++]; + exp->type =3D audit_type; + exp->pattern =3D pattern; + exp->expected_count =3D count; + exp->matched_count =3D 0; + return 0; +} + +/* + * Check if a message matches any pending expectation. + * Returns 1 if all expectations are satisfied, 0 otherwise. + */ +static int audit_observer_match(struct audit_observer *obs, + struct audit_message *msg) +{ + int all_satisfied =3D 1; + + for (int i =3D 0; i < obs->num_expects; i++) { + struct audit_expectation *exp =3D &obs->expects[i]; + + if (exp->matched_count >=3D exp->expected_count) + continue; + + /* Check if this message matches */ + if (exp->type && msg->nlh.nlmsg_type !=3D exp->type) + goto check_satisfied; + + if (strstr(msg->data, exp->pattern)) { + exp->matched_count++; + debug(obs, "%s: matched [%d/%d] %s\n", __func__, + exp->matched_count, exp->expected_count, + exp->pattern); + } + +check_satisfied: + if (exp->matched_count < exp->expected_count) + all_satisfied =3D 0; + } + + return all_satisfied; +} + +/* + * Wait for all expected audit messages to arrive. + * Returns 0 on success (all expectations met), -ETIMEDOUT on timeout. + */ +int audit_observer_wait(struct audit_observer *obs) +{ + struct pollfd pfd =3D { .fd =3D obs->audit_fd, .events =3D POLLIN }; + struct audit_message msg; + int ret; + + while (1) { + ret =3D poll(&pfd, 1, obs->wait_timeout); + if (ret < 0) + return -errno; + if (ret =3D=3D 0) + return -ETIMEDOUT; + + memset(&msg, 0, sizeof(msg)); + ret =3D audit_recv(obs->audit_fd, &msg, MSG_DONTWAIT); + + if (ret =3D=3D -EAGAIN || ret =3D=3D -EWOULDBLOCK) + continue; + + if (ret <=3D 0) + continue; + + debug(obs, "%s: recv type=3D%d %s\n", __func__, + msg.nlh.nlmsg_type, msg.data); + + if (audit_observer_match(obs, &msg)) + return 0; + } +} + +int audit_observer_check_satisfied(struct audit_observer *obs) +{ + for (int i =3D 0; i < obs->num_expects; i++) { + struct audit_expectation *exp =3D &obs->expects[i]; + + if (exp->matched_count < exp->expected_count) { + debug(obs, "%s: FAILED pattern '%s' got %d/%d\n", + __func__, exp->pattern, exp->matched_count, + exp->expected_count); + return 0; + } + } + + return 1; +} diff --git a/tools/testing/selftests/bpf/audit_helpers.h b/tools/testing/se= lftests/bpf/audit_helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..40f3d20635bb25c305067756897= 593f34d54531e --- /dev/null +++ b/tools/testing/selftests/bpf/audit_helpers.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2026 Cloudflare */ +#pragma once + +#include +#include +#include + +#define MAX_AUDIT_MESSAGE_LENGTH 8970 + +struct audit_message { + struct nlmsghdr nlh; + union { + struct audit_status status; + struct nlmsgerr err; + char data[MAX_AUDIT_MESSAGE_LENGTH]; + }; +}; + +/* + * Observer-based audit message matching. + * Tests register expected patterns before triggering events, then + * wait for matches. Messages that don't match any pattern are skipped. + */ +#define AUDIT_EXPECT_MAX 32 + +struct audit_expectation { + __u16 type; + const char *pattern; + int expected_count; + int matched_count; +}; + +struct audit_observer { + struct audit_expectation expects[AUDIT_EXPECT_MAX]; + int num_expects; + FILE *log; + int wait_timeout; + int audit_fd; +}; + +int audit_init(void); +void audit_cleanup(int fd); +int audit_wait_ack(int fd); +int audit_send(int fd, __u16 type, __u32 key, __u32 val); +int audit_recv(int fd, struct audit_message *msg, int flags); +int audit_wait_ack(int fd); + +void audit_observer_init(struct audit_observer *obs, int audit_fd, FILE *l= og, + int wait_timeout); +void audit_observer_reset(struct audit_observer *obs); +int audit_observer_expect(struct audit_observer *obs, int audit_type, + const char *pattern, int count); +int audit_observer_wait(struct audit_observer *obs); +int audit_observer_check_satisfied(struct audit_observer *obs); --=20 2.43.0 From nobody Tue Apr 7 19:55:53 2026 Received: from mail-oa1-f44.google.com (mail-oa1-f44.google.com [209.85.160.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B8C732573F for ; Wed, 11 Mar 2026 21:31:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264696; cv=none; b=To7WelfZvgr0t4RympsOToxCzv84zQXVNFM0flheACZf4G2hfmBm336Oa3FJ2GzQOqi9SxBCbJOoa+SYJNQh9pK7MZd+FMMCv27D/6NH38iQOk2sDXcDnvGwmkLk56gc4N9LZhgFMWt9Olej91w4Dq6ApN0qXx16P2/gkRfoUkI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773264696; c=relaxed/simple; bh=B986+q0EPyEQDvxqJ//qZ7hW3q9zmixUG/Y18ImATFE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jXRT5VxEieyQMKwLm8JUb5KF4/bs1pRDJXgGin5ksBuk0qw+xVVCrVYm+1xb/fkTDtim8eAAmuMQ5Ok/RGzi7gkVKhxV/8puaIZmQYbiYeWnap47VQvIBxqnTpxCYIzpKzTznHPPrD26M+hUuealNdSKnYLost4b7rX4atebhYg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com; spf=pass smtp.mailfrom=cloudflare.com; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b=N3g3PA0N; arc=none smtp.client-ip=209.85.160.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="N3g3PA0N" Received: by mail-oa1-f44.google.com with SMTP id 586e51a60fabf-41708e43f61so156899fac.1 for ; Wed, 11 Mar 2026 14:31:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google09082023; t=1773264691; x=1773869491; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=tthSI5YwBPQg2S9IxaV+bU7gsd9dh2H/s6cG0iD4L0E=; b=N3g3PA0NvgIS8AEBI5hqU5WyfQL2hU2jygUqQxqAReQk1Ig6TnyqS+QPUCr4quJvCh uY3X/ALSuUCLmyBAgNXZX7vK92UvVeJ4pBLtNNJg1SsnXyUMJZBhCcOp2csMAkl1BF7l 8ZL2IPMq8Xk7gS2jwaj8Nc1F5D79LgO2VgYFewcVL1cZ+ZMJk21BWFuBPEEMwa7W8Ufx cp8eWhoPzf8YlTl/hui83+HyEcLJ6MkCOiuwwHo7MRgdidMBsZA6PJEzQ7O/fg5lQlTA ETW0ANocyg4MiNtAS4QMWrmDgKCJGM9xcio3WFlfJuvoLwCTWPziy1j/u7Ta+GFwUO8T dd+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773264691; x=1773869491; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=tthSI5YwBPQg2S9IxaV+bU7gsd9dh2H/s6cG0iD4L0E=; b=bLawhEUHUIH3CD41l5Vq2pIEi48E2E0/HPvY4U1qTv6vcRWeXI/WI0EJc8w2XERyjS fOdlRvWXsHZJEURtPkdi0BF6Xa+B5ftP7DyUNQpf4RwTxvuIw84/1Gw3jCdgZArKx3DT i7gBLDc/FJzT1vBdf4kDEMy1Vcflxjd0YAMU5K9yveEa8SaQl4c/6HHZxoFBcMktbDWu 4UvQddIlYTV+eTTytNpKqbVZ5JDw1egrUmDOI6lS+lCXrhtyU1mzmRTqSwlLYUsR8yLv wPfczU4XHWuBWCzJPeknDsE5uA1gpIvCVg5s1Cbd3BTnZB5S7v1X0ZInh4HEMvGag48I pMzQ== X-Gm-Message-State: AOJu0Yy1zOB/VmtFRrs/FesWYpXH92FPyo7lLUhFgolOmLOH6bUS4qdi ZdwdrJJRbuxTZMnzPfId4MsC40o9n2E96JIYPf6JaWj5j3GDmGwnXgWY/Jva/qA+ci0= X-Gm-Gg: ATEYQzz2u7ShgGt3vO+zF2GPty7Xt+t/NsaKFHj+WO1fcjnRybfmKWtu0kqhxVxY0lm QuUbvSuy6WzQi57QghanqUII/DvPgiZlj5L9f//JcOfSYmTnczOP6GtzAtkqmuYtoWkNFdPW8yD OIcj6wYn4tAJ1Mhm4G1TGFuzHLLKhrfX3qddrfmvKuEJahDo6UeOgAJu0UILNMpdBlironK8IBS QKVZy9ZbvURHeX9LnlXcbwi9TV0/6CqqE3W6819HTpGQdTbZsiN07sh1d3q97/3gvwhZp8YX9mT PraIkG2fr03kDGayC90sGDsR405671vjAKM9ccrSWeqA0uad/TmTLsx3jUh3t8FYSVpNGqBGHFn tMCtbswt5qaBhmzutaRvuTV9is/3thIJbgso+PaW6H/tBnQbTCdkeNY6ww6w5GZ3Amu4DKiiBjx 4ZDxLAkFw= X-Received: by 2002:a05:6870:b0ce:b0:417:3bef:8964 with SMTP id 586e51a60fabf-4177c60a84cmr2552985fac.2.1773264691153; Wed, 11 Mar 2026 14:31:31 -0700 (PDT) Received: from [127.0.1.1] ([2a09:bac5:947d:4e6::7d:82]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4177e1fb90csm3530413fac.4.2026.03.11.14.31.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Mar 2026 14:31:30 -0700 (PDT) From: Frederick Lawler Date: Wed, 11 Mar 2026 16:31:20 -0500 Subject: [PATCH RFC bpf-next 4/4] selftests/bpf: Add lsm_audit_kfuncs tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260311-bpf-auditd-send-message-v1-4-10a62db5c92f@cloudflare.com> References: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> In-Reply-To: <20260311-bpf-auditd-send-message-v1-0-10a62db5c92f@cloudflare.com> To: Paul Moore , James Morris , "Serge E. Hallyn" , Eric Paris , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , =?utf-8?q?G=C3=BCnther_Noack?= Cc: linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, audit@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-team@cloudflare.com, Frederick Lawler X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=22647; i=fred@cloudflare.com; h=from:subject:message-id; bh=B986+q0EPyEQDvxqJ//qZ7hW3q9zmixUG/Y18ImATFE=; b=owEBbQKS/ZANAwAKAasltHYDktNtAcsmYgBpsd8ox7VoA9tHygH6CdWnV5yXxCKCXYsthDZcm zaAQBG5hfWJAjMEAAEKAB0WIQTLNBqMVmu1PHvjOe2rJbR2A5LTbQUCabHfKAAKCRCrJbR2A5LT bSQ2D/4saIy2ZXQv1HF99uhbehkV7IRPcjBS9V9Xt+dosdvExoSYyqjUn0xk3ijXA4OZkfEYb5h 8Gre4xk+Q7VGn3Miht9uAiJJdNtJlZw7sJNJd1MyHXCv1Swb5wLxFOXG0QkabUYyu5G20ea6zYO KuJtTQLZN9YKJi/zWU/znZxwUNTHG6E4oLP0VbzdtL4WrSgMXNWzvYQXOIxF56M/SffERpRQkwa w+llPjdQRzpy6guEjAhpw4hy/m8rnD6d0d5T4oeL0kNMq6x0+WN3rzDNdkCWyYlrWaMHI9iE1IV WLMPk6cg5HYVhrb1F4DwDxgjWKQZAUr3hlZEikDOXuLGTjJ28pSsTWktfCYB5n1uCmfGJNZXAuA PTmJyXU+9L6ae/tNQXUByEIxNaJJMa8+BVZ5GETk7aS1Xy82ZWRySspyaiZ/wZ+SVbGjBowYVSE 68QhCrWrDjbgtgnaanRb4voF8KK25DqaOq/nJF5uXVciVLq7fMhlC6as5zvt0GtHj0offiJxKSL 4E/ncYWuKa4cbA1azHiyW+LmIM1x+G4RhsIbAVwfW9DB7TAzEM/2PzhEOTix2dtx68Sh0QMftge ufMiElHIbEbcXbfh3x3/XKXT/Lxu91HZZe4sOnrNnrZsjWSIG3Xl+IifdE+hEQjRWprzqtFc5Jv PBPmakjl+HSaGhw== X-Developer-Key: i=fred@cloudflare.com; a=openpgp; fpr=CB341A8C566BB53C7BE339EDAB25B4760392D36D Add selftests for the audit kfunc BPF LSM functionality including both the test program and BPF progs. Assisted-by: Claude:claude-4.5-opus Signed-off-by: Frederick Lawler --- .../selftests/bpf/prog_tests/lsm_audit_kfuncs.c | 598 +++++++++++++++++= ++++ .../selftests/bpf/progs/test_lsm_audit_kfuncs.c | 263 +++++++++ 2 files changed, 861 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/lsm_audit_kfuncs.c b/to= ols/testing/selftests/bpf/prog_tests/lsm_audit_kfuncs.c new file mode 100644 index 0000000000000000000000000000000000000000..de18e1a3c79578d4151a12a029f= 2a9e6cc7648e3 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/lsm_audit_kfuncs.c @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Cloudflare */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audit_helpers.h" +#include "test_lsm_audit_kfuncs.skel.h" +#include "test_progs.h" + +#ifndef AUDIT_BPF_LSM_ACCESS +#define AUDIT_BPF_LSM_ACCESS 1427 +#endif + +static inline struct sockaddr_in addr4(void) +{ + return (struct sockaddr_in){ + .sin_family =3D AF_INET, + .sin_port =3D htons(1234), + .sin_addr.s_addr =3D htonl(INADDR_LOOPBACK), + }; +} + +static inline struct sockaddr_in6 addr6(void) +{ + return (struct sockaddr_in6){ + .sin6_family =3D AF_INET6, + .sin6_port =3D htons(1234), + .sin6_addr =3D in6addr_loopback, + }; +} + +static int bind_connect(const struct sockaddr *addr, int addrlen) +{ + int err; + int sock; + int opt =3D 1; + socklen_t optlen =3D sizeof(opt); + + sock =3D socket(addr->sa_family, SOCK_STREAM, 0); + if (!ASSERT_OK_FD(sock, "socket")) + return 1; + + err =3D setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, optlen); + if (!ASSERT_OK(err, "setsockopt")) + goto done; + + err =3D bind(sock, addr, addrlen); + if (!ASSERT_OK(err, "bind")) + goto done; + + err =3D connect(sock, addr, addrlen); + ASSERT_OK(err, "connect"); + + err =3D getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, &optlen); + ASSERT_OK(err, "getsockopt"); + +done: + close(sock); + return err; +} + +static void test_audit_log_sockaddr_src(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct sockaddr_in sin =3D addr4(); + struct sockaddr_in6 sin6 =3D addr6(); + struct bpf_link *link; + + link =3D bpf_program__attach_lsm(skel->progs.test_sockaddr_src); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"bind4\" saddr=3D127.0.0.1 src=3D1234 netif=3Dlo", + 1); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"bind6\" saddr=3D::1 src=3D1234 netif=3Dlo", 1); + + if (bind_connect((const struct sockaddr *)&sin, sizeof(sin))) + goto done; + + if (bind_connect((const struct sockaddr *)&sin6, sizeof(sin6))) + goto done; + + ASSERT_OK(audit_observer_wait(obs), "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +done: + bpf_link__destroy(link); +} + +static void test_audit_log_sockaddr_dest(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct sockaddr_in sin =3D addr4(); + struct sockaddr_in6 sin6 =3D addr6(); + struct bpf_link *link; + + link =3D bpf_program__attach_lsm(skel->progs.test_sockaddr_dest); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"connect4\" daddr=3D127.0.0.1 dest=3D1234 netif=3Dlo", + 1); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"connect6\" daddr=3D::1 dest=3D1234 netif=3Dlo", + 1); + + if (bind_connect((const struct sockaddr *)&sin, sizeof(sin))) + goto out; + + if (bind_connect((const struct sockaddr *)&sin6, sizeof(sin6))) + goto out; + + ASSERT_OK(audit_observer_wait(obs), "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_sock(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct sockaddr_in sin =3D addr4(); + struct sockaddr_in6 sin6 =3D addr6(); + struct bpf_link *link; + + link =3D bpf_program__attach_lsm(skel->progs.test_sock); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"sock4\" laddr=3D127.0.0.1 lport=3D1234 faddr=3D127.0.0= .1 fport=3D1234 netif=3Dlo", + 1); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"sock6\" laddr=3D::1 lport=3D1234 faddr=3D::1 fport=3D1= 234 netif=3Dlo", + 1); + + if (bind_connect((const struct sockaddr *)&sin, sizeof(sin))) + goto out; + + if (bind_connect((const struct sockaddr *)&sin6, sizeof(sin6))) + goto out; + + ASSERT_OK(audit_observer_wait(obs), "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_sock_unix(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct sockaddr_un addr; + struct bpf_link *link; + char expected[256]; + char sun_path[108]; + int server_fd =3D -1; + int opt =3D 1; + socklen_t optlen =3D sizeof(opt); + int err; + + snprintf(sun_path, sizeof(sun_path), "/root/tmp/bpf_audit_test_%d.sock", + getpid()); + + /* Ensure directory exists */ + mkdir("/root/tmp", 0755); + unlink(sun_path); + + link =3D bpf_program__attach_lsm(skel->progs.test_sock_unix); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + snprintf(expected, sizeof(expected), "cause=3D\"sock_unix\" path=3D\"%s\"= ", + sun_path); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, expected, 1); + + memset(&addr, 0, sizeof(addr)); + addr.sun_family =3D AF_UNIX; + strncpy(addr.sun_path, sun_path, sizeof(addr.sun_path) - 1); + + server_fd =3D socket(AF_UNIX, SOCK_STREAM, 0); + if (!ASSERT_OK_FD(server_fd, "socket")) + goto out; + + err =3D bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)); + if (!ASSERT_OK(err, "bind")) + goto out; + + err =3D getsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, &optlen); + ASSERT_OK(err, "getsockopt"); + + ASSERT_OK(audit_observer_wait(obs), "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + if (server_fd >=3D 0) + close(server_fd); + unlink(sun_path); + bpf_link__destroy(link); +} + +static void test_audit_log_file(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + int err; + int fd; + + link =3D bpf_program__attach_lsm(skel->progs.test_file); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"file\" path=3D\"/dev/null\" dev=3D\"devtmpfs\" ino=3D4= ", + 1); + + fd =3D open("/dev/null", O_RDONLY); + close(fd); + if (!ASSERT_OK_FD(fd, "open(/dev/null)")) + goto out; + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_path(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + int err; + int fd; + + link =3D bpf_program__attach_lsm(skel->progs.test_file_path); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"path\" path=3D\"/dev/null\" dev=3D\"devtmpfs\" ino=3D4= ", + 1); + + fd =3D open("/dev/null", O_RDONLY); + close(fd); + if (!ASSERT_OK_FD(fd, "open(/dev/null)")) + goto out; + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_dentry(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + char expected[128]; + char buf[64]; + int err; + + link =3D bpf_program__attach_lsm(skel->progs.test_dentry); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + snprintf(expected, sizeof(expected), + "cause=3D\"dentry\" name=3D\"exe\" dev=3D"); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, expected, 1); + + /* readlink triggers inode_readlink hook */ + err =3D readlink("/proc/self/exe", buf, sizeof(buf)); + if (!ASSERT_GT(err, 0, "readlink(/proc/self/exe)")) + goto out; + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_inode(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + char expected[128]; + struct stat st; + int err; + int fd; + + if (!ASSERT_OK(stat("/dev/null", &st), "stat(/dev/null)")) + return; + + link =3D bpf_program__attach_lsm(skel->progs.test_inode); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + snprintf(expected, sizeof(expected), + "cause=3D\"inode\" name=3D\"null\" dev=3D\"devtmpfs\" ino=3D%lu", + st.st_ino); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, expected, 1); + + fd =3D open("/dev/null", O_RDONLY); + close(fd); + if (!ASSERT_OK_FD(fd, "open(/dev/null)")) + goto out; + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_task(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + char expected[128]; + pid_t pid; + int err; + + pid =3D getpid(); + + link =3D bpf_program__attach_lsm(skel->progs.test_task); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + snprintf(expected, sizeof(expected), + "cause=3D\"task\" opid=3D%d ocomm=3D\"test_progs\"", pid); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, expected, 1); + + err =3D getpgid(pid); + if (!ASSERT_GT(err, -1, "pid pgid match")) + goto out; + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_cap(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + int err; + int fd; + + link =3D bpf_program__attach_lsm(skel->progs.test_cap); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"cap\" capability=3D", 1); + + fd =3D open("/proc/kallsyms", O_RDONLY); + close(fd); + if (!ASSERT_OK_FD(fd, "open(/proc/kallsyms)")) + goto out; + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_ioctl_op(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + char expected[128]; + struct stat st; + int err; + int fd; + + if (!ASSERT_OK(stat("/dev/null", &st), "stat(/dev/null)")) + return; + + link =3D bpf_program__attach_lsm(skel->progs.test_ioctl_op); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + snprintf(expected, sizeof(expected), + "cause=3D\"ioctl_op\" path=3D\"/dev/null\" dev=3D\"devtmpfs\" ino=3D%lu= ioctlcmd=3D0x%x", + st.st_ino, TCGETS); + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, expected, 1); + + fd =3D open("/dev/null", O_RDONLY); + if (!ASSERT_OK_FD(fd, "open(/dev/null)")) + goto out; + + /* ioctl will fail with ENOTTY but the LSM hook fires regardless */ + ioctl(fd, TCGETS, NULL); + close(fd); + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void test_audit_log_sleepable(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct bpf_link *link; + int err; + int fd; + + link =3D bpf_program__attach_lsm(skel->progs.test_sleepable); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"sleepable\" path=3D\"/dev/null\" dev=3D\"devtmpfs\" in= o=3D4", + 1); + + fd =3D open("/dev/null", O_RDONLY); + close(fd); + if (!ASSERT_OK_FD(fd, "open(/dev/null)")) + goto out; + + err =3D audit_observer_wait(obs); + ASSERT_OK(err, "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + +out: + bpf_link__destroy(link); +} + +static void +test_audit_log_sockaddr_both_null(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct sockaddr_in sin =3D addr4(); + struct bpf_link *link; + + link =3D bpf_program__attach_lsm(skel->progs.test_sockaddr_both_null); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + /* Should see cause but no saddr/daddr since both were NULL */ + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"sockaddr_both_null\"", 1); + + bind_connect((const struct sockaddr *)&sin, sizeof(sin)); + + ASSERT_OK(audit_observer_wait(obs), "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + + bpf_link__destroy(link); +} + +static void +test_audit_log_sockaddr_small_addrlen(struct audit_observer *obs, + struct test_lsm_audit_kfuncs *skel) +{ + struct sockaddr_in sin =3D addr4(); + struct bpf_link *link; + + link =3D bpf_program__attach_lsm(skel->progs.test_sockaddr_small_addrlen); + if (!ASSERT_OK_PTR(link, "attach")) + return; + + audit_observer_reset(obs); + + /* Should see cause but no saddr since addrlen was too small */ + audit_observer_expect(obs, AUDIT_BPF_LSM_ACCESS, + "cause=3D\"sockaddr_small_addrlen\"", 1); + + bind_connect((const struct sockaddr *)&sin, sizeof(sin)); + + ASSERT_OK(audit_observer_wait(obs), "audit_observer_wait"); + ASSERT_TRUE(audit_observer_check_satisfied(obs), + "all expectations met"); + + bpf_link__destroy(link); +} + +void test_lsm_audit_kfuncs(void) +{ + struct test_lsm_audit_kfuncs *skel =3D NULL; + struct audit_observer obs; + FILE *log =3D NULL; + int audit_fd; + + audit_fd =3D audit_init(); + if (!ASSERT_GE(audit_fd, 0, "audit_init")) + return; + + if (env.verbosity > VERBOSE_NONE) + log =3D env.stdout_saved; + + audit_observer_init(&obs, audit_fd, log, 500); + + skel =3D test_lsm_audit_kfuncs__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel load")) + goto close_prog; + + if (test__start_subtest("net")) { + test_audit_log_sockaddr_src(&obs, skel); + test_audit_log_sockaddr_dest(&obs, skel); + test_audit_log_sockaddr_both_null(&obs, skel); + test_audit_log_sockaddr_small_addrlen(&obs, skel); + test_audit_log_sock(&obs, skel); + test_audit_log_sock_unix(&obs, skel); + } + + if (test__start_subtest("file")) { + test_audit_log_file(&obs, skel); + test_audit_log_path(&obs, skel); + test_audit_log_dentry(&obs, skel); + test_audit_log_inode(&obs, skel); + } + + if (test__start_subtest("task")) { + test_audit_log_task(&obs, skel); + test_audit_log_cap(&obs, skel); + } + + if (test__start_subtest("ioctl")) + test_audit_log_ioctl_op(&obs, skel); + + if (test__start_subtest("sleepable")) + test_audit_log_sleepable(&obs, skel); + +close_prog: + test_lsm_audit_kfuncs__destroy(skel); + audit_cleanup(audit_fd); +} diff --git a/tools/testing/selftests/bpf/progs/test_lsm_audit_kfuncs.c b/to= ols/testing/selftests/bpf/progs/test_lsm_audit_kfuncs.c new file mode 100644 index 0000000000000000000000000000000000000000..952ba09fce638f3bd14c18060a5= baa3ccaec19ca --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_lsm_audit_kfuncs.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Cloudflare */ + +#include +#include +#include +#include +#include + +#define AF_UNIX 1 +#define AF_INET 2 +#define AF_INET6 10 + +char _license[] SEC("license") =3D "GPL"; + +SEC("lsm/socket_bind") +int BPF_PROG(test_sockaddr_src, struct socket *sock, struct sockaddr *addr= ess, + int addrlen) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + switch (address->sa_family) { + case AF_INET: + bpf_audit_log_cause(ac, "bind4"); + break; + case AF_INET6: + bpf_audit_log_cause(ac, "bind6"); + } + + bpf_audit_log_net_sockaddr(ac, 1, address, NULL, addrlen); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/socket_connect") +int BPF_PROG(test_sockaddr_dest, struct socket *sock, struct sockaddr *add= ress, + int addrlen) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + switch (address->sa_family) { + case AF_INET: + bpf_audit_log_cause(ac, "connect4"); + break; + case AF_INET6: + bpf_audit_log_cause(ac, "connect6"); + } + + bpf_audit_log_net_sockaddr(ac, 1, NULL, address, addrlen); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/socket_bind") +int BPF_PROG(test_sockaddr_both_null, struct socket *sock, + struct sockaddr *address, int addrlen) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "sockaddr_both_null"); + bpf_audit_log_net_sockaddr(ac, 1, NULL, NULL, addrlen); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/socket_bind") +int BPF_PROG(test_sockaddr_small_addrlen, struct socket *sock, + struct sockaddr *address, int addrlen) +{ + struct bpf_audit_context *ac; + + if (address->sa_family !=3D AF_INET) + return -EINVAL; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "sockaddr_small_addrlen"); + bpf_audit_log_net_sockaddr(ac, 1, address, NULL, 1); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/socket_getsockopt") +int BPF_PROG(test_sock, struct socket *sock, int level, int optname) +{ + struct bpf_audit_context *ac; + struct sock *sk =3D sock->sk; + + if (!sk) + return -EINVAL; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + switch (sk->__sk_common.skc_family) { + case AF_INET: + bpf_audit_log_cause(ac, "sock4"); + break; + case AF_INET6: + bpf_audit_log_cause(ac, "sock6"); + } + + bpf_audit_log_net_sock(ac, 1, sock); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/socket_getsockopt") +int BPF_PROG(test_sock_unix, struct socket *sock, int level, int optname) +{ + struct bpf_audit_context *ac; + struct sock *sk =3D sock->sk; + + if (!sk || sk->__sk_common.skc_family !=3D AF_UNIX) + return -EINVAL; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "sock_unix"); + bpf_audit_log_net_sock(ac, 0, sock); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/file_open") +int BPF_PROG(test_file, struct file *file) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "file"); + bpf_audit_log_file(ac, file); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/file_open") +int BPF_PROG(test_file_path, struct file *file) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "path"); + bpf_audit_log_path(ac, &file->f_path); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/inode_readlink") +int BPF_PROG(test_dentry, struct dentry *dentry) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "dentry"); + bpf_audit_log_dentry(ac, dentry); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/file_open") +int BPF_PROG(test_inode, struct file *file) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "inode"); + bpf_audit_log_inode(ac, file->f_inode); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/task_getpgid") +int BPF_PROG(test_task, struct task_struct *task) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "task"); + bpf_audit_log_task(ac, task); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/capable") +int BPF_PROG(test_cap, const struct cred *cred, struct user_namespace *ns, + int cap, unsigned int opts) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "cap"); + bpf_audit_log_cap(ac, cap); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm/file_ioctl") +int BPF_PROG(test_ioctl_op, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "ioctl_op"); + bpf_audit_log_ioctl_op(ac, file, cmd); + bpf_audit_log_end(ac); + return 0; +} + +SEC("lsm.s/file_open") +int BPF_PROG(test_sleepable, struct file *file) +{ + struct bpf_audit_context *ac; + + ac =3D bpf_audit_log_start(); + if (!ac) + return -ENOMEM; + + bpf_audit_log_cause(ac, "sleepable"); + bpf_audit_log_file(ac, file); + bpf_audit_log_end(ac); + return 0; +} + --=20 2.43.0