Linux Security Modules development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
Cc: linux-security-module@vger.kernel.org
Subject: Re: [RFC PATCH v2 2/3] security: Add PR_CAPBSET_DROP_MASK for process-wide bounding-set drops
Date: Tue, 29 Sep 2026 13:19:07 +0000	[thread overview]
Message-ID: <20260929131907.DA7AC1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260929130200.1638343-3-ruanjinjie@huawei.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] userns: PR_CAPBSET_DROP_MASK leaks into new user namespaces
- [High] cred: PR_CAPBSET_DROP_MASK breaks self-containment of struct cred
--

commit fcb774e0491f03726a243dd79d9b587551550d6e
Author: Jinjie Ruan <ruanjinjie@huawei.com>

security: Add PR_CAPBSET_DROP_MASK for process-wide bounding-set drops

This commit introduces a new prctl, PR_CAPBSET_DROP_MASK, to drop bounding set
capabilities across an entire thread group simultaneously. It achieves this by
storing a pending drop mask in the signal_struct and dynamically subtracting
it during capability checks.

> diff --git a/security/commoncap.c b/security/commoncap.c
> index 3399535808fec..3bec15d437312 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
[ ... ]
> @@ -30,6 +32,25 @@
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/capability.h>
>  
> +/**
> + * Effective bounding set of @cred in @task's thread group
> + * @task: task whose thread group's pending drop applies
> + * @cred: credentials to read the bounding set from
> + *
> + * A drop recorded by PR_CAPBSET_DROP_MASK is authoritative on the thread group
> + * and may not have been materialized into every thread's cred yet, so the
> + * effective bounding set is the cred's own set minus the group's pending drop.
> + */
> +kernel_cap_t cap_bset_effective(const struct task_struct *task,
> +				const struct cred *cred)
> +{
> +	kernel_cap_t pending = {
> +		.val = atomic64_read(&task->signal->cap_bset_pending),
> +	};
> +
> +	return cap_drop(cred->cap_bset, pending);
> +}

[Severity: High]
Does this dynamic subtraction inadvertently leak parent bounding set drops into
new user namespaces?

When a new user namespace is created via clone(CLONE_NEWUSER) or unshare(),
set_cred_user_ns() resets cred->cap_bset to CAP_FULL_SET to ensure the new
namespace starts with full capabilities relative to itself.

However, because cap_bset_effective() dynamically subtracts the pending mask
from task->signal, any pending drops from the parent namespace will still be
applied to the new namespace's credentials. This could permanently restrict
them.

[ ... ]
> @@ -1283,6 +1306,63 @@ static int cap_prctl_drop(unsigned long cap)
>  	return commit_creds(new);
>  }
>  
> +static int cap_bset_drop_process(kernel_cap_t mask)
> +{
> +	kernel_cap_t pending;
> +	struct cred *new;
> +
> +	new = prepare_creds();
> +	if (!new)
> +		return -ENOMEM;
> +
> +	/*
> +	 * Record the drop before committing the caller's cred, so that a
> +	 * thread created from now on is guaranteed to observe it.  Apply the
> +	 * current union, not just this call's mask, to the caller's cred.
> +	 */
> +	spin_lock_irq(&current->sighand->siglock);
> +	atomic64_or(mask.val, &current->signal->cap_bset_pending);

[Severity: High]
Does storing the capability drop outside of struct cred break subsystems that
rely on the immutability and self-containment of saved credentials?

If a thread calls PR_CAPBSET_DROP_MASK, while another thread in the same
group opens an AppArmor-mediated file, that file saves the thread's stale
credential (e.g., in file->f_cred).

AppArmor might then evaluate the bounding set directly from this standalone
credential snapshot (like in is_subset_of_obj_privilege()). By placing the
drop state in signal_struct rather than struct cred, these asynchronous
evaluations will miss the pending drops.

Could this lead to false denials or security bypasses because the capability
evaluations are using stale capabilities?

> +	pending.val = atomic64_read(&current->signal->cap_bset_pending);
> +	spin_unlock_irq(&current->sighand->siglock);
> +
> +	new->cap_bset = cap_drop(new->cap_bset, pending);
> +	commit_creds(new);
> +
> +	return 0;
> +}
> +
> +/*
> + * Propagate a pending process-wide bounding-set drop to @p, a task being
> + * created by the current thread.  Threads sharing the group read
> + * current->signal->cap_bset_pending directly; a forked child gets its own
> + * signal_struct and must carry the mask itself.  Called under
> + * current->sighand->siglock, which serializes it with cap_bset_drop_process().
> + */
> +void cap_bset_drop_fork(struct task_struct *p)
> +{
> +	kernel_cap_t mask = {
> +		.val = atomic64_read(&current->signal->cap_bset_pending),
> +	};
> +
> +	if (cap_isclear(mask) || p->signal == current->signal)
> +		return;
> +
> +	atomic64_or(mask.val, &p->signal->cap_bset_pending);
> +}

[Severity: High]
Does actively copying the parent's dropped capabilities mask into a newly
created process erase namespace isolation boundaries?

When CLONE_NEWUSER is requested, the child is meant to receive a full
bounding set within its new namespace.

Because cap_bset_drop_fork() copies the parent's pending mask into the
child's signal_struct without clearing it for new user namespaces, those
capability drops will bleed into the child's effective bounding set. This
breaks the isolation guarantees of user namespaces.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260929130200.1638343-1-ruanjinjie@huawei.com?part=2

  reply	other threads:[~2026-09-29 13:19 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-29 13:01 [RFC PATCH v2 0/3] security: Add PR_CAPBSET_DROP_MASK Jinjie Ruan
2026-09-29 13:01 ` [RFC PATCH v2 1/3] capability: Move mk_kernel_cap() to header Jinjie Ruan
2026-09-29 13:06   ` sashiko-bot
2026-09-29 17:15   ` Bradley Morgan
2026-09-29 13:01 ` [RFC PATCH v2 2/3] security: Add PR_CAPBSET_DROP_MASK for process-wide bounding-set drops Jinjie Ruan
2026-09-29 13:19   ` sashiko-bot [this message]
2026-09-29 13:02 ` [RFC PATCH v2 3/3] selftests: prctl: add process-wide bounding-set drop tests Jinjie Ruan
2026-09-29 13:11   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260929131907.DA7AC1F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox