From: Alexander Aring <aahringo@redhat.com>
To: teigland@redhat.com
Cc: aahringo@redhat.com, gfs2@lists.linux.dev
Subject: [PATCH RESEND dlm/next 1/8] dlm: gate dlm_plock device on CAP_SYS_ADMIN
Date: Tue, 1 Sep 2026 13:47:08 -0400 [thread overview]
Message-ID: <20260901174715.3825582-2-aahringo@redhat.com> (raw)
In-Reply-To: <20260901174715.3825582-1-aahringo@redhat.com>
From: Haofeng Li <lihaofeng@kylinos.cn>
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 — 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 == 0
4. when a matched op exists, the forged result is then applied:
for async ops (op->data != 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 ...") — 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 — e.g. udev MODE=0666,
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=0600 uid=0 gid=0
[!!!] AUTH BYPASS: opened with no capability check (fd=3)
[!!!] FORGE ACCEPTED: kernel accepted forged plock result (rv=0);
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 = 0600 on the miscdevice so the explicit expectation matches
the devtmpfs default and survives future defaults.
Acked-by: Alexander Aring <aahringo@redhat.com>
Signed-off-by: Haofeng Li <lihaofeng@kylinos.cn>
Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
fs/dlm/plock.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index e9598b3fe5d09..711e8bc3a46a6 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -4,6 +4,7 @@
*/
#include <linux/fs.h>
+#include <linux/capability.h>
#include <linux/filelock.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
@@ -477,6 +478,15 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
}
EXPORT_SYMBOL_GPL(dlm_posix_get);
+static int dev_open(struct inode *inode, struct file *file)
+{
+ /* Userspace plock daemon is a privileged cluster component. */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return 0;
+}
+
/* a read copies out one plock request from the send list */
static ssize_t dev_read(struct file *file, char __user *u, size_t count,
loff_t *ppos)
@@ -598,6 +608,7 @@ static __poll_t dev_poll(struct file *file, poll_table *wait)
}
static const struct file_operations dev_fops = {
+ .open = dev_open,
.read = dev_read,
.write = dev_write,
.poll = dev_poll,
@@ -608,7 +619,8 @@ static const struct file_operations dev_fops = {
static struct miscdevice plock_dev_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DLM_PLOCK_MISC_NAME,
- .fops = &dev_fops
+ .fops = &dev_fops,
+ .mode = 0600,
};
int dlm_plock_init(void)
--
2.43.0
next prev parent reply other threads:[~2026-09-01 17:47 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 17:47 [PATCH RESEND dlm/next 0/8] dlm: pending fixes based on v7.3-rc1 Alexander Aring
2026-09-01 17:47 ` Alexander Aring [this message]
2026-09-01 17:47 ` [PATCH RESEND dlm/next 2/8] dlm: require CAP_SYS_ADMIN for dlm-monitor device Alexander Aring
2026-09-01 17:47 ` [PATCH RESEND dlm/next 3/8] dlm: validate userspace lock resource name length Alexander Aring
2026-09-01 17:47 ` [PATCH RESEND dlm/next 4/8] dlm: fix buffer overflow from negative len in dlm_search_rsb_tree Alexander Aring
2026-09-01 17:47 ` [PATCH RESEND dlm/next 5/8] dlm: validate lock modes in recovery messages Alexander Aring
2026-09-01 17:47 ` [PATCH RESEND dlm/next 6/8] dlm: fix NULL pointer dereference in dlm_dump_rsb_name() Alexander Aring
2026-09-01 17:47 ` [PATCH RESEND dlm/next 7/8] dlm: wait for outstanding SRCU callbacks to complete in exit paths Alexander Aring
2026-09-02 13:24 ` Alexander Aring
2026-09-01 17:47 ` [PATCH RESEND dlm/next 8/8] dlm: fix variable key length lookup Alexander Aring
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=20260901174715.3825582-2-aahringo@redhat.com \
--to=aahringo@redhat.com \
--cc=gfs2@lists.linux.dev \
--cc=teigland@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.