From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-yx1-f47.google.com (mail-yx1-f47.google.com [74.125.224.47]) (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 07C3830ACF0 for ; Fri, 31 Jul 2026 02:21:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.47 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785464475; cv=none; b=BezCb5RSC/wVIOUPzuY0kGMIkg23pLetUPwAm24gSDH6kIOgCsWtkbHhAqqC8x8+wzf8nx2dw7c5vF38Ax9OPB9Q4ysvzm+DutCYYbuZ1uMxgnnWZaU/etxj3mUzLNnvsYE5zy0xp0iKyRXg5heJ/qnun4iKpJY8pdYFoxWugqE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785464475; c=relaxed/simple; bh=JVIUapt3mXax8Zzvl5moEskJgWAHSXq0LtxR/fnDvOc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nlQvBmvoAINQyLWwm5KTTMag8w1OC7NP10ZXjpnwqo0/uX0WPo8c9Cw1WOp/Im2fJEnDvKXqRNaBDZZc+DV7pbPi3LPDpvTP+FtyFpqEFsqlyzOteMb1cT0qv+w/jw4xTLxMgHEiqDdlobRUn0RgFGwWQl+id/BLCABVTkSP3ww= 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=iVnaw4OA; arc=none smtp.client-ip=74.125.224.47 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="iVnaw4OA" Received: by mail-yx1-f47.google.com with SMTP id 956f58d0204a3-6681e7911b0so550995d50.0 for ; Thu, 30 Jul 2026 19:21:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785464473; x=1786069273; 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=kln/oJiLAaRdTDOdng8Bb4F+q8mG/4pvdPDoCAUkB+k=; b=iVnaw4OARcyiwp17xlfVt4+M0Qln/nWfZh3V6PdoyeJDARWkLDsbBYfRGIXcR6/SDL d3x6lGmVgS42X8j5BvBW1rdFFjjSaDuHDEqczFPyQtlwB6PdXabQALbplYiEZWb0syAH wi0/qJ3m+QJOEWDEEIOvQ/lp9YSwK4ngN6bJqJ2swcD/8oaAWoPKRgE0yOgoaH1RVvPn HpfeG4z1tzlUc+447NhYmr3pAyEpXy96ft19d7JIe9XXUvmICg6AS2BRY/upe4WsjoUI tJz4C9CXOUMd63rLrGC7llWWpTW+ZO0XPx/rQhZ0C0+JEqXn5LTFkK1jzvvG2S170w56 Zu6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785464473; x=1786069273; 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=kln/oJiLAaRdTDOdng8Bb4F+q8mG/4pvdPDoCAUkB+k=; b=K+kp0fqR6p2TJCm34LhUDXvkvN50mMuRP8mX6/diuqhYtqubnMUXlHK2Z5SNltAoHS 51uzMKjJCKMYvAwjL737ps1vwFMVdy407B+KLadccxjYyRSZXGTLunpyxkRi/u4mPeCu XrKOoxszYjVV059Z7sYenZsnzAiwkg4IYbvO17Tcdj2nJwXLZcrS1akiZi0KNmPy6XPv rCbhiTIVnQ+mgezgh+c7PjalVvksRkp/7/Hycq8vK0qWGP5/u/f+dhMza0TXcIxla9GW F3Uwa56v6koN8wlHRChRF80LyjI4pWXFOvIsXHuj/JBuY5y89/3qEp2ELiMJELGI2Gx2 ChVA== X-Forwarded-Encrypted: i=1; AHgh+RpGQWEpptYGgJ89KyQlaPXl0XrIR8vtHkn5SOsKUUHQRg14p3eyYutzfHeDlpnLXUxwdJM=@vger.kernel.org X-Gm-Message-State: AOJu0YxcRdLy391Eym87+Mf6gkfnQMLszh3baBcIt+ZmSmpdDxoAQB5t DU9/d+uTlhk6kdtjQcSKXHYgoDQDzAnnleLPD3TGDjbUMdkwIa1W+PWB X-Gm-Gg: AR+sD12z/Pi5HSUjejbBQ+NcVLOb6Fb1KGq/6/vdPRdKbKXxxpqUNQC8pCk5PgJJgpA Lm2zPfkZx9OYqTgMaEt+SVXtYp99pzr6PHAWYmpPBCT8TdUDcCDDRzcPLO5bA5BgycvbKvCK2rk vEvVbH4kY+1ArXEvv8VmA9+ApOHdFAXYLJtS11b5zwQNPdL2nT41pHgX1pV4PyovsJqBWaCQdUQ VuzekoAvtKn4j/TBEBzBzp7zCeZFtDvbEUNTGHVXN8dfZaGxqVyWo8cgfZoKPRs/RnyEOQr0DRX Mc2BYG/cKq8L/xe/URqTGJQ+IgvGv2+OxoEGW78dUGkgeozUSZYHnh8Jf91+FZV/jk3bpstn0Oy TgW1svbsjPS3gSopwuALLi/ytnkPT//JMS2D8FEvtgjJIKhK95+QjJMfrKkM1o6wg3gddrL8FKx I6cyGsi6hgVlHCUyhvO9jeINf/FbXDGA0kA210dVbhl/iiUOPB7WqX9LKrK/9xFOJfAr5wtBvFz 88NqhGDBHH540FsZEtx5A== X-Received: by 2002:a05:690c:9981:b0:81e:8a24:d5fe with SMTP id 00721157ae682-81fcb9727a2mr778437b3.2.1785464472839; Thu, 30 Jul 2026 19:21:12 -0700 (PDT) Received: from zenbox ([2600:1700:18fb:6011:e94:8a83:feea:6720]) by smtp.gmail.com with ESMTPSA id 00721157ae682-81fb8b26e8bsm20519047b3.47.2026.07.30.19.21.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Jul 2026 19:21:12 -0700 (PDT) From: Justin Suess To: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, kpsingh@kernel.org, paul@paul-moore.com, mic@digikod.net, viro@zeniv.linux.org.uk, brauner@kernel.org, kees@kernel.org Cc: gnoack@google.com, jack@suse.cz, song@kernel.org, yonghong.song@linux.dev, martin.lau@linux.dev, m@maowtm.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, Justin Suess , Casey Schaufler Subject: [PATCH bpf-next 01/13] lsm: Add LSM hook security_policy_kptr_from_fd Date: Thu, 30 Jul 2026 22:20:34 -0400 Message-ID: <20260731022047.189137-2-utilityemal77@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260731022047.189137-1-utilityemal77@gmail.com> References: <20260731022047.189137-1-utilityemal77@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Add a generic LSM hook handing out a reference to an LSM policy object on behalf of a kernel-internal caller: security_policy_kptr_from_fd(lsmid, fd, &policy) together with union lsm_policy_kptr, the tagged payload carrying such a reference across the LSM boundary. The union holds one per-LSM member; which member is valid is determined by the lsmid the caller passes. The pointers the members hold are the BTF-visible handles whose provenance the BPF verifier guarantees, i.e. referenced kptrs, hence the hook naming: the reference stays strongly typed from the BPF program through the hook to the owning LSM, which resolves the handle to its internal policy representation. This hook backs BPF kfuncs: it lets an LSM hand out a reference to one of its policy objects (identified by a file descriptor created through the LSM's own userspace API) without exporting any symbol or defining any BPF interface itself. The reference is released through security_policy_kptr_put(), added by the next patch. The hook uses targeted dispatch: the shim walks the hook list and only calls the implementation registered by the LSM matching @lsmid, following the security_getprocattr()/security_setprocattr() patterns for generic hooks carrying LSM-specific payloads. When no active LSM matches, the shim returns -EOPNOTSUPP: a kfunc call for an LSM that is compiled out or not enabled fails at runtime rather than being hidden from the BPF program at verification time. For the same reason the union members are not guarded by the LSMs' CONFIG options: the callers are built independently of any individual LSM. The hook is excluded from the "bpf" LSM's attachment points. The targeted dispatch would only reach a program attached there for calls with LSM_ID_BPF, which no caller passes, so the attachment point would be dead. Cc: Paul Moore Cc: Casey Schaufler Signed-off-by: Justin Suess --- Notes: The hook naming choice of policy_kptr_from_fd and the other hooks is up in the air for me. I decided to include the kptr part in the name because it's relevant to the task being performed: we are simply getting a pointer to a kernel policy object from a file descriptor. I'm open to better ideas for the name... include/linux/lsm_hook_defs.h | 2 ++ include/linux/security.h | 25 +++++++++++++++++++++++ kernel/bpf/bpf_lsm.c | 1 + security/security.c | 38 +++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 65c9609ec207..afd5b3f932a9 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -452,6 +452,8 @@ LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token) LSM_HOOK(int, 0, bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd) LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap) +LSM_HOOK(int, -EOPNOTSUPP, policy_kptr_from_fd, int fd, + union lsm_policy_kptr *policy) #endif /* CONFIG_BPF_SYSCALL */ LSM_HOOK(int, 0, locked_down, enum lockdown_reason what) diff --git a/include/linux/security.h b/include/linux/security.h index 153e9043058f..db807e61d310 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -168,6 +168,23 @@ struct lsm_prop { struct lsm_prop_bpf bpf; }; +struct bpf_landlock_ruleset; + +struct lsm_policy_landlock { + struct bpf_landlock_ruleset *ruleset; +}; + +/* + * A reference to an LSM policy object, tagged by the LSM_ID_* value + * passed alongside: only the matching LSM's member is valid. The + * members are not guarded by the LSMs' CONFIG options: the callers + * are built independently of any individual LSM and a call for a + * missing LSM must fail at runtime, not at build time. + */ +union lsm_policy_kptr { + struct lsm_policy_landlock landlock; +}; + extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1]; /* These functions are in security/commoncap.c */ @@ -2312,6 +2329,8 @@ extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *at extern void security_bpf_token_free(struct bpf_token *token); extern int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd); extern int security_bpf_token_capable(const struct bpf_token *token, int cap); +extern int security_policy_kptr_from_fd(u64 lsmid, int fd, + union lsm_policy_kptr *policy); #else static inline int security_bpf(int cmd, union bpf_attr *attr, unsigned int size, bool kernel) @@ -2365,6 +2384,12 @@ static inline int security_bpf_token_capable(const struct bpf_token *token, int { return 0; } + +static inline int security_policy_kptr_from_fd(u64 lsmid, int fd, + union lsm_policy_kptr *policy) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_SECURITY */ #endif /* CONFIG_BPF_SYSCALL */ diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index 3983b4ce73c8..9fa514204fb5 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -56,6 +56,7 @@ BTF_ID(func, bpf_lsm_xfrm_decode_session) #endif BTF_ID(func, bpf_lsm_ismaclabel) BTF_ID(func, bpf_lsm_file_alloc_security) +BTF_ID(func, bpf_lsm_policy_kptr_from_fd) BTF_SET_END(bpf_lsm_disabled_hooks) /* List of LSM hooks that should operate on 'current' cgroup regardless diff --git a/security/security.c b/security/security.c index 71aea8fdf014..14fd8b878cd0 100644 --- a/security/security.c +++ b/security/security.c @@ -5441,6 +5441,44 @@ int security_bpf_token_capable(const struct bpf_token *token, int cap) return call_int_hook(bpf_token_capable, token, cap); } +/** + * security_policy_kptr_from_fd() - Get an LSM policy object from a fd + * @lsmid: LSM_ID_* value of the LSM asked to interpret @fd + * @fd: file descriptor referring to a policy object, resolved in the + * calling task's file descriptor table + * @policy: receives the referenced policy object in the member of the + * LSM identified by @lsmid + * + * Ask the LSM identified by @lsmid to translate @fd into a reference + * counted policy object. The caller must not dereference the + * returned handle, must only hand it back to the same LSM, e.g. + * through security_bprm_enforce_policy_kptr(), and must release it + * with security_policy_kptr_put(). Only the hook implementation of + * the LSM identified by @lsmid is called. The hook is only called + * from a context that may sleep. + * + * An implementation must fill its own member of @policy with a + * reference that remains valid until it is released through the + * policy_kptr_put hook, and must not assume anything about @fd beyond + * what its own userspace API created it with. + * + * Return: Returns 0 if @policy holds a reference counted policy + * object, -EOPNOTSUPP if the LSM does not implement the hook, negative + * values on other failures. + */ +int security_policy_kptr_from_fd(u64 lsmid, int fd, + union lsm_policy_kptr *policy) +{ + struct lsm_static_call *scall; + + lsm_for_each_hook(scall, policy_kptr_from_fd) { + if (scall->hl->lsmid->id != lsmid) + continue; + return scall->hl->hook.policy_kptr_from_fd(fd, policy); + } + return LSM_RET_DEFAULT(policy_kptr_from_fd); +} + /** * security_bpf_map_free() - Free a bpf map's LSM blob * @map: bpf map -- 2.54.0