From nobody Fri Oct 2 14:02:28 2026 Received: from mail-qt1-f181.google.com (mail-qt1-f181.google.com [209.85.160.181]) (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 925E93BB9F8 for ; Thu, 30 Jul 2026 23:45:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455144; cv=none; b=ZEXk3C++tYO7MQPYx2lzGczWrZvJdW3gWim+AFkly29HUCXcwgpJ4COzW+eWRbFFhA6xUdxVfuKfXTQN8j12wbjxTcYeM5YsYroT1anmYd2Q8sZi2M7xXmScVZFcjBiyVVXy6w1XUaN8nKOIx74mHLbdK8rdOpd/aUPcgg1ulL8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455144; c=relaxed/simple; bh=VCpbyUPqORWyRLbwhm51+hqDWgsTGfpZM/vWOJo7WrU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=E1ptg7sBSAqpFvh4xmRSKmdrCpTAlabZMCBnCOlPX8ImZY9pCuOckPcIJrn8SjTF0tlsF6he8M3g7taMZvwPJriBYiD2eCOrwWcO0BWveZ5Z82b2NpkZOCXQDmIAtw9DbjSG4UtMa67jgDubF7IcvnRbfCeH4TrSAU7e2cwECLM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=noSrTpEb; arc=none smtp.client-ip=209.85.160.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="noSrTpEb" Received: by mail-qt1-f181.google.com with SMTP id d75a77b69052e-5218927884fso3049461cf.3 for ; Thu, 30 Jul 2026 16:45:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785455139; x=1786059939; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=CEsXNuooCRONAZouOvL/f+bUqt1A8msd7lPJJsnoW38=; b=noSrTpEbWaCZGx6bD4hO39KX2W9uzVQrgCYkivUx8SINCF2uxcGY4J4B6ollvVEVnG rJWrGCdmliHbtBQZdBmX4yilNIkW6Uuuk61ggcdzUIeP7tXpUsxMc+B8HIqSQZHbWS/0 a3kLlnNILyntHGY9+pcbETmvyf1kGxT6qnTUWlYMJYp8vgoNCygxJtZ0cQvozrcXTsNs MuUKCY1eis8QLcYXYeO2WsriuCKpv/C4xmsBA9mFBs6o47VN5NaHKnzxt+PE/Kt4o+j9 J/mZcjNenUnqIIN/pHotfZQ72gdOfgtIvjqW0Ngt/kJi7656bI1v27C4lJCBM5D5gEY1 ZCCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785455139; x=1786059939; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=CEsXNuooCRONAZouOvL/f+bUqt1A8msd7lPJJsnoW38=; b=Ns8XP8GAsUOc/xGXZnvgjFPVijuYF69yjIpcT/2qXJwAXdGNOX9oJldo74x5zxDxls 9MsQYxqCuZ4S5UAwh76zU4vdqzpf0n/LwIwEQ2ABYZauGw08IIS1yWLqGxPKZ7CTOmDI rFYSzbe0YEGbhtiF3MTqgj/0ZiEF2PACWjyUyl36TsOKa8IhAawoG/DtEiejdOacKvef emhjMvmplqWRksjFhEvN79efWCWOf4Zf6L7FKdor4xGG/s26mS73JbUatFIzF4sxeL5V D5Ee4UvhQuNmlwYWKI//jPGJ0Gd7Tf2Vf0BJG5Urnm5TxzGENM6h/MqpRK+lymlirbRk kF1g== X-Forwarded-Encrypted: i=1; AHgh+RpE7QARlFCVZ53VBUH9i2j55zaX3huXZqAR374FMMBEYrsOcLDXw4N+DMn+5r1Tb03JP8L/S4BbNMToMVc=@vger.kernel.org X-Gm-Message-State: AOJu0YzbGrn7ocNYi5+SCwsSi4CokQnk1kl+wQ5r/0SqSrYixlEa3x5k 7gK3X37GNdBu8QScLNbDahwoADKVrW/+8JC//ZaEwBLAwbfmSS4wHun2 X-Gm-Gg: AR+sD13TIQu14TtlNezs3+oLKa48wciv63GTom67O9ZHmV0NldOQGA5WIQoXWWN84Mx PUAxI8OBoWLG/lwTaf3fD+2qqZkyL0nrDD+lUpc+i0e4cBJ0WTNgGx21/6ZefbcGWZmlNGHpsXk LHDhk59683kYZcjSN0Z17NnmyFtkRSdqCLlUvC4BrkSEq+K2KSWV6nw45yWqzZioxoRIOZeYKRp a5uqc42E1XvBzUG37G81eRhrYMqNuMlnmUvn84i//TinvOndlYW1/qwY0hMCwfauLQNbKeBSXn3 YKF2kYqKvjOuRokVTr1mBZuYQhooiGmmISJOVdyUtGNZn/3zEA40YF8MF3Bdz6Vo6Cv2/zpOOZn 55XvjcU3YDreqby1990F26FzCwOxyt+sVqbm6kzPbdc7I30O4U/fEHRAlJrD3nxisr0ZfYnsMk6 +K06q+BLUtOVAYhsV9lkNcaPIAhkugxG4SdDE6q4mRL0DmBJRgtdcbQrr9N7xxnsY6cpDMfXh9w Y4aXlZdhpV3dTGjJSiNkrrqud7GlH/2cts+TmuRQ3zwK0++lg6EJpr/ER+3Kjw= X-Received: by 2002:ac8:5e4d:0:b0:51a:8c86:bd44 with SMTP id d75a77b69052e-52b386be26emr48728101cf.65.1785455139426; Thu, 30 Jul 2026 16:45:39 -0700 (PDT) Received: from battery.lan (pool-138-88-31-60.washdc.fios.verizon.net. [138.88.31.60]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-908323e8bc0sm28991836d6.26.2026.07.30.16.45.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Jul 2026 16:45:38 -0700 (PDT) From: David Windsor To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Jiri Olsa , Kumar Kartikeya Dwivedi , Emil Tsalapatis , Matt Bobrowski , Paul Moore , James Morris , "Serge E . Hallyn" , Casey Schaufler , Stephen Smalley , Ondrej Mosnacek , Mimi Zohar , Roberto Sassu , Dmitry Kasatkin , Eric Snowberg , Alexander Viro , Christian Brauner , Jan Kara , Shuah Khan Cc: bpf@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, David Windsor Subject: [PATCH v6 bpf-next 1/4] security: introduce struct lsm_xattrs Date: Thu, 30 Jul 2026 19:45:30 -0400 Message-ID: <20260730234533.1912709-2-dwindsor@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260730234533.1912709-1-dwindsor@gmail.com> References: <20260730234533.1912709-1-dwindsor@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In preparation for bpf_init_inode_xattr(), a kfunc that lets bpf LSM programs atomically label new inodes, rework how inode_init_security xattrs are managed. inode_init_security receives the LSM xattr array and its count as separate parameters. For better compatibility with the bpf verifier, update inode_init_security and its callers to consolidate these parameters into a single context object: struct lsm_xattrs. Suggested-by: Paul Moore Signed-off-by: David Windsor --- include/linux/evm.h | 9 +++++---- include/linux/lsm_hook_defs.h | 4 ++-- include/linux/lsm_hooks.h | 16 +++++++--------- include/linux/security.h | 5 +++++ security/integrity/evm/evm_main.c | 8 +++++--- security/security.c | 24 ++++++++++++------------ security/selinux/hooks.c | 4 ++-- security/smack/smack_lsm.c | 27 ++++++++++++--------------- 8 files changed, 50 insertions(+), 47 deletions(-) diff --git a/include/linux/evm.h b/include/linux/evm.h index 913f4573b203..528f360f3308 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -12,6 +12,8 @@ #include #include =20 +struct lsm_xattrs; + #ifdef CONFIG_EVM extern int evm_set_key(void *key, size_t keylen); extern enum integrity_status evm_verifyxattr(struct dentry *dentry, @@ -21,8 +23,8 @@ extern enum integrity_status evm_verifyxattr(struct dentr= y *dentry, int evm_fix_hmac(struct dentry *dentry, const char *xattr_name, const char *xattr_value, size_t xattr_value_len); int evm_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, struct xattr *xattrs, - int *xattr_count); + const struct qstr *qstr, + struct lsm_xattrs *xattrs); extern bool evm_revalidate_status(const char *xattr_name); extern int evm_protected_xattr_if_enabled(const char *req_xattr_name); extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, @@ -63,8 +65,7 @@ static inline int evm_fix_hmac(struct dentry *dentry, con= st char *xattr_name, =20 static inline int evm_inode_init_security(struct inode *inode, struct inod= e *dir, const struct qstr *qstr, - struct xattr *xattrs, - int *xattr_count) + struct lsm_xattrs *xattrs) { return 0; } diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 65c9609ec207..5b2de7865ce8 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -116,8 +116,8 @@ LSM_HOOK(int, 0, inode_alloc_security, struct inode *in= ode) LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode) LSM_HOOK(void, LSM_RET_VOID, inode_free_security_rcu, void *inode_security) LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode, - struct inode *dir, const struct qstr *qstr, struct xattr *xattrs, - int *xattr_count) + struct inode *dir, const struct qstr *qstr, + struct lsm_xattrs *xattrs) LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode, const struct qstr *name, const struct inode *context_inode) LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry, diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index b4f8cad53ddb..7afe06a8d4c6 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -200,20 +200,18 @@ extern struct lsm_static_calls_table static_calls_tab= le __ro_after_init; =20 /** * lsm_get_xattr_slot - Return the next available slot and increment the i= ndex - * @xattrs: array storing LSM-provided xattrs - * @xattr_count: number of already stored xattrs (updated) + * @ctx: xattr state shared by inode_init_security hooks * - * Retrieve the first available slot in the @xattrs array to fill with an = xattr, - * and increment @xattr_count. + * Retrieve the first available slot in the @ctx->xattrs array to fill wit= h an + * xattr, and increment @ctx->xattr_count. * - * Return: The slot to fill in @xattrs if non-NULL, NULL otherwise. + * Return: The slot to fill in @ctx->xattrs if non-NULL, NULL otherwise. */ -static inline struct xattr *lsm_get_xattr_slot(struct xattr *xattrs, - int *xattr_count) +static inline struct xattr *lsm_get_xattr_slot(struct lsm_xattrs *ctx) { - if (unlikely(!xattrs)) + if (unlikely(!ctx || !ctx->xattrs)) return NULL; - return &xattrs[(*xattr_count)++]; + return &ctx->xattrs[ctx->xattr_count++]; } =20 #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/include/linux/security.h b/include/linux/security.h index 153e9043058f..0be590c40689 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -68,6 +68,11 @@ struct watch; struct watch_notification; struct lsm_ctx; =20 +struct lsm_xattrs { + struct xattr *xattrs; + unsigned int xattr_count; +}; + /* Default (no) options for the capable function */ #define CAP_OPT_NONE 0x0 /* If capable should audit the security request */ diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm= _main.c index b59e3f121b8a..b7158fc63543 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -1062,14 +1062,16 @@ static int evm_inode_copy_up_xattr(struct dentry *s= rc, const char *name) * evm_inode_init_security - initializes security.evm HMAC value */ int evm_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, struct xattr *xattrs, - int *xattr_count) + const struct qstr *qstr, + struct lsm_xattrs *lsm_xattrs) { struct evm_xattr *xattr_data; struct xattr *xattr, *evm_xattr; + struct xattr *xattrs; bool evm_protected_xattrs =3D false; int rc; =20 + xattrs =3D lsm_xattrs ? lsm_xattrs->xattrs : NULL; if (!(evm_initialized & EVM_INIT_HMAC) || !xattrs) return 0; =20 @@ -1087,7 +1089,7 @@ int evm_inode_init_security(struct inode *inode, stru= ct inode *dir, if (!evm_protected_xattrs) return 0; =20 - evm_xattr =3D lsm_get_xattr_slot(xattrs, xattr_count); + evm_xattr =3D lsm_get_xattr_slot(lsm_xattrs); /* * Array terminator (xattr name =3D NULL) must be the first non-filled * xattr slot. diff --git a/security/security.c b/security/security.c index 71aea8fdf014..2ad7f09c1a61 100644 --- a/security/security.c +++ b/security/security.c @@ -1333,8 +1333,8 @@ int security_inode_init_security(struct inode *inode,= struct inode *dir, const initxattrs initxattrs, void *fs_data) { struct lsm_static_call *scall; - struct xattr *new_xattrs =3D NULL; - int ret =3D -EOPNOTSUPP, xattr_count =3D 0; + struct lsm_xattrs xattrs =3D {}; + int ret =3D -EOPNOTSUPP; =20 if (unlikely(IS_PRIVATE(inode))) return 0; @@ -1344,15 +1344,15 @@ int security_inode_init_security(struct inode *inod= e, struct inode *dir, =20 if (initxattrs) { /* Allocate +1 as terminator. */ - new_xattrs =3D kcalloc(blob_sizes.lbs_xattr_count + 1, - sizeof(*new_xattrs), GFP_NOFS); - if (!new_xattrs) + xattrs.xattrs =3D kcalloc(blob_sizes.lbs_xattr_count + 1, + sizeof(*xattrs.xattrs), GFP_NOFS); + if (!xattrs.xattrs) return -ENOMEM; } =20 lsm_for_each_hook(scall, inode_init_security) { - ret =3D scall->hl->hook.inode_init_security(inode, dir, qstr, new_xattrs, - &xattr_count); + ret =3D scall->hl->hook.inode_init_security(inode, dir, qstr, + &xattrs); if (ret && ret !=3D -EOPNOTSUPP) goto out; /* @@ -1364,14 +1364,14 @@ int security_inode_init_security(struct inode *inod= e, struct inode *dir, } =20 /* If initxattrs() is NULL, xattr_count is zero, skip the call. */ - if (!xattr_count) + if (!xattrs.xattr_count) goto out; =20 - ret =3D initxattrs(inode, new_xattrs, fs_data); + ret =3D initxattrs(inode, xattrs.xattrs, fs_data); out: - for (; xattr_count > 0; xattr_count--) - kfree(new_xattrs[xattr_count - 1].value); - kfree(new_xattrs); + for (; xattrs.xattr_count > 0; xattrs.xattr_count--) + kfree(xattrs.xattrs[xattrs.xattr_count - 1].value); + kfree(xattrs.xattrs); return (ret =3D=3D -EOPNOTSUPP) ? 0 : ret; } EXPORT_SYMBOL(security_inode_init_security); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8d6945edae7a..21544c775c17 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2962,7 +2962,7 @@ static int selinux_dentry_create_files_as(struct dent= ry *dentry, int mode, =20 static int selinux_inode_init_security(struct inode *inode, struct inode *= dir, const struct qstr *qstr, - struct xattr *xattrs, int *xattr_count) + struct lsm_xattrs *xattrs) { const struct cred_security_struct *crsec =3D selinux_cred(current_cred()); struct superblock_security_struct *sbsec; @@ -2992,7 +2992,7 @@ static int selinux_inode_init_security(struct inode *= inode, struct inode *dir, !(sbsec->flags & SBLABEL_MNT)) return -EOPNOTSUPP; =20 - xattr =3D lsm_get_xattr_slot(xattrs, xattr_count); + xattr =3D lsm_get_xattr_slot(xattrs); if (xattr) { rc =3D security_sid_to_context_force(newsid, &context, &clen); diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index ff115068c5c0..4501078430ca 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -981,10 +981,10 @@ smk_rule_transmutes(struct smack_known *subject, } =20 static int -xattr_dupval(struct xattr *xattrs, int *xattr_count, +xattr_dupval(struct lsm_xattrs *xattrs, const char *name, const void *value, unsigned int vallen) { - struct xattr * const xattr =3D lsm_get_xattr_slot(xattrs, xattr_count); + struct xattr * const xattr =3D lsm_get_xattr_slot(xattrs); =20 if (!xattr) return 0; @@ -1003,14 +1003,13 @@ xattr_dupval(struct xattr *xattrs, int *xattr_count, * @inode: the newly created inode * @dir: containing directory object * @qstr: unused - * @xattrs: where to put the attributes - * @xattr_count: current number of LSM-provided xattrs (updated) + * @xattrs: where to put attributes and update count * * Returns 0 if it all works out, -ENOMEM if there's no memory */ static int smack_inode_init_security(struct inode *inode, struct inode *di= r, const struct qstr *qstr, - struct xattr *xattrs, int *xattr_count) + struct lsm_xattrs *xattrs) { struct task_smack *tsp =3D smack_cred(current_cred()); struct inode_smack * const issp =3D smack_inode(inode); @@ -1057,21 +1056,19 @@ static int smack_inode_init_security(struct inode *= inode, struct inode *dir, if (S_ISDIR(inode->i_mode)) { transflag =3D SMK_INODE_TRANSMUTE; =20 - if (xattr_dupval(xattrs, xattr_count, - XATTR_SMACK_TRANSMUTE, - TRANS_TRUE, - TRANS_TRUE_SIZE - )) + if (xattr_dupval(xattrs, + XATTR_SMACK_TRANSMUTE, + TRANS_TRUE, + TRANS_TRUE_SIZE)) rc =3D -ENOMEM; } } =20 if (rc =3D=3D 0) - if (xattr_dupval(xattrs, xattr_count, - XATTR_SMACK_SUFFIX, - issp->smk_inode->smk_known, - strlen(issp->smk_inode->smk_known) - )) + if (xattr_dupval(xattrs, + XATTR_SMACK_SUFFIX, + issp->smk_inode->smk_known, + strlen(issp->smk_inode->smk_known))) rc =3D -ENOMEM; instant_inode: issp->smk_flags |=3D (SMK_INODE_INSTANT | transflag); --=20 2.53.0 From nobody Fri Oct 2 14:02:28 2026 Received: from mail-qv1-f45.google.com (mail-qv1-f45.google.com [209.85.219.45]) (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 BEC423D810C for ; Thu, 30 Jul 2026 23:45:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455144; cv=none; b=kS4ZdCgceEsi3W6aotdqLe26NvqYKfcWtoSUa9ccMgIpthY1sfBgEislOqYMq7Ey7a09wNFZd1DXkXqomwj+XSMRg9JSfwwdkexy5bjiuDZ2duLMUCCVf2Kh5U7MVuZe/LDht3ixOTgJ5E2943OgTqOB7VziGZXRW04iNffK0aU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455144; c=relaxed/simple; bh=1DTCO6Bphw0A6swBhP7c6bJyoFiSm1Y7s6/4c16HD9E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZfOnYlMOxSeZh3o5N7F22mgKfHsu8ygZUREvU6qmd3dJM5pCcjeAQGSe8DiL0gMLONWCQ9KkbwHgjb308f/iNmfYrfWE8kAl+km4y6gH3XoyDBKNZLBmCE2XLD9YvJ0rzdKJ5XcROvh8L0RfhJJcXza0WLY03z8HlL1auycnCYs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=IfjLWygk; arc=none smtp.client-ip=209.85.219.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IfjLWygk" Received: by mail-qv1-f45.google.com with SMTP id 6a1803df08f44-8f186025973so4976276d6.0 for ; Thu, 30 Jul 2026 16:45:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785455141; x=1786059941; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=jdbK3fdfrv5d4sVx1r+AaPHs8i/JcdSeTVatYSVLKYc=; b=IfjLWygk/NIv3NmVPxmrP0TVaSWqUaKbpCY7M9WzUtfFuEvvAXTDbmNJ/2QImMbswN p3ojJExcqU2ybISntSW7GlrGZNXFo0+L68/9R2OxhV+YLPaSrvO/oXASSbHcagwWGLSe CWeMpmdTq3+TQoXronRoU73X6YKjfONZRXQ6hjX5hyT3td56+psaOvhIDq+q0e9Tqskc BIM7UBcK5d/lVN7trRdHWPQPh0tLHd3dT8riSf74/wy7THJpzjHFZqYv+GiZ0dGvhjiK 3G/7qQen3YmJlZgK3SIfvN99ViIWa/7J3/20b8kqbrOPk661+TryN+3RBOH0oq9GAJWh pDHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785455141; x=1786059941; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=jdbK3fdfrv5d4sVx1r+AaPHs8i/JcdSeTVatYSVLKYc=; b=BDKOZY4y1SYiX7zKsobsDle+pr7Ne1OnpfExs6cazhMXC1HWeQELQygWDrDFtvm8Lp ssPbBx+G9IR2+71GkMCAh4lMrx0DdIJ61XmIbfu4N4D5E2novg2NK3SS7eJbZCKRcPIC u1s3KPFwYOwTq9MWXG8Z7FqPNeVl7NHTdO9zXff04+/e4HbkEYhLViZY2s3J8BuvVSfK jA89uDbDsD7lfK26ClKsfRhqYZz6GriOItI8JIPM71fkcJRLg6hhZkyaQghSF5TN+O2w YZuaTG70GS0J2FoW0cf+M/LxhC1OdyUB4Ohuo8LTfXlhad3Dl1/GXLnjciIybGqto1Yc ByGQ== X-Forwarded-Encrypted: i=1; AHgh+RpEhhuAHc4vCOWhWY5P3h17yb8xCvrnDHKbPKWg0O/2UDugj5PyHUIX5jCX64AdWUUOGq64TFCNEdFjohY=@vger.kernel.org X-Gm-Message-State: AOJu0Yz+iUQrp0PIxsBsoWmqTReQK+UJoZJM5CUWEysM/Xz+UttMWLDD JRLOi+w0EjvbNwc1LLcAxrYeB+fICcqi0Wyx9FYxYcURGU34pVNC5e9V X-Gm-Gg: AR+sD10faxEa7a9tGSyDrrdLvHs7+7k9K7w6RWv8RucCMXIsNYZWSauwBrsK7xOKV6p Py9rBKgI94gzDRCiqLdugu0jAvnE2msePSB5bb7wu71uTjdJvMRTSRLtBKEQFA1HkHFWy/1Jhrs EX1dnBJUVcw0RklF7DUQUzuzMMb7hbnDVx0tta931Vo8Mr/0qS8XMQXMXTc5cxRpdu1TypxhNfj rs4uruvab57kkf8Cdhkd4QIot6DAV9aqbXblF1pP4yQ+Kup7Op49MhIySM15/s5cA08E5juErj2 YKePwMR/xqPzrC12+2mis8HrnL0cV3hNpP7eqfPxTpiXdOT/oFtmIy5r342O2RFtNeCzObNTy+3 wTFapDrEKWyn7yAiT2pwDgUfH9IxjrfQEgWUijcfQmfEjGsl0pwNZD5AlQ8MutLDe4Req4I92v5 HkLG6vmZA6P0ZrFQL6s416ByNkaEGGwmh8xyn17xxVfzp+eo6TmpeYsAfawyhdBcdtSdWLiAQFs djyCT3sANWFIYtvqymug8eKYyVY2VAlelnE+Jay2mr6tzhEm9D4KVm2WfwYdao= X-Received: by 2002:a05:6214:5409:b0:8fe:9e2d:ce4f with SMTP id 6a1803df08f44-9083484849emr49532596d6.65.1785455140622; Thu, 30 Jul 2026 16:45:40 -0700 (PDT) Received: from battery.lan (pool-138-88-31-60.washdc.fios.verizon.net. [138.88.31.60]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-908323e8bc0sm28991836d6.26.2026.07.30.16.45.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Jul 2026 16:45:40 -0700 (PDT) From: David Windsor To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Jiri Olsa , Kumar Kartikeya Dwivedi , Emil Tsalapatis , Matt Bobrowski , Paul Moore , James Morris , "Serge E . Hallyn" , Casey Schaufler , Stephen Smalley , Ondrej Mosnacek , Mimi Zohar , Roberto Sassu , Dmitry Kasatkin , Eric Snowberg , Alexander Viro , Christian Brauner , Jan Kara , Shuah Khan Cc: bpf@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, David Windsor Subject: [PATCH v6 bpf-next 2/4] security: add security_lsmxattr_add() Date: Thu, 30 Jul 2026 19:45:31 -0400 Message-ID: <20260730234533.1912709-3-dwindsor@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260730234533.1912709-1-dwindsor@gmail.com> References: <20260730234533.1912709-1-dwindsor@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add security_lsmxattr_add(), which claims a slot in the inode_init_security xattr array on behalf of the calling LSM and fills it with a copy of the given name and value. Callers pass only the name components beyond their LSM's standard xattr suffix; security_lsmxattr_add() builds the full xattr name from the suffix associated with the given lsm_id. Suggested-by: Paul Moore Signed-off-by: David Windsor --- include/linux/bpf_lsm.h | 3 ++ include/linux/security.h | 10 +++++ security/bpf/hooks.c | 1 + security/security.c | 96 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h index dda272d78f01..4bf350ef02f4 100644 --- a/include/linux/bpf_lsm.h +++ b/include/linux/bpf_lsm.h @@ -12,6 +12,9 @@ #include #include =20 +/* max bpf xattrs per inode */ +#define BPF_LSM_INODE_INIT_XATTRS 4 + #ifdef CONFIG_BPF_LSM =20 extern bool bpf_lsm_initialized __ro_after_init; diff --git a/include/linux/security.h b/include/linux/security.h index 0be590c40689..d35fde7aa11f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -406,6 +406,9 @@ void security_inode_free(struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, initxattrs initxattrs, void *fs_data); +int security_lsmxattr_add(struct lsm_xattrs *xattrs, u64 lsm_id, + const char *name_extra, const void *value, + size_t value_len); int security_inode_init_security_anon(struct inode *inode, const struct qstr *name, const struct inode *context_inode); @@ -900,6 +903,13 @@ static inline int security_inode_init_security(struct = inode *inode, return 0; } =20 +static inline int security_lsmxattr_add(struct lsm_xattrs *xattrs, u64 lsm= _id, + const char *name_extra, + const void *value, size_t value_len) +{ + return -EOPNOTSUPP; +} + static inline int security_inode_init_security_anon(struct inode *inode, const struct qstr *name, const struct inode *context_inode) diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c index 7b98f5d1e2be..8f8c3de3035f 100644 --- a/security/bpf/hooks.c +++ b/security/bpf/hooks.c @@ -33,6 +33,7 @@ static int __init bpf_lsm_init(void) =20 struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init =3D { .lbs_inode =3D sizeof(struct bpf_storage_blob), + .lbs_xattr_count =3D BPF_LSM_INODE_INIT_XATTRS, }; =20 DEFINE_LSM(bpf) =3D { diff --git a/security/security.c b/security/security.c index 2ad7f09c1a61..ae72102cd29b 100644 --- a/security/security.c +++ b/security/security.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) "LSM: " fmt =20 #include +#include #include #include #include @@ -1376,6 +1377,101 @@ int security_inode_init_security(struct inode *inod= e, struct inode *dir, } EXPORT_SYMBOL(security_inode_init_security); =20 +static unsigned int lsm_xattrs_used(const struct lsm_xattrs *xattrs, + const char *prefix) +{ + size_t prefix_len =3D strlen(prefix); + unsigned int i, n =3D 0; + + for (i =3D 0; i < xattrs->xattr_count; i++) { + const char *name =3D xattrs->xattrs[i].name; + + if (name && !strncmp(name, prefix, prefix_len)) + n++; + } + return n; +} + +/** + * security_lsmxattr_add() - Add an xattr during inode_init_security + * @xattrs: xattr state shared by inode_init_security hooks + * @lsm_id: LSM_ID_* value identifying the calling LSM + * @name_extra: xattr name components beyond the calling LSM's standard + * xattr suffix, NULL if the standard suffix is the full name + * @value: xattr value + * @value_len: length of @value + * + * Claim an xattr slot in @xattrs on behalf of the LSM identified by + * @lsm_id and fill it with a copy of @value. The xattr name is built from + * the standard xattr suffix of the calling LSM, followed by @name_extra. + * Callers can invoke this function from non-sleepable context. + * + * Return: Returns 0 on success or if the filesystem does not accept xattrs + * at inode creation, -ENOSPC if the calling LSM's slot budget is + * exhausted, negative values on other errors. + */ +int security_lsmxattr_add(struct lsm_xattrs *xattrs, u64 lsm_id, + const char *name_extra, const void *value, + size_t value_len) +{ + struct xattr *xattr; + void *xattr_value; + const char *suffix; + size_t suffix_len, extra_len, name_len; + + if (!xattrs || !value) + return -EINVAL; + + /* The filesystem did not provide an initxattrs callback. */ + if (!xattrs->xattrs) + return 0; + + switch (lsm_id) { + case LSM_ID_BPF: + if (!name_extra || !name_extra[0]) + return -EINVAL; + suffix =3D XATTR_BPF_LSM_SUFFIX; + if (lsm_xattrs_used(xattrs, XATTR_BPF_LSM_SUFFIX) >=3D + BPF_LSM_INODE_INIT_XATTRS) + return -ENOSPC; + break; + default: + return -EINVAL; + } + + suffix_len =3D strlen(suffix); + extra_len =3D name_extra ? strlen(name_extra) : 0; + name_len =3D suffix_len + extra_len; + if (name_len > XATTR_NAME_MAX) + return -EINVAL; + if (value_len =3D=3D 0 || value_len > XATTR_SIZE_MAX) + return -EINVAL; + + /* Combine xattr value + name into one allocation. */ + xattr_value =3D kmalloc(value_len + name_len + 1, GFP_NOWAIT); + if (!xattr_value) + return -ENOMEM; + + memcpy(xattr_value, value, value_len); + memcpy(xattr_value + value_len, suffix, suffix_len); + if (extra_len) + memcpy(xattr_value + value_len + suffix_len, name_extra, + extra_len); + ((char *)xattr_value)[value_len + name_len] =3D '\0'; + + xattr =3D lsm_get_xattr_slot(xattrs); + if (!xattr) { + kfree(xattr_value); + return -ENOSPC; + } + + xattr->value =3D xattr_value; + xattr->name =3D (const char *)xattr_value + value_len; + xattr->value_len =3D value_len; + + return 0; +} + /** * security_inode_init_security_anon() - Initialize an anonymous inode * @inode: the inode --=20 2.53.0 From nobody Fri Oct 2 14:02:28 2026 Received: from mail-qv1-f46.google.com (mail-qv1-f46.google.com [209.85.219.46]) (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 709EC40E8C1 for ; Thu, 30 Jul 2026 23:45:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455145; cv=none; b=qrecUPhaMl7SOhr1osI+gSFpy9l1o9UXxnhpGB+VbkKQc8Oe53fE57x+zbOyn2coedVNIygqTxBVBt2RK5Y45tnjGicFlzBJPbkDXus3PMG99PINrQNz6yDl/dfoktNuRIN5qGYDa86U83AD0X3pog1YioWttA2NgQ3pdqQmy9M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455145; c=relaxed/simple; bh=UeLmhePSWPFBkTNLrPRrGvFa0QdMl0ECbxnKCarjDNY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hRyaadirRHoHAZTwbQ5DV4ayDPEsrkYasxIu1nJjB/fHOcm4MxYtWMxTqt9ga4S+PzVLnSv/bzNAkEagKh8s5/UQekCfetEg6HAoD8KdnKTrboORIbSYcuvlbj8rTHFUK863xK0yKzyuJm6LR8n5J2C6shALPC0tfUhJASAPG5U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fcN0Tc+2; arc=none smtp.client-ip=209.85.219.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fcN0Tc+2" Received: by mail-qv1-f46.google.com with SMTP id 6a1803df08f44-902fc790cd5so3132806d6.1 for ; Thu, 30 Jul 2026 16:45:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785455142; x=1786059942; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=6bZ7yPHg5vYfLp4cv5XEz6QymRiym0C5qHzBJxTtuE4=; b=fcN0Tc+2K8qu8lyLltORgo0w57ssv+K8cESw8jhOzqU7VeB2DkglRQQO9bhGEikiBN 5dlf811xyvSpZGX2rzNCJmfvhnJvFUvZAaUUeGeZp5SI5p/LyrxBBXaw+DCgXDNA8Bbe ReKDKnUUHd4FF86S1vNfrcClSkrs3EpDczDCIneazYT/b7qC8dn2y/poW4WD0c7tQbHV I4f0yc+BmmibTzqVEOIqp4Mgh8qBut1kAbRY6us4R0tUqHsfmXmFtsHZN9fTlBlkKNfd 2ZFVeLVuZ3clqAM6luCKGGWQ5tEbKalm8UJRL3JW5m4g5oW6wyx/XVkm2j8ftysDIho/ uq7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785455142; x=1786059942; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=6bZ7yPHg5vYfLp4cv5XEz6QymRiym0C5qHzBJxTtuE4=; b=Fc4w7E0CeewbQuW4oPiRkd4OCRgGYyZE+c4C3TP2kFl7jCzxOarXE+yJvupWaz+eXq ohic533T9Sw9HCj6gezz/K/22QGzdpOI53/tY19IUEWk+KVDxoCw8zmZ2BbSQjekoP1g oA1XopRBzmVObV7IA1aloODJAawIRxn8wStiu50SIexEiheXIzkFYTTdliaftjTxpZIz sG5C0H4abgvMAcpZRBXBrOyc72oU+KvojhM3b5M7ZG9EU4bvP7aN2WlcM6aZdegwgErF R61QfIA2dvHIL7LJHcTFe9aPn/l/r9ZuBHPwwXNbhyxIbRp2J7S8zpXG5NjLzv5XXU1S 2drQ== X-Forwarded-Encrypted: i=1; AHgh+RqEkqQMjwy9qAfHADmEmqf15GD8+KcFG5ub4p/KZBu+CZX4ILlLjJRIx81veXmsSCLQQc1e8ij2qEkkjsA=@vger.kernel.org X-Gm-Message-State: AOJu0YyWtgYRvecD2+FlgAupfUYonPVbWlvfMpjK8zjZk6Ujy3oPWE+W SeJl2RUZ05Zdzdg+vhCzX820D483ZbiWvayuIi9OuElDDZC0RscIeSUP X-Gm-Gg: AR+sD10XVIdG11wtQqOiDLhP2qUfVfBJGrObKx/TRGVYLyPyZQSWpEUSpnzw3TXv6NK rbkcmW1fVj1dIRrd9kaGjwEeBIBn5T9S+sHGmRGGZTr74NVEpVBfwRPZuKSrr2Hg1mI3oEWD3MR 1MCoYf8S7ZfIYeorXbQ+J4pM6OWSiFbgbHJezcuI0nZxPYsAr6bY4Gx5WvCjNa/hwgVldo9sCo+ xhixW7lhKGVzrGkM5UuR20l5nKS7Msl80qmoworaHhCYBRhTNfde46yDYtPPKEOE/vxclcrVZSs E85rQr0WEHdeaLhW7KpZxt0xq85lsIMeCmgsWvB8B4y3QEtiFau4NVKqhlXrF12N4RHIApyn4/m RfXNj17IkXDoN+MD0Ih7YpNRx1nZJby6CMxax8ZCuSq83Y8KiJwe6tzPbvPbAHDq+BRHWEpS+Hd Gg+gKKLKrpV1zf3wpVXnFgG4C0seZuwYBZMsxzWmVpyhmaAWGSw3EK3icwNXs6mKQ//EEpFwaF5 CekwIln0En1HYCrHR130RTm//CcgEuERARPnZCovvEgDBPwCVJNaHKKZZq41i9J6HqtYTbTAQ== X-Received: by 2002:a05:6214:3901:b0:8ef:db4:d85f with SMTP id 6a1803df08f44-9083bb5b841mr27021636d6.41.1785455142243; Thu, 30 Jul 2026 16:45:42 -0700 (PDT) Received: from battery.lan (pool-138-88-31-60.washdc.fios.verizon.net. [138.88.31.60]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-908323e8bc0sm28991836d6.26.2026.07.30.16.45.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Jul 2026 16:45:41 -0700 (PDT) From: David Windsor To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Jiri Olsa , Kumar Kartikeya Dwivedi , Emil Tsalapatis , Matt Bobrowski , Paul Moore , James Morris , "Serge E . Hallyn" , Casey Schaufler , Stephen Smalley , Ondrej Mosnacek , Mimi Zohar , Roberto Sassu , Dmitry Kasatkin , Eric Snowberg , Alexander Viro , Christian Brauner , Jan Kara , Shuah Khan Cc: bpf@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, David Windsor Subject: [PATCH v6 bpf-next 3/4] bpf: add bpf_init_inode_xattr kfunc for atomic inode labeling Date: Thu, 30 Jul 2026 19:45:32 -0400 Message-ID: <20260730234533.1912709-4-dwindsor@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260730234533.1912709-1-dwindsor@gmail.com> References: <20260730234533.1912709-1-dwindsor@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add bpf_init_inode_xattr() kfunc for BPF LSM programs to atomically set xattrs via the inode_init_security hook using security_lsmxattr_add(). The hook now passes its xattr state as a single struct lsm_xattrs object, which the kfunc takes directly. This kfunc is only callable from inode_init_security; the verifier rejects attempts to call it elsewhere. A previous attempt [1] required a kmalloc string output protocol for the xattr name. Since commit 6bcdfd2cac55 ("security: Allow all LSMs to provide xattrs for inode_init_security hook") [2], the xattr name is no longer allocated; it is a static constant. Link: https://kernsec.org/pipermail/linux-security-module-archive/2022-Octo= ber/034878.html [1] Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/co= mmit/?id=3D6bcdfd2cac55 [2] Suggested-by: Song Liu Signed-off-by: David Windsor --- fs/bpf_fs_kfuncs.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c index f1863a891db6..7b55073934e0 100644 --- a/fs/bpf_fs_kfuncs.c +++ b/fs/bpf_fs_kfuncs.c @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include =20 __bpf_kfunc_start_defs(); =20 @@ -379,6 +381,44 @@ __bpf_kfunc struct inode *bpf_real_data_inode(struct f= ile *file) return d_real_inode(file_dentry(file)); } =20 +/** + * bpf_init_inode_xattr - set an xattr on a new inode from inode_init_secu= rity + * @xattrs: inode_init_security xattr state from the hook context + * @name__str: xattr name (e.g., "bpf.file_label") + * @value_p: dynptr containing the xattr value + * + * Only callable from lsm/inode_init_security programs. + * + * Return: 0 on success, -EOPNOTSUPP if the filesystem does not accept + * xattrs at inode creation, negative error on other failures. + */ +__bpf_kfunc int bpf_init_inode_xattr(struct lsm_xattrs *xattrs, + const char *name__str, + const struct bpf_dynptr *value_p) +{ + struct bpf_dynptr_kern *value_ptr =3D (struct bpf_dynptr_kern *)value_p; + const void *value; + u32 value_len; + + if (!name__str) + return -EINVAL; + if (strncmp(name__str, XATTR_BPF_LSM_SUFFIX, + sizeof(XATTR_BPF_LSM_SUFFIX) - 1)) + return -EPERM; + + if (!xattrs->xattrs) + return -EOPNOTSUPP; + + value_len =3D __bpf_dynptr_size(value_ptr); + value =3D __bpf_dynptr_data(value_ptr, value_len); + if (!value) + return -EINVAL; + + return security_lsmxattr_add(xattrs, LSM_ID_BPF, + name__str + sizeof(XATTR_BPF_LSM_SUFFIX) - 1, + value, value_len); +} + __bpf_kfunc_end_defs(); =20 BTF_KFUNCS_START(bpf_fs_kfunc_set_ids) @@ -390,6 +430,7 @@ BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_remove_dentry_xattr, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_real_data_inode, KF_SLEEPABLE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_init_inode_xattr) BTF_KFUNCS_END(bpf_fs_kfunc_set_ids) =20 static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id) --=20 2.53.0 From nobody Fri Oct 2 14:02:28 2026 Received: from mail-qv1-f48.google.com (mail-qv1-f48.google.com [209.85.219.48]) (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 DD3EA4156EB for ; Thu, 30 Jul 2026 23:45:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455148; cv=none; b=CUfMwpcVNEXZd/U0jfTrrXdIPEu5oX1nipsXON7CQC6RNMAlQuGF6KwPy+su3gOe2zjtFiVRT4NhZgIRoOj38tniMlmFmbOtfJUxb1QClUmsudpaeAC7xP1VcHT8+5FiLIVz1+nUrPtJh4r6oJ+pFJ7e90krQErFUo0QnIyLkEE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785455148; c=relaxed/simple; bh=g5JI2ISuJpDK1rGZXzBnJjdbj1LWap5IiNy3B60XDFc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KRExpAN7Z0pKvJkIDKpxz5r7MDPfK2VWjyofshr/XZmcAAENC5gJJxwpDM1PZiHq4KKJg5FRX446Lj8QpdW653Ni7UPbrBhCE9f2NexSwlAlFR6rsS1meg/G7Mg8YxfBWwofdTjd2G5tami+7UwRUsoyKNr32s/t8qvMZOV0YR4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GFPouuRO; arc=none smtp.client-ip=209.85.219.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GFPouuRO" Received: by mail-qv1-f48.google.com with SMTP id 6a1803df08f44-8eefd4a8057so4594516d6.0 for ; Thu, 30 Jul 2026 16:45:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785455144; x=1786059944; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=37JfktnWKSwnsVTmyOwT4tNbEmQBNW4uYVQkWjpnTqE=; b=GFPouuROcz6ugxIHaVAki2vlYjr4mflpEJijkejWsj3ry0f1ZDVi6yog4/amul3QJF Fcw8m53cQCl587c38e/t461TLC2j/9KBbtOjL4/XrDpn3hJMnAlJcbx9ITWGTvvvlcED qwIj2NLPSNzj72Xrp/lH7afLhpSWLTSM6THX4mIg6Q5Sc2sgYUuPmZJXZr4IhTrKYrdh 2QTq+6RadmWOKKQKOKYvbCg67L4DcEmcF3xyyKkBTtXvgHD7vA2ZDf0J0t112YSVyE0A GfbScAoKZiNXY9GlwN7DdcDVJ+iHY4nQHsI2b7jCQDzf5yRWSqjP4LtlxjjAKeXCh4D3 zHJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785455144; x=1786059944; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=37JfktnWKSwnsVTmyOwT4tNbEmQBNW4uYVQkWjpnTqE=; b=o+anhKppmUqZs0DUwOfaMQVXX6TXEzhcbZScmssHScOrFmsqRew8RLDZ/Feytfh74/ CixzCB5fgJIp2YiBDQ3WR37jtOqNH6Dd8FmUlkyQ3NdusyfgG6e20pjjXwmb/CSg68NA TMmGnYrhyvBxOPN5HMiW//YmtpNsLgaR5Sc6t8O6NXlga5bzdXytrW1in/QttI2smuTP WGRoAIPfIhpAI9jL2MZiGRVGors09edyK2kH7QyaAZ50UUS60MoQJ3ml4Wm+x6wWyqXK DUEPTDij6HzMuErtLTm0LiuTGYTHHWuET5mHzNxIg5UWJ/zLjiHWyEWLybp+XfEhCfjA R6zQ== X-Forwarded-Encrypted: i=1; AHgh+RoDnnnSaUnhrw+WDS7GWjGZLQYVvUi8LduE86sa25zbrE07gqS+JkWZvVRU4qmE+2YKJy2xJW91YiB5egw=@vger.kernel.org X-Gm-Message-State: AOJu0YzSdm4ogv/yC1jyCnCpKdgAT/YACqpAdNOxAkQYQkhIj5YMZNmJ /XMIHgsTyRvQTXpeMUkgGineoa1XaM6Tu2Zm+LKqIyxBwLEG/3f5apRs X-Gm-Gg: AR+sD113vOS71WLyR9fHnborEgqDkL/qNGdWkRukhd9+8ahshhiJ5+ldDh0TjQJerET ZdcopmQKWXVYDbe6FeOXPANGHFXOYUo9JDGQLKdHA+f6ANmL2T2otdnfsNi7SeVMbtl7l3Icb9f brMjHVrUTZViqpYaMK2NBFYrPUu/YQ6fdnAPh2+7MyWxCgMcshO0uxUnCsVji6/tAZN6bnrzTYG uivOluqoI6S4KN/U3svs0D0RdP8ZpRr2pXEkfC+kcmB5OtpfDOQg1vkqlET9Vc07wtaXBNuCels hxFsw50nFJ+A3FFU9BDc5lcBsaR6jkKvt+rVhZ58bwEk+nsw83HJ3x6Dlek2AHJEz9xYWU4KPlT PeN7X2Kzm4dF7Umk0SBFjLiXcd17b5O7Et6jOlr1cVZKhpzhzWcrVx0LJj4iomL/357JP9ZWl7X 2c6lySvXwf3W4gD2nzqqlZU3sB9Mp9IIp0iagBLd4RIAF1dMYCsyXUh3Csv2xPjg5Snml87uWBi C9VeCTjNITNiypZo4PHysaBmQQZObZJPU7eTfTVWYUSDQ6gGmDlmtVTWk0LXmI= X-Received: by 2002:a05:6214:4a86:b0:907:4598:ad3 with SMTP id 6a1803df08f44-908347b8db0mr47894106d6.50.1785455143760; Thu, 30 Jul 2026 16:45:43 -0700 (PDT) Received: from battery.lan (pool-138-88-31-60.washdc.fios.verizon.net. [138.88.31.60]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-908323e8bc0sm28991836d6.26.2026.07.30.16.45.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Jul 2026 16:45:42 -0700 (PDT) From: David Windsor To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , John Fastabend , KP Singh , Jiri Olsa , Kumar Kartikeya Dwivedi , Emil Tsalapatis , Matt Bobrowski , Paul Moore , James Morris , "Serge E . Hallyn" , Casey Schaufler , Stephen Smalley , Ondrej Mosnacek , Mimi Zohar , Roberto Sassu , Dmitry Kasatkin , Eric Snowberg , Alexander Viro , Christian Brauner , Jan Kara , Shuah Khan Cc: bpf@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, David Windsor Subject: [PATCH v6 bpf-next 4/4] selftests/bpf: add tests for bpf_init_inode_xattr kfunc Date: Thu, 30 Jul 2026 19:45:33 -0400 Message-ID: <20260730234533.1912709-5-dwindsor@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260730234533.1912709-1-dwindsor@gmail.com> References: <20260730234533.1912709-1-dwindsor@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Test bpf atomic inode xattr labeling in inode_init_security. Signed-off-by: David Windsor --- tools/testing/selftests/bpf/bpf_kfuncs.h | 5 + .../selftests/bpf/prog_tests/fs_kfuncs.c | 156 ++++++++++++++++++ .../bpf/progs/test_init_inode_xattr.c | 33 ++++ 3 files changed, 194 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/test_init_inode_xattr= .c diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selft= ests/bpf/bpf_kfuncs.h index ae71e9b69051..2639f9f94195 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -92,4 +92,9 @@ extern int bpf_set_dentry_xattr(struct dentry *dentry, co= nst char *name__str, const struct bpf_dynptr *value_p, int flags) __ksym __weak; extern int bpf_remove_dentry_xattr(struct dentry *dentry, const char *name= __str) __ksym __weak; =20 +struct lsm_xattrs; +extern int bpf_init_inode_xattr(struct lsm_xattrs *xattrs, + const char *name__str, + const struct bpf_dynptr *value_p) __ksym __weak; + #endif diff --git a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c b/tools/tes= ting/selftests/bpf/prog_tests/fs_kfuncs.c index 43a26ec69a8e..b208522dbd33 100644 --- a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c +++ b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c @@ -10,6 +10,7 @@ #include "test_get_xattr.skel.h" #include "test_set_remove_xattr.skel.h" #include "test_fsverity.skel.h" +#include "test_init_inode_xattr.skel.h" =20 static const char testfile[] =3D "/tmp/test_progs_fs_kfuncs"; =20 @@ -268,6 +269,155 @@ static void test_fsverity(void) remove(testfile); } =20 +static void test_init_inode_xattr(void) +{ + struct test_init_inode_xattr *skel =3D NULL; + int fd =3D -1, err; + char value_out[64]; + + /* This test must be run from a fs that calls + * security_inode_init_security(). + */ + const char *testfile_new =3D "/dev/shm/test_progs_fs_kfuncs_new"; + + skel =3D test_init_inode_xattr__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_init_inode_xattr__open_and_load")) + return; + + skel->bss->monitored_pid =3D getpid(); + err =3D test_init_inode_xattr__attach(skel); + if (!ASSERT_OK(err, "test_init_inode_xattr__attach")) + goto out; + + /* Trigger inode_init_security */ + fd =3D open(testfile_new, O_CREAT | O_RDWR, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + goto out; + + /* + * Probably should not be needed as we will be labeling a file + * in /dev/shm, but just in case we check if the hook was actually + * called. + */ + if (!skel->bss->hook_ran) { + printf("%s:SKIP:inode_init_security hook was not invoked\n", + __func__); + test__skip(); + goto out; + } + + /* The filesystem does not accept xattrs at inode creation. */ + if (skel->data->init_result =3D=3D -EOPNOTSUPP) { + printf("%s:SKIP:filesystem does not support LSM init xattrs\n", + __func__); + test__skip(); + goto out; + } + + ASSERT_EQ(skel->data->init_result, 0, "init_result"); + + /* initxattrs prepends "security." to the name. */ + err =3D getxattr(testfile_new, "security.bpf.test_label", value_out, + sizeof(value_out)); + if (err < 0 && errno =3D=3D ENODATA) { + printf("%s:SKIP:filesystem did not apply LSM xattrs\n", + __func__); + test__skip(); + goto out; + } + if (!ASSERT_GE(err, 0, "getxattr")) + goto out; + + ASSERT_EQ(err, (int)sizeof(skel->data->xattr_value), "xattr_size"); + ASSERT_EQ(strncmp(value_out, "unconfined_u:object_r:user_home_t:s0", + sizeof("unconfined_u:object_r:user_home_t:s0")), 0, + "xattr_value"); + +out: + close(fd); + test_init_inode_xattr__destroy(skel); + remove(testfile_new); +} + +/* Keep in sync with BPF_LSM_INODE_INIT_XATTRS in include/linux/bpf_lsm.h.= */ +#define INIT_INODE_XATTR_MAX 4 + +/* + * Programs may attach to inode_init_security without an attach-time limit= , but + * the kfunc only lets BPF claim INIT_INODE_XATTR_MAX xattr slots per inod= e. + * Calls beyond that budget are rejected at runtime with -ENOSPC. + */ +static void test_init_inode_xattr_slot_limit(void) +{ + struct test_init_inode_xattr *skel[INIT_INODE_XATTR_MAX + 1] =3D {}; + struct bpf_link *link[INIT_INODE_XATTR_MAX + 1] =3D {}; + const char *testfile_slot =3D "/dev/shm/test_progs_fs_kfuncs_slot"; + int ok =3D 0, nospc =3D 0, notrun =3D 0, other =3D 0; + int i, fd =3D -1; + + /* All programs attach successfully; there is no attach-time cap. */ + for (i =3D 0; i <=3D INIT_INODE_XATTR_MAX; i++) { + skel[i] =3D test_init_inode_xattr__open(); + if (!ASSERT_OK_PTR(skel[i], "open")) + goto out; + + snprintf(skel[i]->rodata->xattr_name, + sizeof(skel[i]->rodata->xattr_name), "bpf.label_%d", + i); + + if (!ASSERT_OK(test_init_inode_xattr__load(skel[i]), "load")) + goto out; + + skel[i]->bss->monitored_pid =3D getpid(); + + link[i] =3D bpf_program__attach_lsm(skel[i]->progs.test_init_inode_xattr= ); + if (!ASSERT_OK_PTR(link[i], "attach")) + goto out; + } + + /* Trigger inode_init_security once with all programs attached. */ + fd =3D open(testfile_slot, O_CREAT | O_RDWR, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + goto out; + + /* + * Exactly INIT_INODE_XATTR_MAX programs claim a slot; test + * xattr budget accounting with -ENOSPC. + */ + for (i =3D 0; i <=3D INIT_INODE_XATTR_MAX; i++) { + int res =3D skel[i]->data->init_result; + + if (!skel[i]->bss->hook_ran || res =3D=3D -EOPNOTSUPP) + notrun++; + else if (res =3D=3D 0) + ok++; + else if (res =3D=3D -ENOSPC) + nospc++; + else + other++; + } + + if (notrun =3D=3D INIT_INODE_XATTR_MAX + 1) { + printf("%s:SKIP:hook not invoked or fs lacks LSM init xattrs\n", + __func__); + test__skip(); + goto out; + } + + ASSERT_EQ(ok, INIT_INODE_XATTR_MAX, "slots_within_budget"); + ASSERT_EQ(nospc, 1, "slot_over_budget"); + ASSERT_EQ(other, 0, "unexpected_result"); + +out: + if (fd >=3D 0) + close(fd); + for (i =3D 0; i <=3D INIT_INODE_XATTR_MAX; i++) { + bpf_link__destroy(link[i]); + test_init_inode_xattr__destroy(skel[i]); + } + remove(testfile_slot); +} + void test_fs_kfuncs(void) { /* Matches xattr_names in progs/test_get_xattr.c */ @@ -288,4 +438,10 @@ void test_fs_kfuncs(void) =20 if (test__start_subtest("fsverity")) test_fsverity(); + + if (test__start_subtest("init_inode_xattr")) + test_init_inode_xattr(); + + if (test__start_subtest("init_inode_xattr_slot_limit")) + test_init_inode_xattr_slot_limit(); } diff --git a/tools/testing/selftests/bpf/progs/test_init_inode_xattr.c b/to= ols/testing/selftests/bpf/progs/test_init_inode_xattr.c new file mode 100644 index 000000000000..ce3d8d39de9c --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_init_inode_xattr.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Cisco Systems, Inc. */ + +#include "vmlinux.h" +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") =3D "GPL"; + +__u32 monitored_pid; +int hook_ran; +int init_result =3D -1; + +const char xattr_name[16] =3D "bpf.test_label"; +char xattr_value[] =3D "unconfined_u:object_r:user_home_t:s0"; + +SEC("lsm/inode_init_security") +int BPF_PROG(test_init_inode_xattr, struct inode *inode, struct inode *dir, + const struct qstr *qstr, struct lsm_xattrs *xattrs) +{ + struct bpf_dynptr value_ptr; + __u32 pid; + + pid =3D bpf_get_current_pid_tgid() >> 32; + if (pid !=3D monitored_pid) + return 0; + + hook_ran =3D 1; + bpf_dynptr_from_mem(xattr_value, sizeof(xattr_value), 0, &value_ptr); + init_result =3D bpf_init_inode_xattr(xattrs, xattr_name, &value_ptr); + + return 0; +} --=20 2.53.0