From: Ralph Boehme Date: Wed, 22 Jan 2025 11:34:31 +0000 (+0100) Subject: vfs_gpfs: add gpfs:clamp_invalid_times X-Git-Tag: samba-4.20.8~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=edb719760b192ddb7b2fca51b1f112f33933524d;p=thirdparty%2Fsamba.git vfs_gpfs: add gpfs:clamp_invalid_times The timestamp validation added as part of the fix for bug 15151 causes hard failures for certain clients that seem to use a temporary timestamp initially when creating files, changing in a later step. Clamp invalid timestamps to the allowed range 0..UINT32_MAX if "gpfs:clamp_invalid_times = yes" is set. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15151 Signed-off-by: Ralph Boehme Reviewed-by: Christof Schmitt Autobuild-User(master): Christof Schmitt Autobuild-Date(master): Wed Feb 5 23:42:15 UTC 2025 on atb-devel-224 (cherry picked from commit 0a48167044bb1ffd9e19cb2e23de9834d0551be1) --- diff --git a/docs-xml/manpages/vfs_gpfs.8.xml b/docs-xml/manpages/vfs_gpfs.8.xml index 29f2ac453f0..cee12cd3f94 100644 --- a/docs-xml/manpages/vfs_gpfs.8.xml +++ b/docs-xml/manpages/vfs_gpfs.8.xml @@ -316,6 +316,35 @@ + + gpfs:clamp_invalid_times = [ yes | no ] + + + GPFS stores timestamps using 32-bit unsigned integers for the + seconds component. When using gpfs:settimes = yes, this module + validates times that clients attempt to set are within the + supported GPFS range between 0 and UINT32_MAX. If a timestamp is + outside of this range, the client request is rejected. To cope + with clients setting eg temporary timestamps outside the valid + range, this parameter can be used to clamp the client timestamp + to the allowed range. Times before Thu Jan 1 12:00:00 AM UTC + 1970 (the UNIX epock) are then set to Thu Jan 1 12:00:00 AM UTC + 1970, times after Sun Feb 7 06:28:15 AM UTC 2106 will be set to + Sun Feb 7 06:28:15 AM UTC 2106. + + + + + no(default) - Fail request with invalid time. + + + yes - clamp invalid times to 0 or UINT32_MAX. + + + + + + gpfs:syncio = [yes|no] diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index a8b4e38ff88..5cac0deb7f7 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -55,6 +55,7 @@ struct gpfs_config_data { bool acl; bool settimes; bool recalls; + bool clamp_invalid_times; struct { bool gpfs_fstat_x; } pathref_ok; @@ -1588,19 +1589,29 @@ static NTSTATUS vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct *handle, return NT_STATUS_OK; } -static int timespec_to_gpfs_time( - struct timespec ts, gpfs_timestruc_t *gt, int idx, int *flags) +static int timespec_to_gpfs_time(struct gpfs_config_data *config, + struct timespec ts, + gpfs_timestruc_t *gt, + int idx, + int *flags) { if (is_omit_timespec(&ts)) { return 0; } if (ts.tv_sec < 0 || ts.tv_sec > UINT32_MAX) { - DBG_NOTICE("GPFS uses 32-bit unsigned timestamps " - "and cannot handle %jd.\n", - (intmax_t)ts.tv_sec); - errno = ERANGE; - return -1; + if (!config->clamp_invalid_times) { + DBG_NOTICE("GPFS uses 32-bit unsigned timestamps " + "and cannot handle %jd.\n", + (intmax_t)ts.tv_sec); + errno = ERANGE; + return -1; + } + if (ts.tv_sec < 0) { + ts.tv_sec = 0; + } else { + ts.tv_sec = UINT32_MAX; + } } *flags |= 1 << idx; @@ -1611,7 +1622,8 @@ static int timespec_to_gpfs_time( return 0; } -static int smbd_gpfs_set_times(struct files_struct *fsp, +static int smbd_gpfs_set_times(struct gpfs_config_data *config, + struct files_struct *fsp, struct smb_file_time *ft) { gpfs_timestruc_t gpfs_times[4]; @@ -1619,18 +1631,22 @@ static int smbd_gpfs_set_times(struct files_struct *fsp, int rc; ZERO_ARRAY(gpfs_times); - rc = timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags); + rc = timespec_to_gpfs_time(config, ft->atime, gpfs_times, 0, &flags); if (rc != 0) { return rc; } - rc = timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags); + rc = timespec_to_gpfs_time(config, ft->mtime, gpfs_times, 1, &flags); if (rc != 0) { return rc; } /* No good mapping from LastChangeTime to ctime, not storing */ - rc = timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags); + rc = timespec_to_gpfs_time(config, + ft->create_time, + gpfs_times, + 3, + &flags); if (rc != 0) { return rc; } @@ -1696,7 +1712,7 @@ static int vfs_gpfs_fntimes(struct vfs_handle_struct *handle, /* Try to use gpfs_set_times if it is enabled and available */ if (config->settimes) { - return smbd_gpfs_set_times(fsp, ft); + return smbd_gpfs_set_times(config, fsp, ft); } DBG_DEBUG("gpfs_set_times() not available or disabled, " @@ -2048,6 +2064,9 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle, config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs", "recalls", true); + config->clamp_invalid_times = lp_parm_bool(SNUM(handle->conn), "gpfs", + "clamp_invalid_times", false); + ret = vfs_gpfs_check_pathref(config, handle->conn); if (ret != 0) { DBG_ERR("vfs_gpfs_check_pathref() on [%s] failed\n",