FAILED: patch "[PATCH] ceph: bound copied dentry name length in NFS export get_name" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x eff8013c5a8916613c742ae5a2cc341cb605c0ae
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090318-makeover-speller-4b35@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From eff8013c5a8916613c742ae5a2cc341cb605c0ae Mon Sep 17 00:00:00 2001
From: Michael Bommarito <[email protected]>
Date: Sat, 11 Jul 2026 11:07:05 -0400
Subject: [PATCH] ceph: bound copied dentry name length in NFS export get_name
ceph_get_name() copies the MDS-supplied name into the caller's NAME_MAX-sized buffer with memcpy(name, rinfo->dname, rinfo->dname_len) and then writes name[rinfo->dname_len] = 0, without checking dname_len against NAME_MAX. A malicious or buggy MDS that returns a LOOKUPNAME reply with dname_len > NAME_MAX overflows the buffer. __get_snap_name() copies rde->name / rde->name_len the same unchecked way.
Impact: a malicious or compromised Ceph MDS overflows the NAME_MAX name buffer in a client's NFS-export get_name path, a slab out-of-bounds write reported by KASAN. Reachable when a CephFS mount is re-exported over NFS.
Add ceph_export_copy_name(), which rejects lengths above NAME_MAX with -ENAMETOOLONG before the copy, and use it in both ceph_get_name() and __get_snap_name().
fs/ceph/export.c +17 -9
@@ -442,6 +442,16 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,return dentry; } +static int ceph_export_copy_name (char *name,const char *src,u32 len) +{ +if (len >NAME_MAX ) +return -ENAMETOOLONG ; + +memcpy (name, src, len); + name[len] ='\0' ; +return 0 ; +} +static int __get_snap_name (struct dentry *parent,char *name,struct dentry *child) {
@@ -513,9 +523,8 @@ static int __get_snap_name(struct dentry *parent, char *name,BUG_ON (!rde->inode.in);if (ceph_snap (inode) ==le64_to_cpu (rde->inode.in->snapid)) { -memcpy (name, rde->name, rde->name_len); - name[rde->name_len] ='\0' ; - err =0 ; + err =ceph_export_copy_name (name, rde->name, + rde->name_len); goto out; } }
@@ -580,8 +589,8 @@ static int ceph_get_name(struct dentry *parent, char *name, rinfo = &req->r_reply_info;if (!IS_ENCRYPTED (dir)) { -memcpy (name, rinfo->dname, rinfo->dname_len); - name[rinfo->dname_len] =0 ; + err =ceph_export_copy_name (name, rinfo->dname, + rinfo->dname_len); }else {struct fscrypt_str oname =FSTR_INIT (NULL ,0 );struct ceph_fname fname = { .dir = dir,
@@ -595,10 +604,9 @@ static int ceph_get_name(struct dentry *parent, char *name, goto out; err =ceph_fname_to_usr (&fname,NULL , &oname,NULL ); -if (!err) { -memcpy (name, oname.name, oname.len); - name[oname.len] =0 ; - } +if (!err) + err =ceph_export_copy_name (name, oname.name, + oname.len);ceph_fname_free_buffer (dir, &oname); } out:
Sasha Levin
maintainerPATCH 1/1 ceph: bound copied dentry name length in NFS export get_name
From: Michael Bommarito <[email protected]>
[ Upstream commit eff8013c5a8916613c742ae5a2cc341cb605c0ae ]
ceph_get_name() copies the MDS-supplied name into the caller's NAME_MAX-sized buffer with memcpy(name, rinfo->dname, rinfo->dname_len) and then writes name[rinfo->dname_len] = 0, without checking dname_len against NAME_MAX. A malicious or buggy MDS that returns a LOOKUPNAME reply with dname_len > NAME_MAX overflows the buffer. __get_snap_name() copies rde->name / rde->name_len the same unchecked way.
Impact: a malicious or compromised Ceph MDS overflows the NAME_MAX name buffer in a client's NFS-export get_name path, a slab out-of-bounds write reported by KASAN. Reachable when a CephFS mount is re-exported over NFS.
Add ceph_export_copy_name(), which rejects lengths above NAME_MAX with -ENAMETOOLONG before the copy, and use it in both ceph_get_name() and __get_snap_name().
--- fs/ceph/export.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
fs/ceph/export.c +18 -5
@@ -422,6 +422,16 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,return dentry; } +static int ceph_export_copy_name (char *name,const char *src,u32 len) +{ +if (len >NAME_MAX ) +return -ENAMETOOLONG ; + +memcpy (name, src, len); + name[len] ='\0' ; +return 0 ; +} +static int __get_snap_name (struct dentry *parent,char *name,struct dentry *child) {
@@ -487,9 +497,8 @@ static int __get_snap_name(struct dentry *parent, char *name,BUG_ON (!rde->inode.in);if (ceph_snap (inode) ==le64_to_cpu (rde->inode.in->snapid)) { -memcpy (name, rde->name, rde->name_len); - name[rde->name_len] ='\0' ; - err =0 ; + err =ceph_export_copy_name (name, rde->name, + rde->name_len); goto out; } }
@@ -551,8 +560,12 @@ static int ceph_get_name(struct dentry *parent, char *name,if (!err) {struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info; -memcpy (name, rinfo->dname, rinfo->dname_len); - name[rinfo->dname_len] =0 ; + + err =ceph_export_copy_name (name, rinfo->dname, + rinfo->dname_len); + } + +if (!err) {dout ("get_name %p ino %llx.%llx name %s\n" , child,ceph_vinop (inode), name); }else {
Signature · 1 line
2.53.0