Re: [PATCH v4 0/3] API for exporting connectable file handles to userspace

Amir Goldstein
2024-10-14T08:55:19Z

[-- Attachment #1: Type: text/plain, Size: 5147 bytes --]

On Fri, Oct 11, 2024 at 8:40 PM Chuck Lever III <chuck.lever@oracle.com> wrote:
>
>
>
> > On Oct 11, 2024, at 2:22 PM, Amir Goldstein <amir73il@gmail.com> wrote:
> >
> > On Fri, Oct 11, 2024 at 4:24 PM Chuck Lever III <chuck.lever@oracle.com> wrote:
> >>
> >>
> >>
> >>> On Oct 11, 2024, at 5:00 AM, Amir Goldstein <amir73il@gmail.com> wrote:
> >>>
> >>> Christian,
> >>>
> >>> These patches bring the NFS connectable file handles feature to
> >>> userspace servers.
> >>>
> >>> They rely on your and Aleksa's changes recently merged to v6.12.
> >>>
> >>> This v4 incorporates the review comments on Jeff and Jan (thanks!)
> >>> and there does not seem to be any objection for this new API, so
> >>> I think it is ready for staging.
> >>>
> >>> The API I chose for encoding conenctable file handles is pretty
> >>> conventional (AT_HANDLE_CONNECTABLE).
> >>>
> >>> open_by_handle_at(2) does not have AT_ flags argument, but also, I find
> >>> it more useful API that encoding a connectable file handle can mandate
> >>> the resolving of a connected fd, without having to opt-in for a
> >>> connected fd independently.
> >>>
> >>> I chose to implemnent this by using upper bits in the handle type field
> >>> It may be that out-of-tree filesystems return a handle type with upper
> >>> bits set, but AFAIK, no in-tree filesystem does that.
> >>> I added some warnings just in case we encouter that.
> >>>
> >>> I have written an fstest [4] and a man page draft [5] for the feature.
> >>>
> >>> Thanks,
> >>> Amir.
> >>>
> >>> Changes since v3 [3]:
> >>> - Relax WARN_ON in decode and replace with pr_warn in encode (Jeff)
> >>> - Loose the macro FILEID_USER_TYPE_IS_VALID() (Jan)
> >>> - Add explicit check for negative type values (Jan)
> >>> - Added fstest and man-page draft
> >>>
> >>> Changes since v2 [2]:
> >>> - Use bit arithmetics instead of bitfileds (Jeff)
> >>> - Add assertions about use of high type bits
> >>>
> >>> Changes since v1 [1]:
> >>> - Assert on encode for disconnected path (Jeff)
> >>> - Don't allow AT_HANDLE_CONNECTABLE with AT_EMPTY_PATH
> >>> - Drop the O_PATH mount_fd API hack (Jeff)
> >>> - Encode an explicit "connectable" flag in handle type
> >>>
> >>> [1] https://lore.kernel.org/linux-fsdevel/20240919140611.1771651-1-amir73il@gmail.com/
> >>> [2] https://lore.kernel.org/linux-fsdevel/20240923082829.1910210-1-amir73il@gmail.com/
> >>> [3] https://lore.kernel.org/linux-fsdevel/20241008152118.453724-1-amir73il@gmail.com/
> >>> [4] https://github.com/amir73il/xfstests/commits/connectable-fh/
> >>> [5] https://github.com/amir73il/man-pages/commits/connectable-fh/
> >>>
> >>> Amir Goldstein (3):
> >>> fs: prepare for "explicit connectable" file handles
> >>> fs: name_to_handle_at() support for "explicit connectable" file
> >>> handles
> >>> fs: open_by_handle_at() support for decoding "explicit connectable"
> >>> file handles
> >>>
> >>> fs/exportfs/expfs.c | 17 ++++++++-
> >>> fs/fhandle.c | 75 +++++++++++++++++++++++++++++++++++---
> >>> include/linux/exportfs.h | 13 +++++++
> >>> include/uapi/linux/fcntl.h | 1 +
> >>> 4 files changed, 98 insertions(+), 8 deletions(-)
> >>>
> >>> --
> >>> 2.34.1
> >>>
> >>
> >> Acked-by: Chuck Lever <chuck.lever@oracle.com <mailto:chuck.lever@oracle.com>>
> >>
> >> Assuming this is going directly to Christian's tree.
> >>
> >> I'm a little concerned about how this new facility might be
> >> abused to get access to parts of the file system that a user
> >> is not authorized to access.
> >
> > That's exactly the sort of thing I would like to be reviewed,
> > but what makes you feel concerned?
> >
> > Are you concerned about handcrafted file handles?
>
> Yes; a user could construct a file handle that could bypass
> the usual authorization checks when it gets connected. It's
> a little hare-brained and hand-wavy because this is a new
> area for me.
>

A malformed file handle is indeed a concern - it has always been,
but in order to exploit one, an attacker would actually need to have
a filesystem exported to nfs (to the attacking client machine).

With commit 620c266f3949 ("fhandle: relax open_by_handle_at()
permission checks"), attackers that have non-root access to a machine
could also try to exploit filesystem bugs with malformed file handles.

By adding support for connectable file handles, attackers could try
to exploit bugs in ->fh_to_parent() implementations - bugs that would
not have been exploitable so far unless filesystem is exported to nfs with
subtree_check, which is quite rare IIUC.

So I did an audit of the in-tree ->fh_to_{dentry,parent}() implementations.
AFAICT all implementations properly check buffer length before trying
to decode the handle... except for ceph.

It looks to me like __snapfh_to_dentry() does not check buffer length
before assuming that ceph_nfs_snapfh can be accessed.

Ilya,

Do you agree with my analysis?
Please see the attached fix patch.
Let me know if you want me to post it on ceph list or if that is sufficient.

Thanks,
Amir.

[-- Attachment #2: 0001-ceph-fix-bounds-check-for-decoding-fh-of-snapshot-fi.patch --]
[-- Type: text/x-patch, Size: 1233 bytes --]

From 229c0b6663eef65436031b782f858d02d5dec938 Mon Sep 17 00:00:00 2001
From: Amir Goldstein <amir73il@gmail.com>
Date: Mon, 14 Oct 2024 10:46:20 +0200
Subject: [PATCH] ceph: fix bounds check for decoding fh of snapshot file

Prevent attackers from using malformed ceph file handle with type
FILEID_BTRFS_WITH_PARENT to cause out of bounds access.

Fixes: 570df4e9c23f ("ceph: snapshot nfs re-export")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/ceph/export.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/fs/ceph/export.c b/fs/ceph/export.c
index 44451749c544..4a8d00e9910a 100644
--- a/fs/ceph/export.c
+++ b/fs/ceph/export.c
@@ -302,6 +302,8 @@ static struct dentry *ceph_fh_to_dentry(struct super_block *sb,

if (fh_type == FILEID_BTRFS_WITH_PARENT) {
struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
+ if (fh_len < sizeof(*sfh) / 4)
+ return NULL;
return __snapfh_to_dentry(sb, sfh, false);
}

@@ -422,6 +424,8 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,

if (fh_type == FILEID_BTRFS_WITH_PARENT) {
struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
+ if (fh_len < sizeof(*sfh) / 4)
+ return NULL;
return __snapfh_to_dentry(sb, sfh, true);
}

--
2.34.1