From 86f8d95bb1e2e5e905bbc0a09c9d022476dce5ba Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 6 Aug 2021 12:03:38 +0200 Subject: [PATCH 1/7] vfs_gpfs: call SMB_VFS_NEXT_CONNECT() before running some module initialization code No change in behaviour. Prepares for a subsequent commit that checks for IPC shares. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14771 Signed-off-by: Ralph Boehme Reviewed-by: Christof Schmitt (cherry picked from commit 145e739c440d39651d4f3d30682035ab868488ba) --- source3/modules/vfs_gpfs.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 172194dbead..fbd35ac18df 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -2086,6 +2086,11 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle, int ret; bool check_fstype; + ret = SMB_VFS_NEXT_CONNECT(handle, service, user); + if (ret < 0) { + return ret; + } + gpfswrap_lib_init(0); config = talloc_zero(handle->conn, struct gpfs_config_data); @@ -2095,12 +2100,6 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle, return -1; } - ret = SMB_VFS_NEXT_CONNECT(handle, service, user); - if (ret < 0) { - TALLOC_FREE(config); - return ret; - } - check_fstype = lp_parm_bool(SNUM(handle->conn), "gpfs", "check_fstype", true); -- 2.31.1 From 92e0d29bc32c07e616cbac1399b2f936119483ce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 11 Aug 2021 16:23:24 +0200 Subject: [PATCH 2/7] vfs_gpfs: don't check for struct gpfs_config_data in vfs_gpfs_[l]stat() This is unused and the config object won't be avilable for IPC$ anymore with the next commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14771 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme Reviewed-by: Christof Schmitt (cherry picked from commit 070dce224bbe190266682c5e362bc2b0ed798ecc) --- source3/modules/vfs_gpfs.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index fbd35ac18df..15ac7b4608e 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1831,11 +1831,6 @@ static int vfs_gpfs_stat(struct vfs_handle_struct *handle, struct smb_filename *smb_fname) { int ret; - struct gpfs_config_data *config; - - SMB_VFS_HANDLE_GET_DATA(handle, config, - struct gpfs_config_data, - return -1); ret = SMB_VFS_NEXT_STAT(handle, smb_fname); if (ret == -1 && errno == EACCES) { @@ -1850,11 +1845,6 @@ static int vfs_gpfs_lstat(struct vfs_handle_struct *handle, struct smb_filename *smb_fname) { int ret; - struct gpfs_config_data *config; - - SMB_VFS_HANDLE_GET_DATA(handle, config, - struct gpfs_config_data, - return -1); ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); if (ret == -1 && errno == EACCES) { -- 2.31.1 From 4d31ac635fbc67e6baea9ed46fe1dd523fefe010 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 6 Aug 2021 12:05:44 +0200 Subject: [PATCH 3/7] vfs_gpfs: make vfs_gpfs_connect() a no-op on IPC shares We don't ever expect any filesystem IO operations to be called on an IPC shares, so there's no need to initialize the module here. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14771 Signed-off-by: Ralph Boehme Reviewed-by: Christof Schmitt (cherry picked from commit 1a3ac7a940fbb4ad8575ee3b0c56c9de2bf4b1f6) --- source3/modules/vfs_gpfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 15ac7b4608e..2cbb966d844 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -2081,6 +2081,10 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle, return ret; } + if (IS_IPC(handle->conn)) { + return 0; + } + gpfswrap_lib_init(0); config = talloc_zero(handle->conn, struct gpfs_config_data); @@ -2093,7 +2097,7 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle, check_fstype = lp_parm_bool(SNUM(handle->conn), "gpfs", "check_fstype", true); - if (check_fstype && !IS_IPC(handle->conn)) { + if (check_fstype) { const char *connectpath = handle->conn->connectpath; struct statfs buf = { 0 }; -- 2.31.1 From 8b75095916e8baa46952dddcb29cf40b83fa2844 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 29 Jul 2021 15:53:04 +0200 Subject: [PATCH 4/7] vfs_gpfs: check for O_PATH support in gpfswrap_fstat_x() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14771 Signed-off-by: Ralph Boehme Reviewed-by: Christof Schmitt (cherry picked from commit 730f8c49a9bc8333f0b722ad65e4e587421c21ec) --- source3/modules/vfs_gpfs.c | 73 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 2cbb966d844..ee013127c72 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -55,6 +55,9 @@ struct gpfs_config_data { bool acl; bool settimes; bool recalls; + struct { + bool gpfs_fstat_x; + } pathref_ok; }; struct gpfs_fsp_extension { @@ -2069,6 +2072,68 @@ static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd, return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n); } +#ifdef O_PATH +static int vfs_gpfs_check_pathref_fstat_x(struct gpfs_config_data *config, + struct connection_struct *conn) +{ + struct gpfs_iattr64 iattr = {0}; + unsigned int litemask; + int saved_errno; + int fd; + int ret; + + fd = open(conn->connectpath, O_PATH); + if (fd == -1) { + DBG_ERR("openat() of share with O_PATH failed: %s\n", + strerror(errno)); + return -1; + } + + ret = gpfswrap_fstat_x(fd, &litemask, &iattr, sizeof(iattr)); + if (ret == 0) { + close(fd); + config->pathref_ok.gpfs_fstat_x = true; + return 0; + } + + saved_errno = errno; + ret = close(fd); + if (ret != 0) { + DBG_ERR("close failed: %s\n", strerror(errno)); + return -1; + } + + if (saved_errno != EBADF) { + DBG_ERR("gpfswrap_fstat_x() of O_PATH handle failed: %s\n", + strerror(saved_errno)); + return -1; + } + + return 0; +} +#endif + +static int vfs_gpfs_check_pathref(struct gpfs_config_data *config, + struct connection_struct *conn) +{ +#ifndef O_PATH + /* + * This code path leaves all struct gpfs_config_data.pathref_ok members + * initialized to false. + */ + return 0; +#else + int ret; + + ret = vfs_gpfs_check_pathref_fstat_x(config, conn); + if (ret != 0) { + return -1; + } + + return 0; +#endif +} + static int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service, const char *user) { @@ -2158,6 +2223,14 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle, config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs", "recalls", true); + ret = vfs_gpfs_check_pathref(config, handle->conn); + if (ret != 0) { + DBG_ERR("vfs_gpfs_check_pathref() on [%s] failed\n", + handle->conn->connectpath); + TALLOC_FREE(config); + return -1; + } + SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct gpfs_config_data, return -1); -- 2.31.1 From 5a7a108d502f77a6ee96fa5ea99a5c8872ef212e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 29 Jul 2021 19:28:14 +0200 Subject: [PATCH 5/7] vfs_gpfs: add path based fallback for gpfswrap_fstat_x() on pathref handles BUG: https://bugzilla.samba.org/show_bug.cgi?id=14771 Signed-off-by: Ralph Boehme Reviewed-by: Christof Schmitt (cherry picked from commit fde1b98143568fc816165502583f72e73b5d6b71) --- source3/modules/vfs_gpfs.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index ee013127c72..ad159498e3d 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1651,6 +1651,9 @@ static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle, uint32_t *dosmode) { struct gpfs_config_data *config; + int fd = fsp_get_pathref_fd(fsp); + char buf[PATH_MAX]; + const char *p = NULL; struct gpfs_iattr64 iattr = { }; unsigned int litemask; struct timespec ts; @@ -1666,7 +1669,22 @@ static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle, return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode); } - ret = gpfswrap_fstat_x(fsp_get_pathref_fd(fsp), &litemask, &iattr, sizeof(iattr)); + if (fsp->fsp_flags.is_pathref && !config->pathref_ok.gpfs_fstat_x) { + if (fsp->fsp_flags.have_proc_fds) { + p = sys_proc_fd_path(fd, buf, sizeof(buf)); + if (p == NULL) { + return NT_STATUS_NO_MEMORY; + } + } else { + p = fsp->fsp_name->base_name; + } + } + + if (p != NULL) { + ret = gpfswrap_stat_x(p, &litemask, &iattr, sizeof(iattr)); + } else { + ret = gpfswrap_fstat_x(fd, &litemask, &iattr, sizeof(iattr)); + } if (ret == -1 && errno == ENOSYS) { return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode); } @@ -1683,8 +1701,17 @@ static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle, set_effective_capability(DAC_OVERRIDE_CAPABILITY); - ret = gpfswrap_fstat_x(fsp_get_pathref_fd(fsp), &litemask, - &iattr, sizeof(iattr)); + if (p != NULL) { + ret = gpfswrap_stat_x(p, + &litemask, + &iattr, + sizeof(iattr)); + } else { + ret = gpfswrap_fstat_x(fd, + &litemask, + &iattr, + sizeof(iattr)); + } if (ret == -1) { saved_errno = errno; } -- 2.31.1 From 4ff513f400498a4043d13b76bc78a731c03ea433 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 13 Aug 2021 11:39:05 +0200 Subject: [PATCH 6/7] vfs_gpfs: remove ENOSYS fallback from vfs_gpfs_fset_dos_attributes() This API call has existed for a long time, so we can safely assume that this always works. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14771 Pair-Programmed-With: Christof Schmitt Signed-off-by: Ralph Boehme Signed-off-by: Christof Schmitt (cherry picked from commit 3679f54f178ba6ddb940cc66f701e9b3a1dd543d) --- source3/modules/vfs_gpfs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index ad159498e3d..2ed62602fda 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1796,13 +1796,9 @@ static NTSTATUS vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct *handle, } attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode); + ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp), GPFS_WINATTR_SET_ATTRS, &attrs); - - if (ret == -1 && errno == ENOSYS) { - return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode); - } - if (ret == -1) { DBG_WARNING("Setting winattrs failed for %s: %s\n", fsp->fsp_name->base_name, strerror(errno)); -- 2.31.1 From 4088125b1c1da11dd8b53d0931700d9226180a2f Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 1 Jul 2021 16:08:02 +0200 Subject: [PATCH 7/7] vfs_gpfs: add sys_proc_fd_path() fallback to vfs_gpfs_fset_dos_attributes() gpfs_set_winattrs() is a modifying operation, my expectation thus is that it is not allowed on pathref (O_PATH) handles even though a recent Linux kernel commit 44a3b87444058b2cb055092cdebc63858707bf66 allowed calling utimensat() on pathref handles. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14771 RN: Some VFS operations on pathref (O_PATH) handles fail on GPFS Signed-off-by: Ralph Boehme Reviewed-by: Christof Schmitt (cherry picked from commit 882a466ea5f45e5e2197f2408ccd560383e13c3f) --- source3/modules/vfs_gpfs.c | 44 ++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 2ed62602fda..8f4791f78d3 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1797,11 +1797,47 @@ static NTSTATUS vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct *handle, attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode); - ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp), - GPFS_WINATTR_SET_ATTRS, &attrs); + if (!fsp->fsp_flags.is_pathref) { + ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp), + GPFS_WINATTR_SET_ATTRS, &attrs); + if (ret == -1) { + DBG_WARNING("Setting winattrs failed for %s: %s\n", + fsp_str_dbg(fsp), strerror(errno)); + return map_nt_error_from_unix(errno); + } + return NT_STATUS_OK; + } + + if (fsp->fsp_flags.have_proc_fds) { + int fd = fsp_get_pathref_fd(fsp); + const char *p = NULL; + char buf[PATH_MAX]; + + p = sys_proc_fd_path(fd, buf, sizeof(buf)); + if (p == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ret = gpfswrap_set_winattrs_path(p, + GPFS_WINATTR_SET_ATTRS, + &attrs); + if (ret == -1) { + DBG_WARNING("Setting winattrs failed for [%s][%s]: %s\n", + p, fsp_str_dbg(fsp), strerror(errno)); + return map_nt_error_from_unix(errno); + } + return NT_STATUS_OK; + } + + /* + * This is no longer a handle based call. + */ + ret = gpfswrap_set_winattrs_path(fsp->fsp_name->base_name, + GPFS_WINATTR_SET_ATTRS, + &attrs); if (ret == -1) { - DBG_WARNING("Setting winattrs failed for %s: %s\n", - fsp->fsp_name->base_name, strerror(errno)); + DBG_WARNING("Setting winattrs failed for [%s]: %s\n", + fsp_str_dbg(fsp), strerror(errno)); return map_nt_error_from_unix(errno); } -- 2.31.1