From: Steve Dickson <steved@redhat.com>
To: Linux NFS Mailing list <linux-nfs@vger.kernel.org>
Subject: [PATCH 2/4] mountd: Separate lookup of the exported directory and the mount path
Date: Thu, 5 Mar 2026 10:59:46 -0500 [thread overview]
Message-ID: <20260305155948.11261-3-steved@redhat.com> (raw)
In-Reply-To: <20260305155948.11261-1-steved@redhat.com>
From: Trond Myklebust <trond.myklebust@hammerspace.com>
When the caller asks to mount a path that does not terminate with an
exported directory, we want to split up the lookups so that we can
look up the exported directory using the mountd privileged credential,
and the remaining subdirectory lookups using the RPC caller's
credential.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
---
support/include/nfsd_path.h | 1 +
support/misc/nfsd_path.c | 31 ++++++++++++++++++
utils/mountd/mountd.c | 63 +++++++++++++++++++++++++++++++------
3 files changed, 86 insertions(+), 9 deletions(-)
diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h
index f600fb5a..3e5a2f5d 100644
--- a/support/include/nfsd_path.h
+++ b/support/include/nfsd_path.h
@@ -18,6 +18,7 @@ char * nfsd_path_prepend_dir(const char *dir, const char *pathname);
int nfsd_path_stat(const char *pathname, struct stat *statbuf);
int nfsd_path_lstat(const char *pathname, struct stat *statbuf);
+int nfsd_openat(int dirfd, const char *path, int flags);
int nfsd_path_statfs(const char *pathname,
struct statfs *statbuf);
diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
index caec33ca..dfe88e4f 100644
--- a/support/misc/nfsd_path.c
+++ b/support/misc/nfsd_path.c
@@ -203,6 +203,37 @@ nfsd_realpath(const char *path, char *resolved_buf)
return realpath_buf.res_ptr;
}
+struct nfsd_openat_t {
+ const char *path;
+ int dirfd;
+ int flags;
+ int res_fd;
+ int res_error;
+};
+
+static void nfsd_openatfunc(void *data)
+{
+ struct nfsd_openat_t *d = data;
+
+ d->res_fd = openat(d->dirfd, d->path, d->flags);
+ if (d->res_fd == -1)
+ d->res_error = errno;
+}
+
+int nfsd_openat(int dirfd, const char *path, int flags)
+{
+ struct nfsd_openat_t open_buf = {
+ .path = path,
+ .dirfd = dirfd,
+ .flags = flags,
+ };
+
+ nfsd_run_task(nfsd_openatfunc, &open_buf);
+ if (open_buf.res_fd == -1)
+ errno = open_buf.res_error;
+ return open_buf.res_fd;
+}
+
struct nfsd_rw_data {
int fd;
void* buf;
diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
index 39afd4aa..f43ebef5 100644
--- a/utils/mountd/mountd.c
+++ b/utils/mountd/mountd.c
@@ -392,7 +392,10 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
struct nfs_fh_len *fh;
char rpath[MAXPATHLEN+1];
char *p = *path;
+ char *subpath;
char buf[INET6_ADDRSTRLEN];
+ size_t epathlen;
+ int dirfd;
if (*p == '\0')
p = "/";
@@ -412,12 +415,21 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
*error = MNT3ERR_ACCES;
return NULL;
}
- if (nfsd_path_stat(exp->m_export.e_path, &estb) < 0) {
- xlog(L_WARNING, "can't stat export point %s: %s",
+
+ dirfd = nfsd_openat(AT_FDCWD, exp->m_export.e_path, O_PATH);
+ if (dirfd == -1) {
+ xlog(L_WARNING, "can't open export point %s: %s",
p, strerror(errno));
*error = MNT3ERR_NOENT;
return NULL;
}
+ if (fstat(dirfd, &estb) == -1) {
+ xlog(L_WARNING, "can't stat export point %s: %s",
+ p, strerror(errno));
+ *error = MNT3ERR_ACCES;
+ close(dirfd);
+ return NULL;
+ }
if (exp->m_export.e_mountpoint &&
!check_is_mountpoint(exp->m_export.e_mountpoint[0]?
exp->m_export.e_mountpoint:
@@ -426,18 +438,51 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
xlog(L_WARNING, "request to export an unmounted filesystem: %s",
p);
*error = MNT3ERR_NOENT;
+ close(dirfd);
return NULL;
}
- if (nfsd_path_stat(p, &stb) < 0) {
- xlog(L_WARNING, "can't stat exported dir %s: %s",
- p, strerror(errno));
- if (errno == ENOENT)
- *error = MNT3ERR_NOENT;
- else
- *error = MNT3ERR_ACCES;
+ epathlen = strlen(exp->m_export.e_path);
+ if (epathlen > strlen(p)) {
+ xlog(L_WARNING, "raced with change of exported path: %s", p);
+ *error = MNT3ERR_NOENT;
+ close(dirfd);
return NULL;
}
+ subpath = &p[epathlen];
+ while (*subpath == '/')
+ subpath++;
+ if (*subpath != '\0') {
+ int fd;
+
+ /* Just perform a lookup of the path */
+ fd = nfsd_openat(dirfd, subpath, O_PATH);
+ close(dirfd);
+ if (fd == -1) {
+ xlog(L_WARNING, "can't open exported dir %s: %s", p,
+ strerror(errno));
+ if (errno == ENOENT)
+ *error = MNT3ERR_NOENT;
+ else
+ *error = MNT3ERR_ACCES;
+ return NULL;
+ }
+ if (fstat(fd, &stb) == -1) {
+ xlog(L_WARNING, "can't open exported dir %s: %s", p,
+ strerror(errno));
+ if (errno == ENOENT)
+ *error = MNT3ERR_NOENT;
+ else
+ *error = MNT3ERR_ACCES;
+ close(fd);
+ return NULL;
+ }
+ close(fd);
+ } else {
+ close(dirfd);
+ stb = estb;
+ }
+
if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
xlog(L_WARNING, "%s is not a directory or regular file", p);
*error = MNT3ERR_NOTDIR;
--
2.53.0
next prev parent reply other threads:[~2026-03-05 15:59 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-05 15:59 [PATCH 0/4] rpc.mountd CVE-2025-12801 announcement Steve Dickson
2026-03-05 15:59 ` [PATCH 1/4] mountd: Minor refactor of get_rootfh() Steve Dickson
2026-03-05 15:59 ` Steve Dickson [this message]
2026-03-05 15:59 ` [PATCH 3/4] support: Add a mini-library to extract and apply RPC credentials Steve Dickson
2026-03-05 15:59 ` [PATCH 4/4] Fix access checks when mounting subdirectories in NFSv3 Steve Dickson
2026-03-07 18:07 ` [PATCH 0/4] rpc.mountd CVE-2025-12801 announcement Steve Dickson
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=20260305155948.11261-3-steved@redhat.com \
--to=steved@redhat.com \
--cc=linux-nfs@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox