From nobody Mon Sep 28 11:40:00 2026 Received: from mail-ej1-f53.google.com (mail-ej1-f53.google.com [209.85.218.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F8363469F6 for ; Sat, 22 Aug 2026 12:29:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787401756; cv=none; b=O5nxCtV4pXjBDkj4nXDcv4f40cZPgvLLuWqqWaC4Lol9Ir0WIQ+xXUmjTITSf2SNG3upBsMsAMpuW2cG+mrhf8Y9OC8ryusiOFpNm3hgy6XX2io4Ixiq0SzmTwV1dKQKp7sogLs484y/WqyvVChdrm9hL1SEhd6f27sqp+sF13Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787401756; c=relaxed/simple; bh=4yHzd0/sD7uWBpqiQoo6tgH5+VFqqncgDUgCAHisFbU=; h=From:Content-Type:Mime-Version:Subject:Message-Id:Date:Cc:To; b=FC1snPbN5cdJ59m2iXVEIAwR6wg3fTXn/85pSCP2uwp6cwxDt6b/aEE2Q2Mby/nEJTkaOSR9Dzmvtv1DApByjjDX2kfjPmQH+QSxAHPrvovfdmnaQ0cWcFPdPPB8TIowe3yRx83GJVdAk2gEPHlm11vOrLAX2Sc4Vsihq7lYh0A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=doyensec.com; spf=pass smtp.mailfrom=doyensec.com; dkim=pass (2048-bit key) header.d=doyensec.com header.i=@doyensec.com header.b=LpNH3huC; arc=none smtp.client-ip=209.85.218.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=doyensec.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=doyensec.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=doyensec.com header.i=@doyensec.com header.b="LpNH3huC" Received: by mail-ej1-f53.google.com with SMTP id a640c23a62f3a-c160420289bso290163766b.0 for ; Sat, 22 Aug 2026 05:29:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=doyensec.com; s=google; t=1787401752; x=1788006552; darn=vger.kernel.org; h=to:cc:date:message-id:subject:mime-version :content-transfer-encoding:content-type:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=V7iKMrQWKrNcFUdtPEGrYqrgrtfQs5EtCDckx7iIZKg=; b=LpNH3huCo2K9HkJ0ovRFb7spQxXj+x+JTiRmAhLHbpHuvAWqrEhO/bI8RasRauLmPk Wvn0FdvvaGdm9KHtrVyom2xyO5pcD0UXpBquN8JaU0y9AaOqIKMPxjO7oQiO/qHmucF9 Gs5x13Xq1gHIhZVr9G+i73flJzH4j9AdVgnrVle5kmO6mcHy2ZYYK1WhpL+E+JIFH+Z4 WKh1RWYNKt4lhReJEgdh9r5oVf+2Lcb2ZEKhjaO51uzAAQKyKrYIZh2GFDHXgnQvBCwi dT864mc6DZFio4tqMSSh801Pgvc4yYWtXVQReZ7n4tGVVThXivOA4X2TrJDIYSSvNVaT aDsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787401752; x=1788006552; h=to:cc:date:message-id:subject:mime-version :content-transfer-encoding:content-type:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=V7iKMrQWKrNcFUdtPEGrYqrgrtfQs5EtCDckx7iIZKg=; b=LEUkaa2vmIXGsEPNp1r5Nntglrt4VugeRuzGAwt20i4izO6PlKS+B6DEOxK3nW2g7J cJ6UbswYrkdvi7MLDxUgYT7/QrBR2YZ7KY62d1TG3u3sDV8Jo1SuKRv5FgH0zRVFsTXQ 94RtlJlmVVU66HOuRM9C98JAloBgocfuX1DpqkLM4/mkK0VwnkqTOh8eHcAyaqLJ7gL2 TFJHd04NIoBYrw6QxeoYe9fIjUqcK/ZnCniwOQ/+qDodicVaCmmzamMUXPuQNb8Zed3K 8rTz7aT3uBSnZMY4KB7vRh/fe6OWpRD4ixhTaTdY/kRnLy03um2SnQSuKCq1DsCqUY2o la0w== X-Forwarded-Encrypted: i=1; AHgh+RoeH2vH4Czpc1ixRIgvIAJ92+/H8mGaCihGYDczv23DMUspL3cuacGFzrso4S6Xbp+mOYb+dGjhNGqckaw=@vger.kernel.org X-Gm-Message-State: AFuF++nBEs0HgGzljFnEjPZDonfY1txoKM7knIGqq4lA4oT7t5fyrzVC lzIMMLpztgH//pSaUwcsZeJAW+11M8unrtNVBhOrELcU25Fa5ICEKm/wMEpTMhkBVOwqDRVhHFm TcNsyHtmmuw== X-Gm-Gg: AR+sD12UQbtFSyD5IH3St+m6oAD25o/TEEWZvXWNif5rbH2CMB9eTBezGX9EjAo3D0L dcGGbLD7yizjYit67G4tovpO6ZbOe6q7bUKSJnhrpPnZEMDATS/rQbY70JNIT75qkstUI/ed1BW 2ozImoRe58p18ETkYRTq1Cl3iysDw2/lHeEhhyZNs/sW+T4tV90cfxjaniNohIhTTdK0ubowJtC cg4bkS6Mw+KBWd3tvK3mCkJkaD1nhM16uA5blf5hI3X/F2A7LRkFMmVh/mZZNRwEjchEiKqRuXB P8p442/fs8/gBbFpBtC91bJynww23/qmcpa2U/BDkM5C6CMJ3pCUy6xlK1xSTCzFatDOLPYQMs4 r6o4+zyrvgK84VKyncRyvWxd4uF86hypAxTJ6hg4SQxZlpQlVzYyjhbVbVdzv4d/MTIMDaoD1tS dwX/ZwsV9PW8vYr7jyUaKF5Ilxphc6Zxgrhtl2youIuz5e0otoyx6aIYfaT+Epny8Bk623aRghv XuPJ1dQCmow3DIR5fPDLYois13tYrBh4TWu9ULUi/VSvIaPZXqZCFkaxgw6ZPZr5BU12SOd5eH3 TporjsySB05scTyZOCLDNg== X-Received: by 2002:a17:906:eec1:b0:c21:61a6:8825 with SMTP id a640c23a62f3a-c246a72e5e4mr1468035066b.22.1787401752232; Sat, 22 Aug 2026 05:29:12 -0700 (PDT) Received: from smtpclient.apple (78-141-71-213.dynamic.orange.sk. [78.141.71.213]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c249606b60asm314268366b.9.2026.08.22.05.29.11 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 22 Aug 2026 05:29:11 -0700 (PDT) From: Norbert Szetei Content-Transfer-Encoding: quoted-printable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.700.81.1.4\)) Subject: [PATCH] landlock: Fix use-after-free of the source's parent directory Message-Id: Date: Sat, 22 Aug 2026 14:29:00 +0200 Cc: =?utf-8?Q?G=C3=BCnther_Noack?= , Paul Moore , James Morris , "Serge E. Hallyn" , linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org To: =?utf-8?Q?Micka=C3=ABl_Sala=C3=BCn?= X-Mailer: Apple Mail (2.3826.700.81.1.4) Content-Type: text/plain; charset="utf-8" current_check_refer_path() reads old_dentry->d_parent without holding a reference nor a lock on it, and then dereferences it in collect_domain_accesses() and in the audit record. A reference on a child does not pin its parent: __d_move() reassigns dentry->d_parent and drops the reference the child held on its former parent. hook_path_rename() is not affected because the rename path calls lock_rename() before the hook, so the source cannot be reparented under it. hook_path_link() has no such protection: do_linkat() holds a reference on the source dentry but neither locks nor references its parent, so a concurrent rename(2) can reparent the source while security_path_link() runs, and the former parent can then be removed and freed while the hook walks it. Any process able to sandbox itself with LANDLOCK_ACCESS_FS_REFER can trigger this with a linkat(2) loop racing rename(2) and rmdir(2): BUG: KASAN: slab-use-after-free in collect_domain_accesses+0x278/0x290 Read of size 4 at addr ffff888160bd53f4 by task llrepro2/549 collect_domain_accesses+0x278/0x290 current_check_refer_path+0x952/0x1120 security_path_link+0x1be/0x320 filename_linkat+0x342/0x6d0 __x64_sys_linkat+0xfa/0x150 Freed by task 562: kmem_cache_free+0x139/0x4c0 i_callback+0x4b/0x80 rcu_core+0x7dc/0x10a0 Take a reference on the parent with dget_parent(), and release it once the hierarchy walk and the audit record are done. Cc: stable@vger.kernel.org Fixes: b91c3e4ea756 ("landlock: Add support for file reparenting with LANDL= OCK_ACCESS_FS_REFER") Signed-off-by: Norbert Szetei Reviewed-by: G=C3=BCnther Noack Tested-by: G=C3=BCnther Noack --- security/landlock/fs.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/security/landlock/fs.c b/security/landlock/fs.c index 30aa6ce13590..200c83372bbe 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -1298,11 +1298,12 @@ static int current_check_refer_path(struct dentry *= const old_dentry, /* * old_dentry may be the root of the common mount point and * !IS_ROOT(old_dentry) at the same time (e.g. with open_tree() and - * OPEN_TREE_CLONE). We do not need to call dget(old_parent) because - * we keep a reference to old_dentry. + * OPEN_TREE_CLONE). Pins the parent in both cases: a reference on + * old_dentry does not pin its parent, which may then be freed after a + * concurrent rename(2). */ - old_parent =3D (old_dentry =3D=3D mnt_dir.dentry) ? old_dentry : - old_dentry->d_parent; + old_parent =3D (old_dentry =3D=3D mnt_dir.dentry) ? dget(old_dentry) : + dget_parent(old_dentry); =20 /* new_dir->dentry is equal to new_dentry->d_parent */ allow_parent1 =3D collect_domain_accesses(subject->domain, mnt_dir.dentry, @@ -1311,8 +1312,10 @@ static int current_check_refer_path(struct dentry *c= onst old_dentry, allow_parent2 =3D collect_domain_accesses(subject->domain, mnt_dir.dentry, new_dir->dentry, &layer_masks_parent2); - if (allow_parent1 && allow_parent2) + if (allow_parent1 && allow_parent2) { + dput(old_parent); return 0; + } =20 /* * To be able to compare source and destination domain access rights, @@ -1324,8 +1327,10 @@ static int current_check_refer_path(struct dentry *c= onst old_dentry, subject->domain, &mnt_dir, access_request_parent1, &layer_masks_parent1, &request1, old_dentry, access_request_parent2, &layer_masks_parent2, &request2, - exchange ? new_dentry : NULL)) + exchange ? new_dentry : NULL)) { + dput(old_parent); return 0; + } =20 if (request1.access) { request1.audit.u.path.dentry =3D old_parent; @@ -1335,6 +1340,7 @@ static int current_check_refer_path(struct dentry *co= nst old_dentry, request2.audit.u.path.dentry =3D new_dir->dentry; landlock_log_denial(subject, &request2); } + dput(old_parent); =20 /* * This prioritizes EACCES over EXDEV for all actions, including --=20 2.55.0