]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_gpfs: add gpfs:clamp_invalid_times
authorRalph Boehme <slow@samba.org>
Wed, 22 Jan 2025 11:34:31 +0000 (12:34 +0100)
committerJule Anger <janger@samba.org>
Mon, 17 Feb 2025 16:09:09 +0000 (16:09 +0000)
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 <slow@samba.org>
Reviewed-by: Christof Schmitt <cs@samba.org>
Autobuild-User(master): Christof Schmitt <cs@samba.org>
Autobuild-Date(master): Wed Feb  5 23:42:15 UTC 2025 on atb-devel-224

(cherry picked from commit 0a48167044bb1ffd9e19cb2e23de9834d0551be1)

docs-xml/manpages/vfs_gpfs.8.xml
source3/modules/vfs_gpfs.c

index 29f2ac453f06dd78f1a86c0c3d8ab00a109dd25a..cee12cd3f94463f4fb46b7c97c9b2cc5f09bf1d5 100644 (file)
 
                </varlistentry>
 
+               <varlistentry>
+               <term>gpfs:clamp_invalid_times = [ yes | no ]</term>
+               <listitem>
+               <para>
+               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.
+               </para>
+
+               <itemizedlist>
+               <listitem><para>
+               <command>no(default)</command> - Fail request with invalid time.
+               </para></listitem>
+               <listitem><para>
+               <command>yes</command> - clamp invalid times to 0 or UINT32_MAX.
+               </para></listitem>
+               </itemizedlist>
+               </listitem>
+               </varlistentry>
+
+
                <varlistentry>
                <term>gpfs:syncio = [yes|no]</term>
                <listitem>
index a8b4e38ff88c00c61285258f92c4f4a67de152a2..5cac0deb7f72dade36ad6b263e158924e2ac17de 100644 (file)
@@ -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",