* [PATCH] hornet: depend on CONFIG_SECURITY and CONFIG_BPF_SYSCALL
From: Paul Moore @ 2026-05-14 1:14 UTC (permalink / raw)
To: linux-security-module; +Cc: Blaise Boscaccy
Hornet only makes sense as a LSM if the LSM framework is enabled
via CONFIG_SECURITY and eBPF is enabled via CONFIG_BPF_SYSCALL.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202605140655.YX9jzufG-lkp@intel.com/
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/hornet/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/security/hornet/Kconfig b/security/hornet/Kconfig
index 5be71d97daee..537ad015958c 100644
--- a/security/hornet/Kconfig
+++ b/security/hornet/Kconfig
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config SECURITY_HORNET
bool "Hornet support"
+ depends on SECURITY && BPF_SYSCALL
select CRYPTO_LIB_SHA256
select PKCS7_MESSAGE_PARSER
select SYSTEM_DATA_VERIFICATION
--
2.54.0
^ permalink raw reply related
* Re: [linus:master] [landlock] 874c8f8382: kernel-selftests.landlock.audit_test.audit.thread.fail
From: Mickaël Salaün @ 2026-05-13 18:36 UTC (permalink / raw)
To: kernel test robot
Cc: oe-lkp, lkp, linux-kernel, Günther Noack, Jann Horn,
Günther Noack, linux-security-module
In-Reply-To: <202604300436.a07fae12-lkp@intel.com>
Should be fixed with
https://lore.kernel.org/all/20260513105112.140137-2-mic@digikod.net/
On Thu, Apr 30, 2026 at 10:51:07AM +0800, kernel test robot wrote:
>
>
> Hello,
>
> kernel test robot noticed "kernel-selftests.landlock.audit_test.audit.thread.fail" on:
>
> commit: 874c8f83826c95c62c21d9edfe9ef43e5c346724 ("landlock: Fix LOG_SUBDOMAINS_OFF inheritance across fork()")
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git master
>
> [test failed on linus/master dca922e019dd758b4c1b4bec8f1d509efddeaab4]
> [test failed on linux-next/master 9974969c14031a097d6b45bcb7a06bb4aa525c40]
>
> in testcase: kernel-selftests
> version: kernel-selftests-x86_64-9f2693489ef8-1_20260201
> with following parameters:
>
> group: landlock
>
>
>
> config: x86_64-rhel-9.4-kselftests
> compiler: gcc-14
> test machine: 16 threads Intel(R) Core(TM) i7-13620H (Raptor Lake) with 32G memory
>
> (please refer to attached dmesg/kmsg for entire log/backtrace)
>
>
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <oliver.sang@intel.com>
> | Closes: https://lore.kernel.org/oe-lkp/202604300436.a07fae12-lkp@intel.com
>
>
> # timeout set to 300
> # selftests: landlock: audit_test
> # TAP version 13
> # 1..12
> # # Starting 12 tests from 10 test cases.
> # # RUN audit.log_subdomains_off_fork ...
> # # OK audit.log_subdomains_off_fork
> # ok 1 audit.log_subdomains_off_fork
> # # RUN audit.thread ...
> # # audit_test.c:252:thread:Expected 0 (0) == matches_log_signal(_metadata, self->audit_fd, child_data.parent_pid, &denial_dom) (-11)
> # # audit_test.c:254:thread:Expected denial_dom (1) != 1 (1)
> # # audit_test.c:257:thread:Expected 0 (0) == matches_log_domain_allocated(self->audit_fd, getpid(), &allocated_dom) (-11)
> # # audit_test.c:259:thread:Expected denial_dom (1) == allocated_dom (2)
> # DATA: audit(1777390809.810:10): domain=1a323af0a status=allocated mode=enforcing pid=2437 uid=0 exe="/opt/rootfs/tmp/kselftests/landlock/landlock/audit_test" comm="audit_test"
> # ERROR: no match for pattern: ^audit([0-9.:]\+): domain=\([0-9a-f]\+\) status=deallocated denials=1$
> # # audit_test.c:275:thread:Expected 0 (0) == matches_log_domain_deallocated(self->audit_fd, 1, &deallocated_dom) (-2)
> # # audit_test.c:277:thread:Expected denial_dom (1) == deallocated_dom (0)
> # # thread: Test failed
> # # FAIL audit.thread
> # not ok 2 audit.thread
>
>
>
> The kernel config and materials to reproduce are available at:
> https://download.01.org/0day-ci/archive/20260430/202604300436.a07fae12-lkp@intel.com
>
>
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
>
>
^ permalink raw reply
* Re: [PATCH RFC 2/5] dma-heap: charge dma-buf memory via explicit memcg
From: Albert Esteve @ 2026-05-13 18:39 UTC (permalink / raw)
To: T.J. Mercier
Cc: Christian König, Tejun Heo, Johannes Weiner,
Michal Koutný, Jonathan Corbet, Shuah Khan, Sumit Semwal,
Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song,
Andrew Morton, Benjamin Gaignard, Brian Starkey, John Stultz,
Christian Brauner, Paul Moore, James Morris, Serge E. Hallyn,
Stephen Smalley, Ondrej Mosnacek, Shuah Khan, cgroups, linux-doc,
linux-kernel, linux-media, dri-devel, linaro-mm-sig, linux-mm,
linux-security-module, selinux, linux-kselftest, mripard,
echanude
In-Reply-To: <CABdmKX3R5faNgFva-HHVhtTcxJ0_BK9Rei3iTQcA+SRwdKv1Aw@mail.gmail.com>
On Wed, May 13, 2026 at 6:39 PM T.J. Mercier <tjmercier@google.com> wrote:
>
> On Wed, May 13, 2026 at 5:41 AM Albert Esteve <aesteve@redhat.com> wrote:
> >
> > On Tue, May 12, 2026 at 12:14 PM Christian König
> > <christian.koenig@amd.com> wrote:
> > >
> > > On 5/12/26 11:10, Albert Esteve wrote:
> > > > On embedded platforms a central process often allocates dma-buf
> > > > memory on behalf of client applications. Without a way to
> > > > attribute the charge to the requesting client's cgroup, the
> > > > cost lands on the allocator, making per-cgroup memory limits
> > > > ineffective for the actual consumers.
> > > >
> > > > Add charge_pid_fd to struct dma_heap_allocation_data. When set to
> > > > a valid pidfd, DMA_HEAP_IOCTL_ALLOC resolves the target task's
> > > > memcg and charges the buffer there via mem_cgroup_charge_dmabuf()
> > > > inside dma_heap_buffer_alloc(). Without charge_pid_fd, and with
> > > > the mem_accounting module parameter enabled, the buffer is charged
> > > > to the allocator's own cgroup.
> > > >
> > > > Additionally, commit 3c227be90659 ("dma-buf: system_heap: account for
> > > > system heap allocation in memcg") adds __GFP_ACCOUNT to system-heap
> > > > page allocations. Keeping __GFP_ACCOUNT would charge the same pages
> > > > twice (once to kmem, once to MEMCG_DMABUF), thus remove it and route
> > > > all accounting through a single MEMCG_DMABUF path.
> > > >
> > > > Usage examples:
> > > >
> > > > 1. Central allocator charging to a client at allocation time.
> > > > The allocator knows the client's PID (e.g., from binder's
> > > > sender_pid) and uses pidfd to attribute the charge:
> > > >
> > > > pid_t client_pid = txn->sender_pid;
> > > > int pidfd = pidfd_open(client_pid, 0);
> > > >
> > > > struct dma_heap_allocation_data alloc = {
> > > > .len = buffer_size,
> > > > .fd_flags = O_RDWR | O_CLOEXEC,
> > > > .charge_pid_fd = pidfd,
> > > > };
> > > > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > > > close(pidfd);
> > > > /* alloc.fd is now charged to client's cgroup */
> > > >
> > > > 2. Default allocation (no pidfd, mem_accounting=1).
> > > > When charge_pid_fd is not set and the mem_accounting module
> > > > parameter is enabled, the buffer is charged to the allocator's
> > > > own cgroup:
> > > >
> > > > struct dma_heap_allocation_data alloc = {
> > > > .len = buffer_size,
> > > > .fd_flags = O_RDWR | O_CLOEXEC,
> > > > };
> > > > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > > > /* charged to current process's cgroup */
> > > >
> > > > Current limitations:
> > > >
> > > > - Single-owner model: a dma-buf carries one memcg charge regardless of
> > > > how many processes share it. Means only the first owner (and exporter)
> > > > of the shared buffer bears the charge.
> > > > - Only memcg accounting supported. While this makes sense for system
> > > > heap buffers, other heaps (e.g., CMA heaps) will require selectively
> > > > charging also for the dmem controller.
> > >
> > > Well that doesn't looks soo bad, it at least seems to tackle the problem at hand for Android and some of other embedded use cases.
> > >
> > > I'm just not sure if this is future prove and will work for all use cases, e.g. cloud gaming, native context for automotive etc...
> > >
> > > Essentially the problem boils down to two limitations:
> > > 1) a piece of memory can only be charged to one cgroup, the framework doesn't has a concept of charging shared memory to multiple groups
> > > 2) when memory references in the form of file descriptors are passed between applications we have no way of changing the accounting to a different cgroup
> > >
> > > The passing of the memory reference already has a well defined uAPI and if we could solve those two limitations we not only solve the problem without introducing new uAPI (with potential new security risks) but also solve it for all other use cases which uses file descriptors as well as. E.g. memfd, accel and GPU drivers etc...
> >
> > Honestly, adding a hook to fd-passing uAPI to manage charge transfers
> > sounds like a promising solution requiring no uAPI changes. However,
> > it still does not cover all paths, e.g., dup() or fork(). And shared
> > memory sounds like a hard one to tackle, where deciding the best
> > policy is more a per-usecase thing and would probably require
> > userspace configuration.
>
> I'm curious if anyone knows of a use case where FDs aren't involved at
> all? It's possible to fork() or clone() with only a dmabuf mapping and
> no FD. That sounds strange, and I'm not sure there's a real usecase
> for transferring ownership with that approach, but figured I'd at
> least pose the question.
Yeah, that's a good point. I do not really have a usecase myself for
fork(), just thought of it as a posible gap/uncovered path.
>
> > All in all, charge_pid_fd covers a
> > well-defined and immediately practical subset. The UAPI cost is small
> > and the mechanism is explicit about what it does and doesn't solve. A
> > general solution, if it ever converges, would likely supersede
> > charge_pid_fd for most cases, which is a fine outcome if it solves the
> > problem more completely.
> >
> > Either way, if you have a specific approach in mind for solving any of
> > the above limitations, I'd be happy to look into it further.
> >
> > BR,
> > Albert.
> >
> > >
> > > On the other hand it is really nice to finally see this tackled for at least DMA-buf heaps. On the GPU side I have seen just another try of a driver doing some kind of special driver specific accounting to solve this just a few weeks ago. And to be honest such single driver island approach have the tendency to break more often that they are working correctly.
> > >
> > > Regards,
> > > Christian.
> > >
> > > >
> > > > Signed-off-by: Albert Esteve <aesteve@redhat.com>
> > > > ---
> > > > Documentation/admin-guide/cgroup-v2.rst | 5 ++--
> > > > drivers/dma-buf/dma-buf.c | 16 ++++---------
> > > > drivers/dma-buf/dma-heap.c | 42 ++++++++++++++++++++++++++++++---
> > > > drivers/dma-buf/heaps/system_heap.c | 2 --
> > > > include/uapi/linux/dma-heap.h | 6 +++++
> > > > 5 files changed, 53 insertions(+), 18 deletions(-)
> > > >
> > > > diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
> > > > index 8bdbc2e866430..824d269531eb1 100644
> > > > --- a/Documentation/admin-guide/cgroup-v2.rst
> > > > +++ b/Documentation/admin-guide/cgroup-v2.rst
> > > > @@ -1636,8 +1636,9 @@ The following nested keys are defined.
> > > > structures.
> > > >
> > > > dmabuf (npn)
> > > > - Amount of memory used for exported DMA buffers allocated by the cgroup.
> > > > - Stays with the allocating cgroup regardless of how the buffer is shared.
> > > > + Amount of memory used for exported DMA buffers allocated by or on
> > > > + behalf of the cgroup. Stays with the allocating cgroup regardless
> > > > + of how the buffer is shared.
> > > >
> > > > workingset_refault_anon
> > > > Number of refaults of previously evicted anonymous pages.
> > > > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> > > > index ce02377f48908..23fb758b78297 100644
> > > > --- a/drivers/dma-buf/dma-buf.c
> > > > +++ b/drivers/dma-buf/dma-buf.c
> > > > @@ -181,8 +181,11 @@ static void dma_buf_release(struct dentry *dentry)
> > > > */
> > > > BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
> > > >
> > > > - mem_cgroup_uncharge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > > > - mem_cgroup_put(dmabuf->memcg);
> > > > + if (dmabuf->memcg) {
> > > > + mem_cgroup_uncharge_dmabuf(dmabuf->memcg,
> > > > + PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > > > + mem_cgroup_put(dmabuf->memcg);
> > > > + }
> > > >
> > > > dmabuf->ops->release(dmabuf);
> > > >
> > > > @@ -764,13 +767,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> > > > dmabuf->resv = resv;
> > > > }
> > > >
> > > > - dmabuf->memcg = get_mem_cgroup_from_mm(current->mm);
> > > > - if (!mem_cgroup_charge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE,
> > > > - GFP_KERNEL)) {
> > > > - ret = -ENOMEM;
> > > > - goto err_memcg;
> > > > - }
> > > > -
> > > > file->private_data = dmabuf;
> > > > file->f_path.dentry->d_fsdata = dmabuf;
> > > > dmabuf->file = file;
> > > > @@ -781,8 +777,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> > > >
> > > > return dmabuf;
> > > >
> > > > -err_memcg:
> > > > - mem_cgroup_put(dmabuf->memcg);
> > > > err_file:
> > > > fput(file);
> > > > err_module:
> > > > diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
> > > > index ac5f8685a6494..ff6e259afcdc0 100644
> > > > --- a/drivers/dma-buf/dma-heap.c
> > > > +++ b/drivers/dma-buf/dma-heap.c
> > > > @@ -7,13 +7,17 @@
> > > > */
> > > >
> > > > #include <linux/cdev.h>
> > > > +#include <linux/cgroup.h>
> > > > #include <linux/device.h>
> > > > #include <linux/dma-buf.h>
> > > > #include <linux/dma-heap.h>
> > > > +#include <linux/memcontrol.h>
> > > > +#include <linux/sched/mm.h>
> > > > #include <linux/err.h>
> > > > #include <linux/export.h>
> > > > #include <linux/list.h>
> > > > #include <linux/nospec.h>
> > > > +#include <linux/pidfd.h>
> > > > #include <linux/syscalls.h>
> > > > #include <linux/uaccess.h>
> > > > #include <linux/xarray.h>
> > > > @@ -55,10 +59,12 @@ MODULE_PARM_DESC(mem_accounting,
> > > > "Enable cgroup-based memory accounting for dma-buf heap allocations (default=false).");
> > > >
> > > > static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > > > - u32 fd_flags,
> > > > - u64 heap_flags)
> > > > + u32 fd_flags, u64 heap_flags,
> > > > + struct mem_cgroup *charge_to)
> > > > {
> > > > struct dma_buf *dmabuf;
> > > > + unsigned int nr_pages;
> > > > + struct mem_cgroup *memcg = charge_to;
> > > > int fd;
> > > >
> > > > /*
> > > > @@ -73,6 +79,22 @@ static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > > > if (IS_ERR(dmabuf))
> > > > return PTR_ERR(dmabuf);
> > > >
> > > > + nr_pages = len / PAGE_SIZE;
> > > > +
> > > > + if (memcg)
> > > > + css_get(&memcg->css);
> > > > + else if (mem_accounting)
> > > > + memcg = get_mem_cgroup_from_mm(current->mm);
> > > > +
> > > > + if (memcg) {
> > > > + if (!mem_cgroup_charge_dmabuf(memcg, nr_pages, GFP_KERNEL)) {
> > > > + mem_cgroup_put(memcg);
> > > > + dma_buf_put(dmabuf);
> > > > + return -ENOMEM;
> > > > + }
> > > > + dmabuf->memcg = memcg;
> > > > + }
> > > > +
> > > > fd = dma_buf_fd(dmabuf, fd_flags);
> > > > if (fd < 0) {
> > > > dma_buf_put(dmabuf);
> > > > @@ -102,6 +124,9 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > > > {
> > > > struct dma_heap_allocation_data *heap_allocation = data;
> > > > struct dma_heap *heap = file->private_data;
> > > > + struct mem_cgroup *memcg = NULL;
> > > > + struct task_struct *task;
> > > > + unsigned int pidfd_flags;
> > > > int fd;
> > > >
> > > > if (heap_allocation->fd)
> > > > @@ -113,9 +138,20 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > > > if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS)
> > > > return -EINVAL;
> > > >
> > > > + if (heap_allocation->charge_pid_fd) {
> > > > + task = pidfd_get_task(heap_allocation->charge_pid_fd, &pidfd_flags);
> > > > + if (IS_ERR(task))
> > > > + return PTR_ERR(task);
> > > > +
> > > > + memcg = get_mem_cgroup_from_mm(task->mm);
> > > > + put_task_struct(task);
> > > > + }
> > > > +
> > > > fd = dma_heap_buffer_alloc(heap, heap_allocation->len,
> > > > heap_allocation->fd_flags,
> > > > - heap_allocation->heap_flags);
> > > > + heap_allocation->heap_flags,
> > > > + memcg);
> > > > + mem_cgroup_put(memcg);
> > > > if (fd < 0)
> > > > return fd;
> > > >
> > > > diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
> > > > index 03c2b87cb1112..95d7688167b93 100644
> > > > --- a/drivers/dma-buf/heaps/system_heap.c
> > > > +++ b/drivers/dma-buf/heaps/system_heap.c
> > > > @@ -385,8 +385,6 @@ static struct page *alloc_largest_available(unsigned long size,
> > > > if (max_order < orders[i])
> > > > continue;
> > > > flags = order_flags[i];
> > > > - if (mem_accounting)
> > > > - flags |= __GFP_ACCOUNT;
> > > > page = alloc_pages(flags, orders[i]);
> > > > if (!page)
> > > > continue;
> > > > diff --git a/include/uapi/linux/dma-heap.h b/include/uapi/linux/dma-heap.h
> > > > index a4cf716a49fa6..e02b0f8cbc6a1 100644
> > > > --- a/include/uapi/linux/dma-heap.h
> > > > +++ b/include/uapi/linux/dma-heap.h
> > > > @@ -29,6 +29,10 @@
> > > > * handle to the allocated dma-buf
> > > > * @fd_flags: file descriptor flags used when allocating
> > > > * @heap_flags: flags passed to heap
> > > > + * @charge_pid_fd: optional pidfd of the process whose cgroup should be
> > > > + * charged for this allocation; 0 means charge the calling
> > > > + * process's cgroup
> > > > + * @__padding: reserved, must be zero
> > > > *
> > > > * Provided by userspace as an argument to the ioctl
> > > > */
> > > > @@ -37,6 +41,8 @@ struct dma_heap_allocation_data {
> > > > __u32 fd;
> > > > __u32 fd_flags;
> > > > __u64 heap_flags;
> > > > + __u32 charge_pid_fd;
> > > > + __u32 __padding;
> > > > };
> > > >
> > > > #define DMA_HEAP_IOC_MAGIC 'H'
> > > >
> > >
> >
>
^ permalink raw reply
* Re: [PATCH v7 10/10] ipe: Add BPF program load policy enforcement via Hornet integration
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-11-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> Add support for the bpf_prog_load_post_integrity LSM hook, enabling IPE
> to make policy decisions about BPF program loading based on integrity
> verdicts provided by the Hornet LSM.
>
> New policy operation:
> op=BPF_PROG_LOAD - Matches BPF program load events
>
> New policy properties:
> bpf_signature=NONE - No Verdict
> bpf_signature=OK - Program signature and map hashes verified
> bpf_signature=UNSIGNED - No signature provided
> bpf_signature=PARTIALSIG - Signature OK but no map hash data
> bpf_signature=UNKNOWNKEY - The keyring requested by the user is invalid
> bpf_signature=UNEXPECTED - An unexpected hash value was encountered
> bpf_signature=FAULT - System error during verification
> bpf_signature=BADSIG - Signature or map hash verification failed
> bpf_keyring=BUILTIN - Program was signed using a builtin keyring
> bpf_keyring=SECONDARY - Program was signed using the secondary keyring
> bpf_keyring=PLATFORM - Program was signed using the platform keyring
> bpf_kernel=TRUE - Program originated from kernelspace
> bpf_kernel=FALSE - Program originated from userspace
>
> These properties map directly to the lsm_integrity_verdict enum values
> provided by the Hornet LSM through security_bpf_prog_load_post_integrity.
>
> The feature is gated on CONFIG_IPE_PROP_BPF_SIGNATURE which depends on
> CONFIG_SECURITY_HORNET.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> Acked-by: Fan Wu <wufan@kernel.org>
> ---
> Documentation/admin-guide/LSM/ipe.rst | 162 +++++++++++++++++++++++++-
> Documentation/security/ipe.rst | 68 +++++++++++
> security/ipe/Kconfig | 15 +++
> security/ipe/audit.c | 15 +++
> security/ipe/eval.c | 93 ++++++++++++++-
> security/ipe/eval.h | 11 ++
> security/ipe/hooks.c | 63 ++++++++++
> security/ipe/hooks.h | 15 +++
> security/ipe/ipe.c | 14 +++
> security/ipe/ipe.h | 3 +
> security/ipe/policy.h | 14 +++
> security/ipe/policy_parser.c | 27 +++++
> 12 files changed, 498 insertions(+), 2 deletions(-)
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 9/10] selftests/hornet: Add a selftest for the Hornet LSM
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-10-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> This selftest contains a testcase that utilizes light skeleton eBPF
> loaders and exercises hornet's map validation.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> ---
> tools/testing/selftests/Makefile | 1 +
> tools/testing/selftests/hornet/Makefile | 63 ++++++++++++++++++++
> tools/testing/selftests/hornet/loader.c | 21 +++++++
> tools/testing/selftests/hornet/trivial.bpf.c | 33 ++++++++++
> 4 files changed, 118 insertions(+)
> create mode 100644 tools/testing/selftests/hornet/Makefile
> create mode 100644 tools/testing/selftests/hornet/loader.c
> create mode 100644 tools/testing/selftests/hornet/trivial.bpf.c
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 8/10] hornet: Add a light skeleton data extractor scripts
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-9-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> These script eases light skeleton development against Hornet by
> generating a data payloads which can be used for signing a light
> skeleton binary using gen_sig.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> ---
> scripts/hornet/extract-insn.sh | 27 +++++++++++++++++++++++++++
> scripts/hornet/extract-map.sh | 27 +++++++++++++++++++++++++++
> scripts/hornet/extract-skel.sh | 27 +++++++++++++++++++++++++++
> 3 files changed, 81 insertions(+)
> create mode 100755 scripts/hornet/extract-insn.sh
> create mode 100755 scripts/hornet/extract-map.sh
> create mode 100755 scripts/hornet/extract-skel.sh
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 7/10] hornet: Introduce gen_sig
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-8-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> This introduces the gen_sig tool. It creates a pkcs#7 signature of a
> data payload. Additionally it appends a signed attribute containing a
> set of hashes.
>
> Typical usage is to provide a payload containing the light skeleton
> ebpf syscall program binary and it's associated maps, which can be
> extracted from the auto-generated skeleton header.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> ---
> scripts/Makefile | 1 +
> scripts/hornet/Makefile | 5 +
> scripts/hornet/gen_sig.c | 401 ++++++++++++++++++++++++++++++++++++
> scripts/hornet/write-sig.sh | 27 +++
> 4 files changed, 434 insertions(+)
> create mode 100644 scripts/hornet/Makefile
> create mode 100644 scripts/hornet/gen_sig.c
> create mode 100755 scripts/hornet/write-sig.sh
Merged into lsm/dev, but I did add a .gitignore for scripts/hornet/ and
I fixed up the SPDX tag (it wants C++ style comments).
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 6/10] security: Hornet LSM
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-7-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> This adds the Hornet Linux Security Module which provides enhanced
> signature verification and data validation for eBPF programs. This
> allows users to continue to maintain an invariant that all code
> running inside of the kernel has actually been signed and verified, by
> the kernel.
>
> This effort builds upon the currently excepted upstream solution. It
> further hardens it by providing deterministic, in-kernel checking of
> map hashes to solidify auditing along with preventing TOCTOU attacks
> against lskel map hashes.
>
> Target map hashes are passed in via PKCS#7 signed attributes. Hornet
> determines the extent which the eBFP program is signed and defers to
> other LSMs for policy decisions.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> Nacked-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
> ---
> Documentation/admin-guide/LSM/Hornet.rst | 323 +++++++++++++++++++++
> Documentation/admin-guide/LSM/index.rst | 1 +
> MAINTAINERS | 9 +
> include/linux/oid_registry.h | 3 +
> include/uapi/linux/lsm.h | 1 +
> security/Kconfig | 3 +-
> security/Makefile | 1 +
> security/hornet/Kconfig | 13 +
> security/hornet/Makefile | 7 +
> security/hornet/hornet.asn1 | 12 +
> security/hornet/hornet_lsm.c | 352 +++++++++++++++++++++++
> 11 files changed, 724 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/admin-guide/LSM/Hornet.rst
> create mode 100644 security/hornet/Kconfig
> create mode 100644 security/hornet/Makefile
> create mode 100644 security/hornet/hornet.asn1
> create mode 100644 security/hornet/hornet_lsm.c
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 5/10] lsm: security: Add additional enum values for bpf integrity checks
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-6-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> First add a generic LSM_INT_VERDICT_FAULT value to indicate a system
> failure during checking. Second, add a LSM_INT_VERDICT_UNKNOWNKEY to
> signal that the payload was signed with a key other than one that
> exists in the secondary keyring. And finally add an
> LSM_INT_VERDICT_UNEXPECTED enum value to indicate that a unexpected
> hash value was encountered at some stage of verification.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> ---
> include/linux/security.h | 3 +++
> 1 file changed, 3 insertions(+)
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 4/10] lsm: framework for BPF integrity verification
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-5-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> Add a new LSM hook and two new LSM hook callbacks to support LSMs that
> perform integrity verification, e.g. digital signature verification,
> of BPF programs.
>
> While the BPF subsystem does implement a signature verification scheme,
> it does not satisfy a number of existing requirements, adding support
> for BPF program integrity verification to the LSM framework allows
> administrators to select additional integrity verification mechanisms
> to meet these needs while also providing a mechanism for future
> expansion. Additional on why this is necessary can be found at the
> lore archive link below:
>
> https://lore.kernel.org/linux-security-module/CAHC9VhTQ_DR=ANzoDBjcCtrimV7XcCZVUsANPt=TjcvM4d-vjg@mail.gmail.com/
>
> The LSM-based BPF integrity verification mechanism works within the
> existing security_bpf_prog_load() hook called by the BPF subsystem.
> It adds an additional dedicated integrity callback and a new LSM
> hook/callback to be called from within LSMs implementing integrity
> verification.
>
> The first new callback, bpf_prog_load_integrity(), located within the
> security_bpf_prog_load() hook, is necessary to ensure that the integrity
> verification callbacks are executed before any of the existing LSMs
> are executed via the bpf_prog_load() callback. Reusing the existing
> bpf_prog_load() callback for integrity verification could result in LSMs
> not having access to the integrity verification results when asked to
> authorize the BPF program load in the bpf_prog_load() callback.
>
> The new LSM hook, security_bpf_prog_load_post_integrity(), is intended
> to be called from within LSMs performing BPF program integrity
> verification. It is used to report the verdict of the integrity
> verification to other LSMs enforcing access control policy on BPF
> program loads. LSMs enforcing such access controls should register a
> bpf_prog_load_post_integrity() callback to receive integrity verdicts.
>
> More information on these new callbacks and hook can be found in the
> code comments in this patch.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> Link: https://lore.kernel.org/linux-security-module/CAHC9VhTQ_DR=ANzoDBjcCtrimV7XcCZVUsANPt=TjcvM4d-vjg@mail.gmail.com/
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> include/linux/lsm_hook_defs.h | 5 +++
> include/linux/security.h | 25 ++++++++++++
> security/security.c | 75 +++++++++++++++++++++++++++++++++--
> 3 files changed, 102 insertions(+), 3 deletions(-)
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 3/10] crypto: pkcs7: add tests for pkcs7_get_authattr
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-4-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> Add example code to the test module pkcs7_key_type.c that verifies a
> message and then pulls out a known authenticated attribute.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> Acked-by: David Howells <dhowells@redhat.com>
> ---
> crypto/asymmetric_keys/pkcs7_key_type.c | 44 ++++++++++++++++++++++++-
> 1 file changed, 43 insertions(+), 1 deletion(-)
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 2/10] crypto: pkcs7: add ability to extract signed attributes by OID
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-3-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> Signers may add any information they like in signed attributes and
> sometimes this information turns out to be relevant to specific
> signing cases, so add an api pkcs7_get_authattr() to extract the value
> of an authenticated attribute by specific OID. The current
> implementation is designed for the single signer use case and simply
> terminates the search when it finds the relevant OID.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> ---
> crypto/asymmetric_keys/Makefile | 4 +-
> crypto/asymmetric_keys/pkcs7_aa.asn1 | 18 ++++++
> crypto/asymmetric_keys/pkcs7_parser.c | 81 +++++++++++++++++++++++++++
> include/crypto/pkcs7.h | 4 ++
> 4 files changed, 106 insertions(+), 1 deletion(-)
> create mode 100644 crypto/asymmetric_keys/pkcs7_aa.asn1
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH v7 1/10] crypto: pkcs7: add flag for validated trust on a signed info block
From: Paul Moore @ 2026-05-13 18:36 UTC (permalink / raw)
To: Blaise Boscaccy, Blaise Boscaccy, Jonathan Corbet, James Morris,
Serge E. Hallyn, Mickaël Salaün, Günther Noack,
Dr. David Alan Gilbert, Andrew Morton, James.Bottomley, dhowells,
Fan Wu, Ryan Foster, Randy Dunlap, linux-security-module,
linux-doc, linux-kernel, bpf, Song Liu
In-Reply-To: <20260507191416.2984054-2-bboscaccy@linux.microsoft.com>
On May 7, 2026 Blaise Boscaccy <bboscaccy@linux.microsoft.com> wrote:
>
> Allow consumers of struct pkcs7_message to tell if any of the sinfo
> fields has passed a trust validation. Note that this does not happen
> in parsing, pkcs7_validate_trust() must be explicitly called or called
> via validate_pkcs7_trust(). Since the way to get this trusted pkcs7
> object is via verify_pkcs7_message_sig, export that so modules can use
> it.
>
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> ---
> certs/system_keyring.c | 1 +
> crypto/asymmetric_keys/pkcs7_parser.h | 1 +
> crypto/asymmetric_keys/pkcs7_trust.c | 1 +
> 3 files changed, 3 insertions(+)
Merged into lsm/dev, thanks.
--
paul-moore.com
^ permalink raw reply
* [PATCH] lsm: hold cred_guard_mutex for lsm_set_self_attr()
From: Stephen Smalley @ 2026-05-13 18:05 UTC (permalink / raw)
To: selinux
Cc: paul, omosnace, casey, serge, john.johansen,
linux-security-module, Stephen Smalley
Just as proc_pid_attr_write() already does before calling the LSM
hook. This only matters for SELinux and AppArmor which check
whether the process is being ptraced and if so, whether to
allow the transition.
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
---
security/lsm_syscalls.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
index 5648b1f0ce9c..08a017669c02 100644
--- a/security/lsm_syscalls.c
+++ b/security/lsm_syscalls.c
@@ -57,7 +57,14 @@ u64 lsm_name_to_attr(const char *name)
SYSCALL_DEFINE4(lsm_set_self_attr, unsigned int, attr, struct lsm_ctx __user *,
ctx, u32, size, u32, flags)
{
- return security_setselfattr(attr, ctx, size, flags);
+ int rc;
+
+ rc = mutex_lock_interruptible(¤t->signal->cred_guard_mutex);
+ if (rc < 0)
+ return rc;
+ rc = security_setselfattr(attr, ctx, size, flags);
+ mutex_unlock(¤t->signal->cred_guard_mutex);
+ return rc;
}
/**
--
2.54.0
^ permalink raw reply related
* [PATCH v1] landlock: Account all audit data allocations to user space
From: Mickaël Salaün @ 2026-05-13 18:03 UTC (permalink / raw)
To: Günther Noack
Cc: Mickaël Salaün, linux-security-module, cgroups,
linux-mm, Paul Moore, stable
Mark the kzalloc_flex() of struct landlock_details with
GFP_KERNEL_ACCOUNT so the allocation is charged to the calling task,
like the other Landlock per-domain allocations which have used
GFP_KERNEL_ACCOUNT forever.
Every property of landlock_details is caller-attributable: allocated by
landlock_restrict_self(2), owned by the caller's landlock_hierarchy,
contents are the caller's pid, uid, comm, and exe_path, lifetime bounded
by the caller's domain. While the caller may not know nor control the
size of this allocation (i.e. exe_path), this data should still be
accounted for it.
The deciding factor is whether userspace can trigger the allocation, not
whether the size of the data is known nor controlled by the caller.
This aligns with the kmemcg accounting policy established by commit
5d097056c9a0 ("kmemcg: account certain kmem allocations to memcg").
No new failure modes: the hierarchy and ruleset are allocated before
details and are already accounted, so landlock_restrict_self(2) already
returns -ENOMEM under memcg pressure. This change widens that existing
failure window slightly; it does not introduce a new error code.
Cc: Günther Noack <gnoack@google.com>
Cc: Paul Moore <paul@paul-moore.com>
Cc: stable@vger.kernel.org
Fixes: 1d636984e088 ("landlock: Add AUDIT_LANDLOCK_DOMAIN and log domain status")
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---
security/landlock/domain.c | 9 +++++----
security/landlock/domain.h | 5 +----
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/security/landlock/domain.c b/security/landlock/domain.c
index 06b6bd845060..5dd06f7c2312 100644
--- a/security/landlock/domain.c
+++ b/security/landlock/domain.c
@@ -90,11 +90,12 @@ static struct landlock_details *get_current_details(void)
return ERR_CAST(buffer);
/*
- * Create the new details according to the path's length. Do not
- * allocate with GFP_KERNEL_ACCOUNT because it is independent from the
- * caller.
+ * Create the new details according to the path's length. Account
+ * to the calling task's memcg, like the other Landlock per-domain
+ * allocations, even if it may not control the related size.
*/
- details = kzalloc_flex(*details, exe_path, path_size);
+ details =
+ kzalloc_flex(*details, exe_path, path_size, GFP_KERNEL_ACCOUNT);
if (!details)
return ERR_PTR(-ENOMEM);
diff --git a/security/landlock/domain.h b/security/landlock/domain.h
index a9d57db0120d..35cac8f6daee 100644
--- a/security/landlock/domain.h
+++ b/security/landlock/domain.h
@@ -33,10 +33,7 @@ enum landlock_log_status {
* Rarely accessed, mainly when logging the first domain's denial.
*
* The contained pointers are initialized at the domain creation time and never
- * changed again. Contrary to most other Landlock object types, this one is
- * not allocated with GFP_KERNEL_ACCOUNT because its size may not be under the
- * caller's control (e.g. unknown exe_path) and the data is not explicitly
- * requested nor used by tasks.
+ * changed again.
*/
struct landlock_details {
/**
--
2.54.0
^ permalink raw reply related
* Re: [PATCH RFC 2/5] dma-heap: charge dma-buf memory via explicit memcg
From: T.J. Mercier @ 2026-05-13 16:39 UTC (permalink / raw)
To: Albert Esteve
Cc: Christian König, Tejun Heo, Johannes Weiner,
Michal Koutný, Jonathan Corbet, Shuah Khan, Sumit Semwal,
Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song,
Andrew Morton, Benjamin Gaignard, Brian Starkey, John Stultz,
Christian Brauner, Paul Moore, James Morris, Serge E. Hallyn,
Stephen Smalley, Ondrej Mosnacek, Shuah Khan, cgroups, linux-doc,
linux-kernel, linux-media, dri-devel, linaro-mm-sig, linux-mm,
linux-security-module, selinux, linux-kselftest, mripard,
echanude
In-Reply-To: <CADSE00KZMJFYJ92XZa=r9EeJJRGT=SNChwOW-_jTznc7F79xGw@mail.gmail.com>
On Wed, May 13, 2026 at 5:41 AM Albert Esteve <aesteve@redhat.com> wrote:
>
> On Tue, May 12, 2026 at 12:14 PM Christian König
> <christian.koenig@amd.com> wrote:
> >
> > On 5/12/26 11:10, Albert Esteve wrote:
> > > On embedded platforms a central process often allocates dma-buf
> > > memory on behalf of client applications. Without a way to
> > > attribute the charge to the requesting client's cgroup, the
> > > cost lands on the allocator, making per-cgroup memory limits
> > > ineffective for the actual consumers.
> > >
> > > Add charge_pid_fd to struct dma_heap_allocation_data. When set to
> > > a valid pidfd, DMA_HEAP_IOCTL_ALLOC resolves the target task's
> > > memcg and charges the buffer there via mem_cgroup_charge_dmabuf()
> > > inside dma_heap_buffer_alloc(). Without charge_pid_fd, and with
> > > the mem_accounting module parameter enabled, the buffer is charged
> > > to the allocator's own cgroup.
> > >
> > > Additionally, commit 3c227be90659 ("dma-buf: system_heap: account for
> > > system heap allocation in memcg") adds __GFP_ACCOUNT to system-heap
> > > page allocations. Keeping __GFP_ACCOUNT would charge the same pages
> > > twice (once to kmem, once to MEMCG_DMABUF), thus remove it and route
> > > all accounting through a single MEMCG_DMABUF path.
> > >
> > > Usage examples:
> > >
> > > 1. Central allocator charging to a client at allocation time.
> > > The allocator knows the client's PID (e.g., from binder's
> > > sender_pid) and uses pidfd to attribute the charge:
> > >
> > > pid_t client_pid = txn->sender_pid;
> > > int pidfd = pidfd_open(client_pid, 0);
> > >
> > > struct dma_heap_allocation_data alloc = {
> > > .len = buffer_size,
> > > .fd_flags = O_RDWR | O_CLOEXEC,
> > > .charge_pid_fd = pidfd,
> > > };
> > > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > > close(pidfd);
> > > /* alloc.fd is now charged to client's cgroup */
> > >
> > > 2. Default allocation (no pidfd, mem_accounting=1).
> > > When charge_pid_fd is not set and the mem_accounting module
> > > parameter is enabled, the buffer is charged to the allocator's
> > > own cgroup:
> > >
> > > struct dma_heap_allocation_data alloc = {
> > > .len = buffer_size,
> > > .fd_flags = O_RDWR | O_CLOEXEC,
> > > };
> > > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > > /* charged to current process's cgroup */
> > >
> > > Current limitations:
> > >
> > > - Single-owner model: a dma-buf carries one memcg charge regardless of
> > > how many processes share it. Means only the first owner (and exporter)
> > > of the shared buffer bears the charge.
> > > - Only memcg accounting supported. While this makes sense for system
> > > heap buffers, other heaps (e.g., CMA heaps) will require selectively
> > > charging also for the dmem controller.
> >
> > Well that doesn't looks soo bad, it at least seems to tackle the problem at hand for Android and some of other embedded use cases.
> >
> > I'm just not sure if this is future prove and will work for all use cases, e.g. cloud gaming, native context for automotive etc...
> >
> > Essentially the problem boils down to two limitations:
> > 1) a piece of memory can only be charged to one cgroup, the framework doesn't has a concept of charging shared memory to multiple groups
> > 2) when memory references in the form of file descriptors are passed between applications we have no way of changing the accounting to a different cgroup
> >
> > The passing of the memory reference already has a well defined uAPI and if we could solve those two limitations we not only solve the problem without introducing new uAPI (with potential new security risks) but also solve it for all other use cases which uses file descriptors as well as. E.g. memfd, accel and GPU drivers etc...
>
> Honestly, adding a hook to fd-passing uAPI to manage charge transfers
> sounds like a promising solution requiring no uAPI changes. However,
> it still does not cover all paths, e.g., dup() or fork(). And shared
> memory sounds like a hard one to tackle, where deciding the best
> policy is more a per-usecase thing and would probably require
> userspace configuration.
I'm curious if anyone knows of a use case where FDs aren't involved at
all? It's possible to fork() or clone() with only a dmabuf mapping and
no FD. That sounds strange, and I'm not sure there's a real usecase
for transferring ownership with that approach, but figured I'd at
least pose the question.
> All in all, charge_pid_fd covers a
> well-defined and immediately practical subset. The UAPI cost is small
> and the mechanism is explicit about what it does and doesn't solve. A
> general solution, if it ever converges, would likely supersede
> charge_pid_fd for most cases, which is a fine outcome if it solves the
> problem more completely.
>
> Either way, if you have a specific approach in mind for solving any of
> the above limitations, I'd be happy to look into it further.
>
> BR,
> Albert.
>
> >
> > On the other hand it is really nice to finally see this tackled for at least DMA-buf heaps. On the GPU side I have seen just another try of a driver doing some kind of special driver specific accounting to solve this just a few weeks ago. And to be honest such single driver island approach have the tendency to break more often that they are working correctly.
> >
> > Regards,
> > Christian.
> >
> > >
> > > Signed-off-by: Albert Esteve <aesteve@redhat.com>
> > > ---
> > > Documentation/admin-guide/cgroup-v2.rst | 5 ++--
> > > drivers/dma-buf/dma-buf.c | 16 ++++---------
> > > drivers/dma-buf/dma-heap.c | 42 ++++++++++++++++++++++++++++++---
> > > drivers/dma-buf/heaps/system_heap.c | 2 --
> > > include/uapi/linux/dma-heap.h | 6 +++++
> > > 5 files changed, 53 insertions(+), 18 deletions(-)
> > >
> > > diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
> > > index 8bdbc2e866430..824d269531eb1 100644
> > > --- a/Documentation/admin-guide/cgroup-v2.rst
> > > +++ b/Documentation/admin-guide/cgroup-v2.rst
> > > @@ -1636,8 +1636,9 @@ The following nested keys are defined.
> > > structures.
> > >
> > > dmabuf (npn)
> > > - Amount of memory used for exported DMA buffers allocated by the cgroup.
> > > - Stays with the allocating cgroup regardless of how the buffer is shared.
> > > + Amount of memory used for exported DMA buffers allocated by or on
> > > + behalf of the cgroup. Stays with the allocating cgroup regardless
> > > + of how the buffer is shared.
> > >
> > > workingset_refault_anon
> > > Number of refaults of previously evicted anonymous pages.
> > > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> > > index ce02377f48908..23fb758b78297 100644
> > > --- a/drivers/dma-buf/dma-buf.c
> > > +++ b/drivers/dma-buf/dma-buf.c
> > > @@ -181,8 +181,11 @@ static void dma_buf_release(struct dentry *dentry)
> > > */
> > > BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
> > >
> > > - mem_cgroup_uncharge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > > - mem_cgroup_put(dmabuf->memcg);
> > > + if (dmabuf->memcg) {
> > > + mem_cgroup_uncharge_dmabuf(dmabuf->memcg,
> > > + PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > > + mem_cgroup_put(dmabuf->memcg);
> > > + }
> > >
> > > dmabuf->ops->release(dmabuf);
> > >
> > > @@ -764,13 +767,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> > > dmabuf->resv = resv;
> > > }
> > >
> > > - dmabuf->memcg = get_mem_cgroup_from_mm(current->mm);
> > > - if (!mem_cgroup_charge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE,
> > > - GFP_KERNEL)) {
> > > - ret = -ENOMEM;
> > > - goto err_memcg;
> > > - }
> > > -
> > > file->private_data = dmabuf;
> > > file->f_path.dentry->d_fsdata = dmabuf;
> > > dmabuf->file = file;
> > > @@ -781,8 +777,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> > >
> > > return dmabuf;
> > >
> > > -err_memcg:
> > > - mem_cgroup_put(dmabuf->memcg);
> > > err_file:
> > > fput(file);
> > > err_module:
> > > diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
> > > index ac5f8685a6494..ff6e259afcdc0 100644
> > > --- a/drivers/dma-buf/dma-heap.c
> > > +++ b/drivers/dma-buf/dma-heap.c
> > > @@ -7,13 +7,17 @@
> > > */
> > >
> > > #include <linux/cdev.h>
> > > +#include <linux/cgroup.h>
> > > #include <linux/device.h>
> > > #include <linux/dma-buf.h>
> > > #include <linux/dma-heap.h>
> > > +#include <linux/memcontrol.h>
> > > +#include <linux/sched/mm.h>
> > > #include <linux/err.h>
> > > #include <linux/export.h>
> > > #include <linux/list.h>
> > > #include <linux/nospec.h>
> > > +#include <linux/pidfd.h>
> > > #include <linux/syscalls.h>
> > > #include <linux/uaccess.h>
> > > #include <linux/xarray.h>
> > > @@ -55,10 +59,12 @@ MODULE_PARM_DESC(mem_accounting,
> > > "Enable cgroup-based memory accounting for dma-buf heap allocations (default=false).");
> > >
> > > static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > > - u32 fd_flags,
> > > - u64 heap_flags)
> > > + u32 fd_flags, u64 heap_flags,
> > > + struct mem_cgroup *charge_to)
> > > {
> > > struct dma_buf *dmabuf;
> > > + unsigned int nr_pages;
> > > + struct mem_cgroup *memcg = charge_to;
> > > int fd;
> > >
> > > /*
> > > @@ -73,6 +79,22 @@ static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > > if (IS_ERR(dmabuf))
> > > return PTR_ERR(dmabuf);
> > >
> > > + nr_pages = len / PAGE_SIZE;
> > > +
> > > + if (memcg)
> > > + css_get(&memcg->css);
> > > + else if (mem_accounting)
> > > + memcg = get_mem_cgroup_from_mm(current->mm);
> > > +
> > > + if (memcg) {
> > > + if (!mem_cgroup_charge_dmabuf(memcg, nr_pages, GFP_KERNEL)) {
> > > + mem_cgroup_put(memcg);
> > > + dma_buf_put(dmabuf);
> > > + return -ENOMEM;
> > > + }
> > > + dmabuf->memcg = memcg;
> > > + }
> > > +
> > > fd = dma_buf_fd(dmabuf, fd_flags);
> > > if (fd < 0) {
> > > dma_buf_put(dmabuf);
> > > @@ -102,6 +124,9 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > > {
> > > struct dma_heap_allocation_data *heap_allocation = data;
> > > struct dma_heap *heap = file->private_data;
> > > + struct mem_cgroup *memcg = NULL;
> > > + struct task_struct *task;
> > > + unsigned int pidfd_flags;
> > > int fd;
> > >
> > > if (heap_allocation->fd)
> > > @@ -113,9 +138,20 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > > if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS)
> > > return -EINVAL;
> > >
> > > + if (heap_allocation->charge_pid_fd) {
> > > + task = pidfd_get_task(heap_allocation->charge_pid_fd, &pidfd_flags);
> > > + if (IS_ERR(task))
> > > + return PTR_ERR(task);
> > > +
> > > + memcg = get_mem_cgroup_from_mm(task->mm);
> > > + put_task_struct(task);
> > > + }
> > > +
> > > fd = dma_heap_buffer_alloc(heap, heap_allocation->len,
> > > heap_allocation->fd_flags,
> > > - heap_allocation->heap_flags);
> > > + heap_allocation->heap_flags,
> > > + memcg);
> > > + mem_cgroup_put(memcg);
> > > if (fd < 0)
> > > return fd;
> > >
> > > diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
> > > index 03c2b87cb1112..95d7688167b93 100644
> > > --- a/drivers/dma-buf/heaps/system_heap.c
> > > +++ b/drivers/dma-buf/heaps/system_heap.c
> > > @@ -385,8 +385,6 @@ static struct page *alloc_largest_available(unsigned long size,
> > > if (max_order < orders[i])
> > > continue;
> > > flags = order_flags[i];
> > > - if (mem_accounting)
> > > - flags |= __GFP_ACCOUNT;
> > > page = alloc_pages(flags, orders[i]);
> > > if (!page)
> > > continue;
> > > diff --git a/include/uapi/linux/dma-heap.h b/include/uapi/linux/dma-heap.h
> > > index a4cf716a49fa6..e02b0f8cbc6a1 100644
> > > --- a/include/uapi/linux/dma-heap.h
> > > +++ b/include/uapi/linux/dma-heap.h
> > > @@ -29,6 +29,10 @@
> > > * handle to the allocated dma-buf
> > > * @fd_flags: file descriptor flags used when allocating
> > > * @heap_flags: flags passed to heap
> > > + * @charge_pid_fd: optional pidfd of the process whose cgroup should be
> > > + * charged for this allocation; 0 means charge the calling
> > > + * process's cgroup
> > > + * @__padding: reserved, must be zero
> > > *
> > > * Provided by userspace as an argument to the ioctl
> > > */
> > > @@ -37,6 +41,8 @@ struct dma_heap_allocation_data {
> > > __u32 fd;
> > > __u32 fd_flags;
> > > __u64 heap_flags;
> > > + __u32 charge_pid_fd;
> > > + __u32 __padding;
> > > };
> > >
> > > #define DMA_HEAP_IOC_MAGIC 'H'
> > >
> >
>
^ permalink raw reply
* Re: [PATCH RFC 2/5] dma-heap: charge dma-buf memory via explicit memcg
From: T.J. Mercier @ 2026-05-13 16:35 UTC (permalink / raw)
To: Albert Esteve
Cc: Christian König, Tejun Heo, Johannes Weiner,
Michal Koutný, Jonathan Corbet, Shuah Khan, Sumit Semwal,
Michal Hocko, Roman Gushchin, Shakeel Butt, Muchun Song,
Andrew Morton, Benjamin Gaignard, Brian Starkey, John Stultz,
Christian Brauner, Paul Moore, James Morris, Serge E. Hallyn,
Stephen Smalley, Ondrej Mosnacek, Shuah Khan, cgroups, linux-doc,
linux-kernel, linux-media, dri-devel, linaro-mm-sig, linux-mm,
linux-security-module, selinux, linux-kselftest, mripard,
echanude
In-Reply-To: <CADSE00Jq_uvNgvxgPze0mEdUd+hF4-DPZkHy0KroWHZzygf4WA@mail.gmail.com>
On Wed, May 13, 2026 at 4:39 AM Albert Esteve <aesteve@redhat.com> wrote:
>
> On Tue, May 12, 2026 at 8:53 PM T.J. Mercier <tjmercier@google.com> wrote:
> >
> > On Tue, May 12, 2026 at 3:14 AM Christian König
> > <christian.koenig@amd.com> wrote:
> > >
> > > On 5/12/26 11:10, Albert Esteve wrote:
> > > > On embedded platforms a central process often allocates dma-buf
> > > > memory on behalf of client applications. Without a way to
> > > > attribute the charge to the requesting client's cgroup, the
> > > > cost lands on the allocator, making per-cgroup memory limits
> > > > ineffective for the actual consumers.
> > > >
> > > > Add charge_pid_fd to struct dma_heap_allocation_data. When set to
> > > > a valid pidfd, DMA_HEAP_IOCTL_ALLOC resolves the target task's
> > > > memcg and charges the buffer there via mem_cgroup_charge_dmabuf()
> > > > inside dma_heap_buffer_alloc(). Without charge_pid_fd, and with
> > > > the mem_accounting module parameter enabled, the buffer is charged
> > > > to the allocator's own cgroup.
> > > >
> > > > Additionally, commit 3c227be90659 ("dma-buf: system_heap: account for
> > > > system heap allocation in memcg") adds __GFP_ACCOUNT to system-heap
> > > > page allocations. Keeping __GFP_ACCOUNT would charge the same pages
> > > > twice (once to kmem, once to MEMCG_DMABUF), thus remove it and route
> > > > all accounting through a single MEMCG_DMABUF path.
> > > >
> > > > Usage examples:
> > > >
> > > > 1. Central allocator charging to a client at allocation time.
> > > > The allocator knows the client's PID (e.g., from binder's
> > > > sender_pid) and uses pidfd to attribute the charge:
> > > >
> > > > pid_t client_pid = txn->sender_pid;
> > > > int pidfd = pidfd_open(client_pid, 0);
> > > >
> > > > struct dma_heap_allocation_data alloc = {
> > > > .len = buffer_size,
> > > > .fd_flags = O_RDWR | O_CLOEXEC,
> > > > .charge_pid_fd = pidfd,
> > > > };
> > > > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > > > close(pidfd);
> > > > /* alloc.fd is now charged to client's cgroup */
> > > >
> > > > 2. Default allocation (no pidfd, mem_accounting=1).
> > > > When charge_pid_fd is not set and the mem_accounting module
> > > > parameter is enabled, the buffer is charged to the allocator's
> > > > own cgroup:
> > > >
> > > > struct dma_heap_allocation_data alloc = {
> > > > .len = buffer_size,
> > > > .fd_flags = O_RDWR | O_CLOEXEC,
> > > > };
> > > > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > > > /* charged to current process's cgroup */
> > > >
> > > > Current limitations:
> > > >
> > > > - Single-owner model: a dma-buf carries one memcg charge regardless of
> > > > how many processes share it. Means only the first owner (and exporter)
> > > > of the shared buffer bears the charge.
> > > > - Only memcg accounting supported. While this makes sense for system
> > > > heap buffers, other heaps (e.g., CMA heaps) will require selectively
> > > > charging also for the dmem controller.
> > >
> > > Well that doesn't looks soo bad, it at least seems to tackle the problem at hand for Android and some of other embedded use cases.
> >
> > Yeah I think this might work. I know of 3 cases, and it trivially
> > solves the first two. The third requires some work on our end to
> > extend our userspace interfaces to include the pidfd but it seems
> > doable. I'm checking with our graphics folks.
> >
> > 1) Direct allocation from user (e.g. app -> allocation ioctl on
> > /dev/dma_heap/foo)
> > No changes required to userspace. mem_accounting=1 charges the app.
> >
> > 2) Single hop remote allocation (e.g. app -> AHardwareBuffer_allocate
> > -> gralloc)
> > gralloc has the caller's pid as described in the commit message. Open
> > a pidfd and pass it in the dma_heap_allocation_data.
> >
> > 3) Double hop remote allocation (e.g. app -> dequeueBuffer ->
> > SurfaceFlinger -> gralloc)
> > In this case gralloc knows SurfaceFlinger's pid, but not the app's. So
> > we need to add the app's pidfd to the SurfaceFlinger -> gralloc
> > interface, or transfer the memcg charge from SurfaceFlinger to the app
> > after the allocation.
> > It'd be nice to avoid the charge transfer option entirely, but if we
> > need it that doesn't seem so bad in this case because it's a bulk
> > charge for the entire dmabuf rather than per-page. So the exporter
> > doesn't need to get involved (we wouldn't need a new dma_buf_op) and
> > we wouldn't have to worry about looping and locking for each page.
> >
> > > I'm just not sure if this is future prove and will work for all use cases, e.g. cloud gaming, native context for automotive etc...
> > >
> > > Essentially the problem boils down to two limitations:
> > > 1) a piece of memory can only be charged to one cgroup, the framework doesn't has a concept of charging shared memory to multiple groups
> >
> > Yup, memcg already has this problem with pagecache and shmem.
> >
> > > 2) when memory references in the form of file descriptors are passed between applications we have no way of changing the accounting to a different cgroup
> > >
> > > The passing of the memory reference already has a well defined uAPI and if we could solve those two limitations we not only solve the problem without introducing new uAPI (with potential new security risks) but also solve it for all other use cases which uses file descriptors as well as. E.g. memfd, accel and GPU drivers etc...
> > >
> > > On the other hand it is really nice to finally see this tackled for at least DMA-buf heaps.
> >
> > I have a question about this part. Albert I guess you are interested
> > only in accounting dmabuf-heap allocations, or do you expect to add
> > __GFP_ACCOUNT or mem_cgroup_charge_dmabuf calls to other
> > non-dmabuf-heap exporters?
>
> We're scoping this to dma-buf heaps for now. CMA heaps and the dmem
> controller are on the radar for follow-up/parallel work (there will be
> dragons and will surely need discussion). For DRM and V4L2 the
> long-term intent is migration to heaps, which would make direct
> accounting on those paths unnecessary.
Ah I see. GEM buffers exported to dmabufs are what I had in mind. I
guess this would only leave the odd non-DRM driver with the need to
add their own accounting calls, which I don't expect would be a big
problem.
> udmabufs are already
> memcg-charged, so adding a separate MEMCG_DMABUF would double count.
> Are there any other exporters you had in mind that would benefit from
> this approach?
>
> BR,
> Albert.
>
> >
> > > On the GPU side I have seen just another try of a driver doing some kind of special driver specific accounting to solve this just a few weeks ago. And to be honest such single driver island approach have the tendency to break more often that they are working correctly.
> > >
> > > Regards,
> > > Christian.
> > >
> > > >
> > > > Signed-off-by: Albert Esteve <aesteve@redhat.com>
> > > > ---
> > > > Documentation/admin-guide/cgroup-v2.rst | 5 ++--
> > > > drivers/dma-buf/dma-buf.c | 16 ++++---------
> > > > drivers/dma-buf/dma-heap.c | 42 ++++++++++++++++++++++++++++++---
> > > > drivers/dma-buf/heaps/system_heap.c | 2 --
> > > > include/uapi/linux/dma-heap.h | 6 +++++
> > > > 5 files changed, 53 insertions(+), 18 deletions(-)
> > > >
> > > > diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
> > > > index 8bdbc2e866430..824d269531eb1 100644
> > > > --- a/Documentation/admin-guide/cgroup-v2.rst
> > > > +++ b/Documentation/admin-guide/cgroup-v2.rst
> > > > @@ -1636,8 +1636,9 @@ The following nested keys are defined.
> > > > structures.
> > > >
> > > > dmabuf (npn)
> > > > - Amount of memory used for exported DMA buffers allocated by the cgroup.
> > > > - Stays with the allocating cgroup regardless of how the buffer is shared.
> > > > + Amount of memory used for exported DMA buffers allocated by or on
> > > > + behalf of the cgroup. Stays with the allocating cgroup regardless
> > > > + of how the buffer is shared.
> > > >
> > > > workingset_refault_anon
> > > > Number of refaults of previously evicted anonymous pages.
> > > > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> > > > index ce02377f48908..23fb758b78297 100644
> > > > --- a/drivers/dma-buf/dma-buf.c
> > > > +++ b/drivers/dma-buf/dma-buf.c
> > > > @@ -181,8 +181,11 @@ static void dma_buf_release(struct dentry *dentry)
> > > > */
> > > > BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
> > > >
> > > > - mem_cgroup_uncharge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > > > - mem_cgroup_put(dmabuf->memcg);
> > > > + if (dmabuf->memcg) {
> > > > + mem_cgroup_uncharge_dmabuf(dmabuf->memcg,
> > > > + PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > > > + mem_cgroup_put(dmabuf->memcg);
> > > > + }
> > > >
> > > > dmabuf->ops->release(dmabuf);
> > > >
> > > > @@ -764,13 +767,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> > > > dmabuf->resv = resv;
> > > > }
> > > >
> > > > - dmabuf->memcg = get_mem_cgroup_from_mm(current->mm);
> > > > - if (!mem_cgroup_charge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE,
> > > > - GFP_KERNEL)) {
> > > > - ret = -ENOMEM;
> > > > - goto err_memcg;
> > > > - }
> > > > -
> > > > file->private_data = dmabuf;
> > > > file->f_path.dentry->d_fsdata = dmabuf;
> > > > dmabuf->file = file;
> > > > @@ -781,8 +777,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> > > >
> > > > return dmabuf;
> > > >
> > > > -err_memcg:
> > > > - mem_cgroup_put(dmabuf->memcg);
> > > > err_file:
> > > > fput(file);
> > > > err_module:
> > > > diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
> > > > index ac5f8685a6494..ff6e259afcdc0 100644
> > > > --- a/drivers/dma-buf/dma-heap.c
> > > > +++ b/drivers/dma-buf/dma-heap.c
> > > > @@ -7,13 +7,17 @@
> > > > */
> > > >
> > > > #include <linux/cdev.h>
> > > > +#include <linux/cgroup.h>
> > > > #include <linux/device.h>
> > > > #include <linux/dma-buf.h>
> > > > #include <linux/dma-heap.h>
> > > > +#include <linux/memcontrol.h>
> > > > +#include <linux/sched/mm.h>
> > > > #include <linux/err.h>
> > > > #include <linux/export.h>
> > > > #include <linux/list.h>
> > > > #include <linux/nospec.h>
> > > > +#include <linux/pidfd.h>
> > > > #include <linux/syscalls.h>
> > > > #include <linux/uaccess.h>
> > > > #include <linux/xarray.h>
> > > > @@ -55,10 +59,12 @@ MODULE_PARM_DESC(mem_accounting,
> > > > "Enable cgroup-based memory accounting for dma-buf heap allocations (default=false).");
> > > >
> > > > static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > > > - u32 fd_flags,
> > > > - u64 heap_flags)
> > > > + u32 fd_flags, u64 heap_flags,
> > > > + struct mem_cgroup *charge_to)
> > > > {
> > > > struct dma_buf *dmabuf;
> > > > + unsigned int nr_pages;
> > > > + struct mem_cgroup *memcg = charge_to;
> > > > int fd;
> > > >
> > > > /*
> > > > @@ -73,6 +79,22 @@ static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > > > if (IS_ERR(dmabuf))
> > > > return PTR_ERR(dmabuf);
> > > >
> > > > + nr_pages = len / PAGE_SIZE;
> > > > +
> > > > + if (memcg)
> > > > + css_get(&memcg->css);
> > > > + else if (mem_accounting)
> > > > + memcg = get_mem_cgroup_from_mm(current->mm);
> > > > +
> > > > + if (memcg) {
> > > > + if (!mem_cgroup_charge_dmabuf(memcg, nr_pages, GFP_KERNEL)) {
> > > > + mem_cgroup_put(memcg);
> > > > + dma_buf_put(dmabuf);
> > > > + return -ENOMEM;
> > > > + }
> > > > + dmabuf->memcg = memcg;
> > > > + }
> > > > +
> > > > fd = dma_buf_fd(dmabuf, fd_flags);
> > > > if (fd < 0) {
> > > > dma_buf_put(dmabuf);
> > > > @@ -102,6 +124,9 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > > > {
> > > > struct dma_heap_allocation_data *heap_allocation = data;
> > > > struct dma_heap *heap = file->private_data;
> > > > + struct mem_cgroup *memcg = NULL;
> > > > + struct task_struct *task;
> > > > + unsigned int pidfd_flags;
> > > > int fd;
> > > >
> > > > if (heap_allocation->fd)
> > > > @@ -113,9 +138,20 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > > > if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS)
> > > > return -EINVAL;
> > > >
> > > > + if (heap_allocation->charge_pid_fd) {
> > > > + task = pidfd_get_task(heap_allocation->charge_pid_fd, &pidfd_flags);
> > > > + if (IS_ERR(task))
> > > > + return PTR_ERR(task);
> > > > +
> > > > + memcg = get_mem_cgroup_from_mm(task->mm);
> > > > + put_task_struct(task);
> > > > + }
> > > > +
> > > > fd = dma_heap_buffer_alloc(heap, heap_allocation->len,
> > > > heap_allocation->fd_flags,
> > > > - heap_allocation->heap_flags);
> > > > + heap_allocation->heap_flags,
> > > > + memcg);
> > > > + mem_cgroup_put(memcg);
> > > > if (fd < 0)
> > > > return fd;
> > > >
> > > > diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
> > > > index 03c2b87cb1112..95d7688167b93 100644
> > > > --- a/drivers/dma-buf/heaps/system_heap.c
> > > > +++ b/drivers/dma-buf/heaps/system_heap.c
> > > > @@ -385,8 +385,6 @@ static struct page *alloc_largest_available(unsigned long size,
> > > > if (max_order < orders[i])
> > > > continue;
> > > > flags = order_flags[i];
> > > > - if (mem_accounting)
> > > > - flags |= __GFP_ACCOUNT;
> > > > page = alloc_pages(flags, orders[i]);
> > > > if (!page)
> > > > continue;
> > > > diff --git a/include/uapi/linux/dma-heap.h b/include/uapi/linux/dma-heap.h
> > > > index a4cf716a49fa6..e02b0f8cbc6a1 100644
> > > > --- a/include/uapi/linux/dma-heap.h
> > > > +++ b/include/uapi/linux/dma-heap.h
> > > > @@ -29,6 +29,10 @@
> > > > * handle to the allocated dma-buf
> > > > * @fd_flags: file descriptor flags used when allocating
> > > > * @heap_flags: flags passed to heap
> > > > + * @charge_pid_fd: optional pidfd of the process whose cgroup should be
> > > > + * charged for this allocation; 0 means charge the calling
> > > > + * process's cgroup
> > > > + * @__padding: reserved, must be zero
> > > > *
> > > > * Provided by userspace as an argument to the ioctl
> > > > */
> > > > @@ -37,6 +41,8 @@ struct dma_heap_allocation_data {
> > > > __u32 fd;
> > > > __u32 fd_flags;
> > > > __u64 heap_flags;
> > > > + __u32 charge_pid_fd;
> > > > + __u32 __padding;
> > > > };
> > > >
> > > > #define DMA_HEAP_IOC_MAGIC 'H'
> > > >
> > >
> >
>
^ permalink raw reply
* [PATCH v2 3/3] selftests/landlock: Test OverlayFS renames w/o LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
In-Reply-To: <20260513160552.4022649-1-gnoack@google.com>
Even though OverlayFS uses vfs_rename() with RENAME_WHITEOUT, and even
though RENAME_WHITEOUT requires LANDLOCK_ACCESS_FS_MAKE_WHITEOUT, a process
that renames files in an OverlayFS can do so without having the
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT right in that location.
This works, and is supposed to work, because OverlayFS uses the credentials
determined at mount time for the internal vfs_rename() operation. -- The
rename happens with the credentials of the user who mounted the OverlayFS.
Signed-off-by: Günther Noack <gnoack@google.com>
---
tools/testing/selftests/landlock/fs_test.c | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index bdad92195f62..0c29887278d0 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -6963,6 +6963,37 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
}
}
+TEST_F_FORK(layout2_overlay, rename_in_overlay_without_make_whiteout)
+{
+ struct stat st;
+ const char *merge_fl1_renamed = MERGE_DATA "/fl1_renamed";
+
+ if (self->skip_test)
+ SKIP(return, "overlayfs is not supported (test)");
+
+ enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_WHITEOUT, NULL);
+
+ /*
+ * Execute a regular file rename within OverlayFS.
+ * merge_fl1 originates from lower layer, so this triggers a copy-up
+ * and creation of a whiteout in the upper layer.
+ */
+ EXPECT_EQ(0, rename(merge_fl1, merge_fl1_renamed));
+
+ /* Check that the rename worked. */
+ EXPECT_EQ(0, stat(merge_fl1_renamed, &st));
+ EXPECT_EQ(-1, stat(merge_fl1, &st));
+ EXPECT_EQ(ENOENT, errno);
+
+ /*
+ * Check that the whiteout object on the underlying "upper" filesystem
+ * exists after the rename. This is OK because it was done with the
+ * credentials of the OverlayFS.
+ */
+ EXPECT_EQ(0, stat(UPPER_DATA "/fl1", &st));
+ EXPECT_TRUE(S_ISCHR(st.st_mode));
+ EXPECT_EQ(0, st.st_rdev);
+}
FIXTURE(layout3_fs)
{
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v2 2/3] selftests/landlock: Add test for RENAME_WHITEOUT denial
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
In-Reply-To: <20260513160552.4022649-1-gnoack@google.com>
Add a test to check that renames with RENAME_WHITEOUT are guarded by
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT.
Signed-off-by: Günther Noack <gnoack@google.com>
---
tools/testing/selftests/landlock/fs_test.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 53d1b659849f..bdad92195f62 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -2248,6 +2248,19 @@ TEST_F_FORK(layout1, rename_file)
RENAME_EXCHANGE));
}
+TEST_F_FORK(layout1, rename_whiteout_denied)
+{
+ enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_WHITEOUT, NULL);
+
+ /*
+ * Try to rename a file with RENAME_WHITEOUT.
+ * file1_s3d3 is in dir_s3d2 (tmpfs), so it supports RENAME_WHITEOUT.
+ */
+ EXPECT_EQ(-1, renameat2(AT_FDCWD, file1_s3d3, AT_FDCWD,
+ TMP_DIR "/s3d1/s3d2/s3d3/f2", RENAME_WHITEOUT));
+ EXPECT_EQ(EACCES, errno);
+}
+
TEST_F_FORK(layout1, rename_dir)
{
const struct rule rules[] = {
@@ -6950,6 +6963,7 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
}
}
+
FIXTURE(layout3_fs)
{
bool has_created_dir;
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v2 1/3] landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
In-Reply-To: <20260513160552.4022649-1-gnoack@google.com>
renameat2(2) with the RENAME_WHITEOUT flag places a whiteout character
device file in the source file location in place of the moved file.
This creates a directory entry even in cases where all
LANDLOCK_ACCESS_FS_MAKE_* rights are denied.
Introduce the LANDLOCK_ACCESS_FS_MAKE_WHITEOUT right, which is checked
for the origin directory if RENAME_WHITEOUT is passed.
This does not affect normal renames within layered OverlayFS mounts:
When OverlayFS invokes rename with RENAME_WHITEOUT as part of a
"normal" rename operation, it does so in ovl_rename() using the
credentials that were set at the time of mounting the OverlayFS.
Bump the Landlock ABI version to 10.
Suggested-by: Christian Brauner <brauner@kernel.org>
Suggested-by: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Günther Noack <gnoack@google.com>
---
include/uapi/linux/landlock.h | 3 +++
security/landlock/audit.c | 1 +
security/landlock/fs.c | 15 +++++++++++++++
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
tools/testing/selftests/landlock/base_test.c | 4 ++--
tools/testing/selftests/landlock/fs_test.c | 5 +++--
7 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 10a346e55e95..1f8a1d6d25f1 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -328,6 +328,8 @@ struct landlock_net_port_attr {
*
* If multiple requirements are not met, the ``EACCES`` error code takes
* precedence over ``EXDEV``.
+ * - %LANDLOCK_ACCESS_FS_MAKE_WHITEOUT: Create a whiteout object through
+ * :manpage:`rename(2)` with ``RENAME_WHITEOUT``.
*
* .. warning::
*
@@ -356,6 +358,7 @@ struct landlock_net_port_attr {
#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
#define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15)
#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX (1ULL << 16)
+#define LANDLOCK_ACCESS_FS_MAKE_WHITEOUT (1ULL << 17)
/* clang-format on */
/**
diff --git a/security/landlock/audit.c b/security/landlock/audit.c
index 8d0edf94037d..09c97083f599 100644
--- a/security/landlock/audit.c
+++ b/security/landlock/audit.c
@@ -38,6 +38,7 @@ static const char *const fs_access_strings[] = {
[BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
[BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix",
+ [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_WHITEOUT)] = "fs.make_whiteout",
};
static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index c1ecfe239032..09de6ba5c3a3 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1519,6 +1519,21 @@ static int hook_path_rename(const struct path *const old_dir,
const unsigned int flags)
{
/* old_dir refers to old_dentry->d_parent and new_dir->mnt */
+ if (flags & RENAME_WHITEOUT) {
+ int err;
+
+ /*
+ * Rename with RENAME_WHITEOUT creates a whiteout object in the
+ * old location, so we check the access right for creating that.
+ *
+ * See Documentation/filesystems/overlayfs.rst and renameat2(2).
+ */
+ err = current_check_access_path(
+ old_dir, LANDLOCK_ACCESS_FS_MAKE_WHITEOUT);
+ if (err)
+ return err;
+ }
+
return current_check_refer_path(old_dentry, new_dir, new_dentry, true,
!!(flags & RENAME_EXCHANGE));
}
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index b454ad73b15e..e59378e8e897 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -19,7 +19,7 @@
#define LANDLOCK_MAX_NUM_LAYERS 16
#define LANDLOCK_MAX_NUM_RULES U32_MAX
-#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_RESOLVE_UNIX
+#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index accfd2e5a0cd..d45469d5d464 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -166,7 +166,7 @@ static const struct file_operations ruleset_fops = {
* If the change involves a fix that requires userspace awareness, also update
* the errata documentation in Documentation/userspace-api/landlock.rst .
*/
-const int landlock_abi_version = 9;
+const int landlock_abi_version = 10;
/**
* sys_landlock_create_ruleset - Create a new ruleset
diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
index 30d37234086c..6c8113c2ded1 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -76,8 +76,8 @@ TEST(abi_version)
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
};
- ASSERT_EQ(9, landlock_create_ruleset(NULL, 0,
- LANDLOCK_CREATE_RULESET_VERSION));
+ ASSERT_EQ(10, landlock_create_ruleset(NULL, 0,
+ LANDLOCK_CREATE_RULESET_VERSION));
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
LANDLOCK_CREATE_RULESET_VERSION));
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index cdb47fc1fc0a..53d1b659849f 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -579,7 +579,7 @@ TEST_F_FORK(layout1, inval)
LANDLOCK_ACCESS_FS_IOCTL_DEV | \
LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
-#define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX
+#define ACCESS_LAST LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
#define ACCESS_ALL ( \
ACCESS_FILE | \
@@ -593,7 +593,8 @@ TEST_F_FORK(layout1, inval)
LANDLOCK_ACCESS_FS_MAKE_FIFO | \
LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
LANDLOCK_ACCESS_FS_MAKE_SYM | \
- LANDLOCK_ACCESS_FS_REFER)
+ LANDLOCK_ACCESS_FS_REFER | \
+ LANDLOCK_ACCESS_FS_MAKE_WHITEOUT)
/* clang-format on */
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v2 0/3] landlock: Restrict renameat2 with RENAME_WHITEOUT
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
Hello!
As discussed in [1], the renameat2() syscall's RENAME_WHITEOUT flag allows
the creation of chardev directory entries with major=minor=0 as "whiteout
objects" in the location of the rename source file [2].
This functionality is available even without having any OverlayFS mounted
and can be invoked with the regular renameat2(2) syscall [3].
In V1 [5], it was discussed that whiteout objects are not the same as
character devices, and should therefore be guarded with a separate access
right. We are therefore guarding the operation with the new access right
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT now.
By introducing a new access right, that change is also exposed by
incrementing the ABI level and does not require a Landlock erratum.
Motivation
==========
The RENAME_WHITEOUT flag side-steps all of the existing Landlock access
rights, which are designed to restrict the creation of directory entries.
It is desirable to restrict that.
This patch set fixes that by adding a check in Landlock's path_rename hook.
Tradeoffs considered in the implementation
==========================================
* Should the access right check be merged into the longer
current_check_refer_path() function?
I am leaning towards keeping it as a special case earlier. This means
that we traverse the source path twice, but as we have seen in Debian
Code Search, there are apparently no legitimate callers of renameat2()
with RENAME_WHITEOUT who are calling this from within a Landlock domain.
(fuse-overlayfs is legitimate, but is not landlocked)
It doesn't seem worth complicating our common rename code for a corner
case that doesn't happen in practice.
[1] https://lore.kernel.org/all/adUBCQXrt7kmgqJT@google.com/
[2] https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories
[3] https://man7.org/linux/man-pages/man2/renameat2.2.html#DESCRIPTION
[4] https://codesearch.debian.net/search?q=rename.*RENAME_WHITEOUT&literal=0
[5] https://lore.kernel.org/all/20260411090944.3131168-2-gnoack@google.com/
Changelog
=========
v2:
- Introduce LANDLOCK_ACCESS_FS_MAKE_WHITEOUT access right
and guard it with that.
- Bump ABI version
v1:
- initial version
https://lore.kernel.org/all/20260411090944.3131168-2-gnoack@google.com/
Günther Noack (3):
landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT
selftests/landlock: Add test for RENAME_WHITEOUT denial
selftests/landlock: Test OverlayFS renames w/o
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
include/uapi/linux/landlock.h | 3 ++
security/landlock/audit.c | 1 +
security/landlock/fs.c | 15 ++++++
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
tools/testing/selftests/landlock/base_test.c | 4 +-
tools/testing/selftests/landlock/fs_test.c | 50 +++++++++++++++++++-
7 files changed, 71 insertions(+), 6 deletions(-)
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply
* Re: [PATCH] rust: cred: add safe abstractions for capable() and ns_capable()
From: kernel test robot @ 2026-05-13 15:39 UTC (permalink / raw)
To: Arnav Sharma, ojeda, paul
Cc: oe-kbuild-all, Arnav Sharma, Serge Hallyn, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, linux-security-module,
rust-for-linux, linux-kernel
In-Reply-To: <20260506204913.26022-1-arnav4324@gmail.com>
Hi Arnav,
kernel test robot noticed the following build errors:
[auto build test ERROR on rust/rust-next]
[also build test ERROR on linus/master v7.1-rc3 next-20260508]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Arnav-Sharma/rust-cred-add-safe-abstractions-for-capable-and-ns_capable/20260513-154340
base: https://github.com/Rust-for-Linux/linux rust-next
patch link: https://lore.kernel.org/r/20260506204913.26022-1-arnav4324%40gmail.com
patch subject: [PATCH] rust: cred: add safe abstractions for capable() and ns_capable()
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260513/202605131729.NXF18q0f-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260513/202605131729.NXF18q0f-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605131729.NXF18q0f-lkp@intel.com/
All errors (new ones prefixed by >>):
PATH=/opt/cross/clang-20/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
INFO PATH=/opt/cross/rustc-1.88.0-bindgen-0.72.1/cargo/bin:/opt/cross/clang-20/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/usr/bin/timeout -k 100 12h /usr/bin/make KCFLAGS=\ -fno-crash-diagnostics\ -Wno-error=return-type\ -Wreturn-type\ -funsigned-char\ -Wundef\ -falign-functions=64 W=1 --keep-going LLVM=1 -j384 -C source O=/kbuild/obj/consumer/x86_64-rhel-9.4-rust ARCH=x86_64 SHELL=/bin/bash rustfmtcheck
make: Entering directory '/kbuild/src'
make[1]: Entering directory '/kbuild/obj/consumer/x86_64-rhel-9.4-rust'
>> Diff in rust/kernel/cred.rs:168:
// the specified capability is granted.
unsafe { bindings::ns_capable(ns, cap as i32) }
}
-
>> Diff in rust/kernel/cred.rs:168:
// the specified capability is granted.
unsafe { bindings::ns_capable(ns, cap as i32) }
}
-
make[2]: *** [Makefile:1954: rustfmt] Error 123
make[2]: Target 'rustfmtcheck' not remade because of errors.
make[1]: Leaving directory '/kbuild/obj/consumer/x86_64-rhel-9.4-rust'
make[1]: *** [Makefile:248: __sub-make] Error 2
make[1]: Target 'rustfmtcheck' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'rustfmtcheck' not remade because of errors.
make: Leaving directory '/kbuild/src'
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v1] landlock: Demonstrate best-effort allowed_access filtering
From: Mickaël Salaün @ 2026-05-13 15:18 UTC (permalink / raw)
To: Günther Noack
Cc: Mickaël Salaün, linux-security-module, Justin Suess,
Tingmao Wang
Landlock provides best-effort sandboxing across ABI versions:
applications request the rights they need, and on older kernels the
unsupported rights are silently dropped from handled_access_* by the
documented compatibility switch. The recommended pattern for
landlock_add_rule(2) calls is to mirror this filtering at the rule
level, which wasn't explicitly described in the exemple.
Show the pattern explicitly in the filesystem and network rule examples
by masking each rule's allowed_access against the ruleset's
handled_access_* and adding the rule only when at least one bit remains
set. This makes the recommended best-effort pattern self-documenting.
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---
Documentation/userspace-api/landlock.rst | 48 +++++++++++++-----------
1 file changed, 27 insertions(+), 21 deletions(-)
diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index fd8b78c31f2f..45861fa75685 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -8,7 +8,7 @@ Landlock: unprivileged access control
=====================================
:Author: Mickaël Salaün
-:Date: March 2026
+:Date: May 2026
The goal of Landlock is to enable restriction of ambient rights (e.g. global
filesystem or network access) for a set of processes. Because Landlock
@@ -155,7 +155,7 @@ this file descriptor.
.. code-block:: c
- int err;
+ int err = 0;
struct landlock_path_beneath_attr path_beneath = {
.allowed_access =
LANDLOCK_ACCESS_FS_EXECUTE |
@@ -163,25 +163,29 @@ this file descriptor.
LANDLOCK_ACCESS_FS_READ_DIR,
};
- path_beneath.parent_fd = open("/usr", O_PATH | O_CLOEXEC);
- if (path_beneath.parent_fd < 0) {
- perror("Failed to open file");
- close(ruleset_fd);
- return 1;
- }
- err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
- &path_beneath, 0);
- close(path_beneath.parent_fd);
- if (err) {
- perror("Failed to update ruleset");
- close(ruleset_fd);
- return 1;
+ path_beneath.allowed_access &= ruleset_attr.handled_access_fs;
+ if (path_beneath.allowed_access) {
+ path_beneath.parent_fd = open("/usr", O_PATH | O_CLOEXEC);
+ if (path_beneath.parent_fd < 0) {
+ perror("Failed to open file");
+ close(ruleset_fd);
+ return 1;
+ }
+ err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
+ &path_beneath, 0);
+ close(path_beneath.parent_fd);
+ if (err) {
+ perror("Failed to update ruleset");
+ close(ruleset_fd);
+ return 1;
+ }
}
-It may also be required to create rules following the same logic as explained
-for the ruleset creation, by filtering access rights according to the Landlock
-ABI version. In this example, this is not required because all of the requested
-``allowed_access`` rights are already available in ABI 1.
+As shown above, masking the rule's ``allowed_access`` against the ruleset's
+``handled_access_*`` is the recommended best-effort pattern: rights the running
+kernel does not support are dropped (the compatibility switch above already
+cleared them in ``handled_access_*``), and the rule is skipped if no supported
+right remains.
For network access-control, we can add a set of rules that allow to use a port
number for a specific action: HTTPS connections.
@@ -193,8 +197,10 @@ number for a specific action: HTTPS connections.
.port = 443,
};
- err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
- &net_port, 0);
+ net_port.allowed_access &= ruleset_attr.handled_access_net;
+ if (net_port.allowed_access)
+ err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
+ &net_port, 0);
When passing a non-zero ``flags`` argument to ``landlock_restrict_self()``, a
similar backwards compatibility check is needed for the restrict flags
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] rust: cred: add safe abstractions for capable() and ns_capable()
From: kernel test robot @ 2026-05-13 12:53 UTC (permalink / raw)
To: Arnav Sharma, ojeda, paul
Cc: llvm, oe-kbuild-all, Arnav Sharma, Serge Hallyn, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich, linux-security-module,
rust-for-linux, linux-kernel
In-Reply-To: <20260506204913.26022-1-arnav4324@gmail.com>
Hi Arnav,
kernel test robot noticed the following build errors:
[auto build test ERROR on rust/rust-next]
[also build test ERROR on linus/master v7.1-rc3 next-20260508]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Arnav-Sharma/rust-cred-add-safe-abstractions-for-capable-and-ns_capable/20260513-154340
base: https://github.com/Rust-for-Linux/linux rust-next
patch link: https://lore.kernel.org/r/20260506204913.26022-1-arnav4324%40gmail.com
patch subject: [PATCH] rust: cred: add safe abstractions for capable() and ns_capable()
config: loongarch-randconfig-001 (https://download.01.org/0day-ci/archive/20260513/202605132018.249x1thF-lkp@intel.com/config)
compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260513/202605132018.249x1thF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605132018.249x1thF-lkp@intel.com/
All errors (new ones prefixed by >>):
>> error[E0425]: cannot find function `capable` in crate `bindings`
--> rust/kernel/cred.rs:133:24
|
133 | unsafe { bindings::capable(cap as i32) }
| ^^^^^^^ not found in `bindings`
--
>> error[E0425]: cannot find function `ns_capable` in crate `bindings`
--> rust/kernel/cred.rs:169:24
|
169 | unsafe { bindings::ns_capable(ns, cap as i32) }
| ^^^^^^^^^^ help: a function with a similar name exists: `cap_capable`
|
::: rust/bindings/bindings_generated.rs:107518:5
|
107518 | / pub fn cap_capable(
107519 | | cred: *const cred,
107520 | | ns: *mut user_namespace,
107521 | | cap: ffi::c_int,
107522 | | opts: ffi::c_uint,
107523 | | ) -> ffi::c_int;
| |____________________- similarly named function `cap_capable` defined here
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH RFC 2/5] dma-heap: charge dma-buf memory via explicit memcg
From: Albert Esteve @ 2026-05-13 12:41 UTC (permalink / raw)
To: Christian König
Cc: Tejun Heo, Johannes Weiner, Michal Koutný, Jonathan Corbet,
Shuah Khan, Sumit Semwal, Michal Hocko, Roman Gushchin,
Shakeel Butt, Muchun Song, Andrew Morton, Benjamin Gaignard,
Brian Starkey, John Stultz, T.J. Mercier, Christian Brauner,
Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Ondrej Mosnacek, Shuah Khan, cgroups, linux-doc, linux-kernel,
linux-media, dri-devel, linaro-mm-sig, linux-mm,
linux-security-module, selinux, linux-kselftest, mripard,
echanude
In-Reply-To: <8ef38815-6ae9-4359-86d4-042554357639@amd.com>
On Tue, May 12, 2026 at 12:14 PM Christian König
<christian.koenig@amd.com> wrote:
>
> On 5/12/26 11:10, Albert Esteve wrote:
> > On embedded platforms a central process often allocates dma-buf
> > memory on behalf of client applications. Without a way to
> > attribute the charge to the requesting client's cgroup, the
> > cost lands on the allocator, making per-cgroup memory limits
> > ineffective for the actual consumers.
> >
> > Add charge_pid_fd to struct dma_heap_allocation_data. When set to
> > a valid pidfd, DMA_HEAP_IOCTL_ALLOC resolves the target task's
> > memcg and charges the buffer there via mem_cgroup_charge_dmabuf()
> > inside dma_heap_buffer_alloc(). Without charge_pid_fd, and with
> > the mem_accounting module parameter enabled, the buffer is charged
> > to the allocator's own cgroup.
> >
> > Additionally, commit 3c227be90659 ("dma-buf: system_heap: account for
> > system heap allocation in memcg") adds __GFP_ACCOUNT to system-heap
> > page allocations. Keeping __GFP_ACCOUNT would charge the same pages
> > twice (once to kmem, once to MEMCG_DMABUF), thus remove it and route
> > all accounting through a single MEMCG_DMABUF path.
> >
> > Usage examples:
> >
> > 1. Central allocator charging to a client at allocation time.
> > The allocator knows the client's PID (e.g., from binder's
> > sender_pid) and uses pidfd to attribute the charge:
> >
> > pid_t client_pid = txn->sender_pid;
> > int pidfd = pidfd_open(client_pid, 0);
> >
> > struct dma_heap_allocation_data alloc = {
> > .len = buffer_size,
> > .fd_flags = O_RDWR | O_CLOEXEC,
> > .charge_pid_fd = pidfd,
> > };
> > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > close(pidfd);
> > /* alloc.fd is now charged to client's cgroup */
> >
> > 2. Default allocation (no pidfd, mem_accounting=1).
> > When charge_pid_fd is not set and the mem_accounting module
> > parameter is enabled, the buffer is charged to the allocator's
> > own cgroup:
> >
> > struct dma_heap_allocation_data alloc = {
> > .len = buffer_size,
> > .fd_flags = O_RDWR | O_CLOEXEC,
> > };
> > ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
> > /* charged to current process's cgroup */
> >
> > Current limitations:
> >
> > - Single-owner model: a dma-buf carries one memcg charge regardless of
> > how many processes share it. Means only the first owner (and exporter)
> > of the shared buffer bears the charge.
> > - Only memcg accounting supported. While this makes sense for system
> > heap buffers, other heaps (e.g., CMA heaps) will require selectively
> > charging also for the dmem controller.
>
> Well that doesn't looks soo bad, it at least seems to tackle the problem at hand for Android and some of other embedded use cases.
>
> I'm just not sure if this is future prove and will work for all use cases, e.g. cloud gaming, native context for automotive etc...
>
> Essentially the problem boils down to two limitations:
> 1) a piece of memory can only be charged to one cgroup, the framework doesn't has a concept of charging shared memory to multiple groups
> 2) when memory references in the form of file descriptors are passed between applications we have no way of changing the accounting to a different cgroup
>
> The passing of the memory reference already has a well defined uAPI and if we could solve those two limitations we not only solve the problem without introducing new uAPI (with potential new security risks) but also solve it for all other use cases which uses file descriptors as well as. E.g. memfd, accel and GPU drivers etc...
Honestly, adding a hook to fd-passing uAPI to manage charge transfers
sounds like a promising solution requiring no uAPI changes. However,
it still does not cover all paths, e.g., dup() or fork(). And shared
memory sounds like a hard one to tackle, where deciding the best
policy is more a per-usecase thing and would probably require
userspace configuration. All in all, charge_pid_fd covers a
well-defined and immediately practical subset. The UAPI cost is small
and the mechanism is explicit about what it does and doesn't solve. A
general solution, if it ever converges, would likely supersede
charge_pid_fd for most cases, which is a fine outcome if it solves the
problem more completely.
Either way, if you have a specific approach in mind for solving any of
the above limitations, I'd be happy to look into it further.
BR,
Albert.
>
> On the other hand it is really nice to finally see this tackled for at least DMA-buf heaps. On the GPU side I have seen just another try of a driver doing some kind of special driver specific accounting to solve this just a few weeks ago. And to be honest such single driver island approach have the tendency to break more often that they are working correctly.
>
> Regards,
> Christian.
>
> >
> > Signed-off-by: Albert Esteve <aesteve@redhat.com>
> > ---
> > Documentation/admin-guide/cgroup-v2.rst | 5 ++--
> > drivers/dma-buf/dma-buf.c | 16 ++++---------
> > drivers/dma-buf/dma-heap.c | 42 ++++++++++++++++++++++++++++++---
> > drivers/dma-buf/heaps/system_heap.c | 2 --
> > include/uapi/linux/dma-heap.h | 6 +++++
> > 5 files changed, 53 insertions(+), 18 deletions(-)
> >
> > diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
> > index 8bdbc2e866430..824d269531eb1 100644
> > --- a/Documentation/admin-guide/cgroup-v2.rst
> > +++ b/Documentation/admin-guide/cgroup-v2.rst
> > @@ -1636,8 +1636,9 @@ The following nested keys are defined.
> > structures.
> >
> > dmabuf (npn)
> > - Amount of memory used for exported DMA buffers allocated by the cgroup.
> > - Stays with the allocating cgroup regardless of how the buffer is shared.
> > + Amount of memory used for exported DMA buffers allocated by or on
> > + behalf of the cgroup. Stays with the allocating cgroup regardless
> > + of how the buffer is shared.
> >
> > workingset_refault_anon
> > Number of refaults of previously evicted anonymous pages.
> > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> > index ce02377f48908..23fb758b78297 100644
> > --- a/drivers/dma-buf/dma-buf.c
> > +++ b/drivers/dma-buf/dma-buf.c
> > @@ -181,8 +181,11 @@ static void dma_buf_release(struct dentry *dentry)
> > */
> > BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
> >
> > - mem_cgroup_uncharge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > - mem_cgroup_put(dmabuf->memcg);
> > + if (dmabuf->memcg) {
> > + mem_cgroup_uncharge_dmabuf(dmabuf->memcg,
> > + PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> > + mem_cgroup_put(dmabuf->memcg);
> > + }
> >
> > dmabuf->ops->release(dmabuf);
> >
> > @@ -764,13 +767,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> > dmabuf->resv = resv;
> > }
> >
> > - dmabuf->memcg = get_mem_cgroup_from_mm(current->mm);
> > - if (!mem_cgroup_charge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE,
> > - GFP_KERNEL)) {
> > - ret = -ENOMEM;
> > - goto err_memcg;
> > - }
> > -
> > file->private_data = dmabuf;
> > file->f_path.dentry->d_fsdata = dmabuf;
> > dmabuf->file = file;
> > @@ -781,8 +777,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
> >
> > return dmabuf;
> >
> > -err_memcg:
> > - mem_cgroup_put(dmabuf->memcg);
> > err_file:
> > fput(file);
> > err_module:
> > diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
> > index ac5f8685a6494..ff6e259afcdc0 100644
> > --- a/drivers/dma-buf/dma-heap.c
> > +++ b/drivers/dma-buf/dma-heap.c
> > @@ -7,13 +7,17 @@
> > */
> >
> > #include <linux/cdev.h>
> > +#include <linux/cgroup.h>
> > #include <linux/device.h>
> > #include <linux/dma-buf.h>
> > #include <linux/dma-heap.h>
> > +#include <linux/memcontrol.h>
> > +#include <linux/sched/mm.h>
> > #include <linux/err.h>
> > #include <linux/export.h>
> > #include <linux/list.h>
> > #include <linux/nospec.h>
> > +#include <linux/pidfd.h>
> > #include <linux/syscalls.h>
> > #include <linux/uaccess.h>
> > #include <linux/xarray.h>
> > @@ -55,10 +59,12 @@ MODULE_PARM_DESC(mem_accounting,
> > "Enable cgroup-based memory accounting for dma-buf heap allocations (default=false).");
> >
> > static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > - u32 fd_flags,
> > - u64 heap_flags)
> > + u32 fd_flags, u64 heap_flags,
> > + struct mem_cgroup *charge_to)
> > {
> > struct dma_buf *dmabuf;
> > + unsigned int nr_pages;
> > + struct mem_cgroup *memcg = charge_to;
> > int fd;
> >
> > /*
> > @@ -73,6 +79,22 @@ static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> > if (IS_ERR(dmabuf))
> > return PTR_ERR(dmabuf);
> >
> > + nr_pages = len / PAGE_SIZE;
> > +
> > + if (memcg)
> > + css_get(&memcg->css);
> > + else if (mem_accounting)
> > + memcg = get_mem_cgroup_from_mm(current->mm);
> > +
> > + if (memcg) {
> > + if (!mem_cgroup_charge_dmabuf(memcg, nr_pages, GFP_KERNEL)) {
> > + mem_cgroup_put(memcg);
> > + dma_buf_put(dmabuf);
> > + return -ENOMEM;
> > + }
> > + dmabuf->memcg = memcg;
> > + }
> > +
> > fd = dma_buf_fd(dmabuf, fd_flags);
> > if (fd < 0) {
> > dma_buf_put(dmabuf);
> > @@ -102,6 +124,9 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > {
> > struct dma_heap_allocation_data *heap_allocation = data;
> > struct dma_heap *heap = file->private_data;
> > + struct mem_cgroup *memcg = NULL;
> > + struct task_struct *task;
> > + unsigned int pidfd_flags;
> > int fd;
> >
> > if (heap_allocation->fd)
> > @@ -113,9 +138,20 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
> > if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS)
> > return -EINVAL;
> >
> > + if (heap_allocation->charge_pid_fd) {
> > + task = pidfd_get_task(heap_allocation->charge_pid_fd, &pidfd_flags);
> > + if (IS_ERR(task))
> > + return PTR_ERR(task);
> > +
> > + memcg = get_mem_cgroup_from_mm(task->mm);
> > + put_task_struct(task);
> > + }
> > +
> > fd = dma_heap_buffer_alloc(heap, heap_allocation->len,
> > heap_allocation->fd_flags,
> > - heap_allocation->heap_flags);
> > + heap_allocation->heap_flags,
> > + memcg);
> > + mem_cgroup_put(memcg);
> > if (fd < 0)
> > return fd;
> >
> > diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
> > index 03c2b87cb1112..95d7688167b93 100644
> > --- a/drivers/dma-buf/heaps/system_heap.c
> > +++ b/drivers/dma-buf/heaps/system_heap.c
> > @@ -385,8 +385,6 @@ static struct page *alloc_largest_available(unsigned long size,
> > if (max_order < orders[i])
> > continue;
> > flags = order_flags[i];
> > - if (mem_accounting)
> > - flags |= __GFP_ACCOUNT;
> > page = alloc_pages(flags, orders[i]);
> > if (!page)
> > continue;
> > diff --git a/include/uapi/linux/dma-heap.h b/include/uapi/linux/dma-heap.h
> > index a4cf716a49fa6..e02b0f8cbc6a1 100644
> > --- a/include/uapi/linux/dma-heap.h
> > +++ b/include/uapi/linux/dma-heap.h
> > @@ -29,6 +29,10 @@
> > * handle to the allocated dma-buf
> > * @fd_flags: file descriptor flags used when allocating
> > * @heap_flags: flags passed to heap
> > + * @charge_pid_fd: optional pidfd of the process whose cgroup should be
> > + * charged for this allocation; 0 means charge the calling
> > + * process's cgroup
> > + * @__padding: reserved, must be zero
> > *
> > * Provided by userspace as an argument to the ioctl
> > */
> > @@ -37,6 +41,8 @@ struct dma_heap_allocation_data {
> > __u32 fd;
> > __u32 fd_flags;
> > __u64 heap_flags;
> > + __u32 charge_pid_fd;
> > + __u32 __padding;
> > };
> >
> > #define DMA_HEAP_IOC_MAGIC 'H'
> >
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox