From nobody Sat Jul 25 16:20:07 2026 Received: from mailgw.kylinos.cn (mailgw.kylinos.cn [124.126.103.232]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53CEB3A5421 for ; Thu, 16 Jul 2026 07:22:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=124.126.103.232 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784186528; cv=none; b=PqUCZFIgFZbp1JMMyhwoDkY9u6uEjNinAroKRlW5yuZ2EgInwUJA3H2WrYSQ9iJqI/Ar6sq3tvs7POJgqU4PMIIZILsBErIo2RXfYdRdsI/jUpaAd7+XY+QmSmaRXdfuNZ0OUzAhbfbglxf/8r0foNKwcz27/fp4D4zBM82+vb4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784186528; c=relaxed/simple; bh=T9asGJUk/B7ooYJrTYe7NLGzmEhQvhlSajtKOW+pouE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=YeEcpXRxrIRNj1eXnZz0tasJz0/lAUz+fA/2lBbpg522aRzYjJEeS1ZrHPQVyR1DMmZmtVOijHPrpGu+0Nmui7xL0lsCmfKf6epDpalw8zlvtZyQ4vBVjaJrABOQ5IfGDThPcfu/ABHoaXj9znQN9MOv1SR9qg77pubNR75+h00= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=kylinos.cn; spf=pass smtp.mailfrom=kylinos.cn; arc=none smtp.client-ip=124.126.103.232 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=kylinos.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=kylinos.cn X-UUID: 06e2d68080e711f1aa26b74ffac11d73-20260716 X-CID-CACHE: Type:Local,Time:202607161511+08,HitQuantity:1 X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.3.12,REQID:d5627d7f-4e89-44bf-97a7-ae01d2013e3c,IP:0,U RL:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:0 X-CID-META: VersionHash:e7bac3a,CLOUDID:b73c612305126364857bceaa785b845b,BulkI D:nil,BulkQuantity:0,Recheck:0,SF:81|82|102|850|865|898,TC:nil,Content:0|1 5|50,EDM:-3,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI :0,OSA:0,AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 2,SSN|SDN X-CID-BAS: 2,SSN|SDN,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-CID-RHF: D41D8CD98F00B204E9800998ECF8427E X-UUID: 06e2d68080e711f1aa26b74ffac11d73-20260716 X-User: lihaofeng@kylinos.cn Received: from localhost.localdomain [(10.44.16.150)] by mailgw.kylinos.cn (envelope-from ) (Generic MTA with TLSv1.3 TLS_AES_256_GCM_SHA384 256/256) with ESMTP id 364802631; Thu, 16 Jul 2026 15:21:56 +0800 From: Haofeng Li To: aahringo@redhat.com, teigland@redhat.com Cc: gfs2@lists.linux.dev, linux-kernel@vger.kernel.org, Haofeng Li <13266079573@163.com>, Haofeng Li Subject: [PATCH 1/2] dlm: gate dlm_plock device on CAP_SYS_ADMIN Date: Thu, 16 Jul 2026 15:21:51 +0800 Message-Id: <20260716072152.326803-2-lihaofeng@kylinos.cn> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260716072152.326803-1-lihaofeng@kylinos.cn> References: <20260716072152.326803-1-lihaofeng@kylinos.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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 Acked-by: Alexander Aring --- 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 e9598b3fe5d0..711e8bc3a46a 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -4,6 +4,7 @@ */ =20 #include +#include #include #include #include @@ -477,6 +478,15 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 numb= er, struct file *file, } EXPORT_SYMBOL_GPL(dlm_posix_get); =20 +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) } =20 static const struct file_operations dev_fops =3D { + .open =3D dev_open, .read =3D dev_read, .write =3D dev_write, .poll =3D dev_poll, @@ -608,7 +619,8 @@ static const struct file_operations dev_fops =3D { static struct miscdevice plock_dev_misc =3D { .minor =3D MISC_DYNAMIC_MINOR, .name =3D DLM_PLOCK_MISC_NAME, - .fops =3D &dev_fops + .fops =3D &dev_fops, + .mode =3D 0600, }; =20 int dlm_plock_init(void) --=20 2.25.1 From nobody Sat Jul 25 16:20:07 2026 Received: from mailgw.kylinos.cn (mailgw.kylinos.cn [124.126.103.232]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A3A033A6B6F for ; Thu, 16 Jul 2026 07:22:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=124.126.103.232 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784186527; cv=none; b=iPvQ6ZCIZbuQ1mnNpWVJt0j/L4znEGRSq4j+8G+q/aY92mF1bgt+i5Q2R1nEyHGLJn1o+/zjGVuJ2wyF792ilPaQgf1tknT1iiIJQ3FgtFb4TmkBXvszi7GscuIMyocWZoEU7Ts9UQy6C/ODqw1YlsBdW0Aobo9vmUDZSe5qc1Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784186527; c=relaxed/simple; bh=qizhEZaqPEQFBRoCJ2kjVTe4C6XQZBS8qGx5Db+TomI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=iWdCHykKMUs5qRzWzlw9JuH2wangHjRI7567v7Vx/IHU2IK3wxuKhwmMc4xWQ9e+J9bIgjBAci8AU5n+eb63y9hKNiBhfUhtLeMqxidWo2VE8WCoEOIXnWRMU9Zqd1TvfHvPmfzF0pWYpo7OZrZ2ngWyY8vHk17asVPhGMvpmIc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=kylinos.cn; spf=pass smtp.mailfrom=kylinos.cn; arc=none smtp.client-ip=124.126.103.232 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=kylinos.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=kylinos.cn X-UUID: 072d4c2e80e711f1aa26b74ffac11d73-20260716 X-CID-CACHE: Type:Local,Time:202607161511+08,HitQuantity:1 X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.3.12,REQID:790099af-de38-4e23-bd3a-d8d38218dcfe,IP:0,U RL:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:0 X-CID-META: VersionHash:e7bac3a,CLOUDID:5026b3d9e88eb68b1fa06eb1c6f46296,BulkI D:nil,BulkQuantity:0,Recheck:0,SF:81|82|102|850|865|898,TC:nil,Content:0|1 5|50,EDM:-3,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI :0,OSA:0,AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 2,SSN|SDN X-CID-BAS: 2,SSN|SDN,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-CID-RHF: D41D8CD98F00B204E9800998ECF8427E X-UUID: 072d4c2e80e711f1aa26b74ffac11d73-20260716 X-User: lihaofeng@kylinos.cn Received: from localhost.localdomain [(10.44.16.150)] by mailgw.kylinos.cn (envelope-from ) (Generic MTA with TLSv1.3 TLS_AES_256_GCM_SHA384 256/256) with ESMTP id 694100958; Thu, 16 Jul 2026 15:21:57 +0800 From: Haofeng Li To: aahringo@redhat.com, teigland@redhat.com Cc: gfs2@lists.linux.dev, linux-kernel@vger.kernel.org, Haofeng Li <13266079573@163.com>, Haofeng Li Subject: [PATCH 2/2] dlm: require CAP_SYS_ADMIN for dlm-monitor device Date: Thu, 16 Jul 2026 15:21:52 +0800 Message-Id: <20260716072152.326803-3-lihaofeng@kylinos.cn> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260716072152.326803-1-lihaofeng@kylinos.cn> References: <20260716072152.326803-1-lihaofeng@kylinos.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable monitor_device_open() in fs/dlm/user.c performs only atomic_inc(&dlm_monitor_opened) and sets dlm_monitor_unused =3D 0; it does no capability check. monitor_device_close() does atomic_dec_and_test(&dlm_monitor_opened) and, when the count reaches zero, calls dlm_stop_lockspaces() =E2=80=94 which stops every lockspace on the node. The miscdevice is also registered with no .mode field. Attack chain (when the device node is reachable by an unprivileged opener =E2=80=94 see mitigation note below): 1. attacker open("/dev/dlm-monitor") with no cap check; the global counter goes 0 -> 1 2. attacker close(fd); atomic_dec_and_test reaches zero again and dlm_stop_lockspaces() runs -> every DLM lockspace on the local node is stopped. Other cluster members then observe the node losing its lockspaces (membership / recovery side effects), so the impact is not strictly local to GFS2 / OCFS2 / lvmlockd / cluster-md workloads on this node. variant: attacker holds the fd open indefinitely to suppress the intended stop when dlm_controld later closes its own fd (inverse abuse =E2=80=94 recovery / shutdown stalls) Mitigation: devtmpfs creates /dev/dlm-monitor as 0600 root:root on a stock kernel, so unprivileged open is blocked by the node mode, not by a kernel cap check. The gap is real wherever the node is reachable (udev MODE=3D0666, container bind-mount, fd via SCM_RIGHTS, or any setup where dlm_controld shares its monitor fd). Reproduction (kernel 7.2.0-rc3, dlm loaded, no live lockspace): # ./exploit_h3 # as root [*] lockspace devices present: 0 [!!!] AUTH BYPASS: opened /dev/dlm-monitor, no cap check (fd=3D3) [VULNERABLE] monitor open auth bypass demonstrated $ setpriv --reuid 65534 --regid 65534 ./exploit_h3 [OK ] open denied: Permission denied # node 0600, not cap check The destructive close path is opt-in in the PoX (--i-know-it-stops-lockspaces); we did not drive it here. Driving the close path on a node with active lockspaces would stop them; on this throw-away node there are none, but we keep the opt-in gate so the same PoX is safe to re-run on production-like clusters. Fix: gate monitor_device_open() on capable(CAP_SYS_ADMIN) and set .mode =3D 0600 on monitor_device, matching the dlm_controld-only intended usage. Signed-off-by: Haofeng Li Acked-by: Alexander Aring --- fs/dlm/user.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/dlm/user.c b/fs/dlm/user.c index a8ed4c8fdc5b..cd7e142ca670 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -4,6 +4,7 @@ */ =20 #include +#include #include #include #include @@ -910,6 +911,10 @@ static int ctl_device_close(struct inode *inode, struc= t file *file) =20 static int monitor_device_open(struct inode *inode, struct file *file) { + /* dlm_controld is the only expected opener; last close stops LS. */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + atomic_inc(&dlm_monitor_opened); dlm_monitor_unused =3D 0; return 0; @@ -958,6 +963,7 @@ static struct miscdevice monitor_device =3D { .name =3D "dlm-monitor", .fops =3D &monitor_device_fops, .minor =3D MISC_DYNAMIC_MINOR, + .mode =3D 0600, }; =20 int __init dlm_user_init(void) --=20 2.25.1