Re: [PATCH 1/2] dlm: gate dlm_plock device on CAP_SYS_ADMIN

Alexander Aring <[email protected]> Thu, 16 Jul 2026 14:11:42 -0400
Newsgroups dev.linux.lists.gfs2,org.kernel.vger.linux-kernel
Message-ID <CAK-6q+jkA3_sYQZhRRHNBCrX4MsjsLJMRODr-d6t6n3T3tFTOg@mail.gmail.com>
Hi,

On Thu, Jul 16, 2026 at 3:27=E2=80=AFAM Haofeng Li <[email protected]> w=
rote:
>
> fs/dlm/plock.c registers /dev/dlm_plock via a miscdevice whose
> file_operations has no .open callback and whose .mode field is unset.
> The kernel therefore performs no capability check on open, and any
> process that can open the node becomes an unprivileged plock daemon
> with full read+write access to the pending-plock queue.
>
> Attack chain (when the device node is reachable by an unprivileged
> opener =E2=80=94 see mitigation note below):
>
>   1. attacker open("/dev/dlm_plock") succeeds with no cap check
>   2. dev_read() drains pending plock requests straight to user
>      space, leaking dlm_plock_info fields: fsid, number (resource
>      id / inode), start, end, owner, pid, ex, wait
>   3. dev_write() matches an attacker-supplied dlm_plock_info
>      against a pending op on recv_list (matched on fsid+number+
>      owner+pid+start+end+ex+wait) and memcpy()'s it into the
>      in-kernel op, including a forged .rv =3D=3D 0
>   4. when a matched op exists, the forged result is then applied:
>      for async ops (op->data !=3D NULL), dlm_plock_callback() runs
>      posix_lock_file(); for sync ops, the requester wakes and
>      proceeds as if the cluster had granted the lock.  Either way
>      the requester ends up holding a POSIX lock without a real DLM
>      grant, or sees attacker-chosen rv that breaks lock correctness.
>      With no pending op on recv_list, dev_write() still returns
>      sizeof(info) but does nothing beyond a pr_debug ("dlm dev_write
>      no op ...") =E2=80=94 so a syntactically accepted write does not by
>      itself prove an applied grant.
>
> Mitigation: on a stock kernel, devtmpfs creates /dev/dlm_plock as
> 0600 root:root, so steps 1-4 are only reachable where the node is
> exposed to a less privileged principal =E2=80=94 e.g. udev MODE=3D0666,
> container bind-mount of the node, or an fd passed via SCM_RIGHTS.
> The in-kernel capability gap is real regardless of node mode.
>
> Reproduction (kernel 7.2.0-rc3, dlm loaded):
>
>   # ./exploit_h2   # as root
>   [*] node /dev/dlm_plock mode=3D0600 uid=3D0 gid=3D0
>   [!!!] AUTH BYPASS: opened with no capability check (fd=3D3)
>   [!!!] FORGE ACCEPTED: kernel accepted forged plock result (rv=3D0);
>        pending ops are grant-forgeable
>   [VULNERABLE] open + read-leak + grant-forge demonstrated
>
>   The "FORGE ACCEPTED" line means dev_write() returned sizeof(info),
>   i.e. the write path is reachable and the version check passed; it
>   does not by itself mean a grant was applied.  Demonstrating an
>   actual forged grant requires a concurrent plock op on recv_list to
>   match against.
>
>   $ setpriv --reuid 65534 --regid 65534 ./exploit_h2
>   [OK ] open denied: Permission denied   # devtmpfs 0600,
>                                          not a kernel cap check
>
> Fix: add a .open callback that requires CAP_SYS_ADMIN, and set
> .mode =3D 0600 on the miscdevice so the explicit expectation matches
> the devtmpfs default and survives future defaults.
>
> Signed-off-by: Haofeng Li <[email protected]>

Acked-by: Alexander Aring <[email protected]>

Thanks.

- Alex