s4:ntvfs: Avoid signed integer overflow
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Mon, 4 Sep 2023 04:49:48 +0000 (16:49 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 25 Oct 2023 22:23:37 +0000 (22:23 +0000)
Signed integer overflow is undefined behaviour.

ubsan reports errors similar to the following:
signed integer overflow: 9223372036854775807 + 2147483682 cannot be represented in type 'long int'

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/ntvfs/posix/pvfs_dirlist.c

index a503404015414b218f6eb2dd13f355f857f2770a..3cf3d00d7ab3dc031a00b147640776c1bf6dc9be 100644 (file)
@@ -242,7 +242,8 @@ const char *pvfs_list_next(struct pvfs_dir *dir, off_t *ofs)
                        talloc_free(short_name);
                }
 
-               dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE;
+               /* Casting is necessary to avoid signed integer overflow. */
+               dir->offset = (unsigned long)telldir(dir->dir) + (unsigned long)DIR_OFFSET_BASE;
                (*ofs) = dir->offset;
 
                dcache_add(dir, dname);
@@ -311,7 +312,8 @@ NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, off_t *ofs)
 
        while ((de = readdir(dir->dir))) {
                if (strcasecmp_m(name, de->d_name) == 0) {
-                       dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE;
+                       /* Casting is necessary to avoid signed integer overflow. */
+                       dir->offset = (unsigned long)telldir(dir->dir) + (unsigned long)DIR_OFFSET_BASE;
                        *ofs = dir->offset;
                        return NT_STATUS_OK;
                }
@@ -348,7 +350,8 @@ NTSTATUS pvfs_list_seek_ofs(struct pvfs_dir *dir, uint32_t resume_key, off_t *of
                        dir->end_of_search = true;
                        return NT_STATUS_OBJECT_NAME_NOT_FOUND;
                }
-               *ofs = telldir(dir->dir) + DIR_OFFSET_BASE;
+               /* Casting is necessary to avoid signed integer overflow. */
+               *ofs = (unsigned long)telldir(dir->dir) + (unsigned long)DIR_OFFSET_BASE;
                dir->offset = *ofs;
                return NT_STATUS_OK;
        }
@@ -371,7 +374,8 @@ NTSTATUS pvfs_list_seek_ofs(struct pvfs_dir *dir, uint32_t resume_key, off_t *of
        rewinddir(dir->dir);
 
        while ((de = readdir(dir->dir))) {
-               dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE;
+               /* Casting is necessary to avoid signed integer overflow. */
+               dir->offset = (unsigned long)telldir(dir->dir) + (unsigned long)DIR_OFFSET_BASE;
                if (resume_key == (uint32_t)dir->offset) {
                        *ofs = dir->offset;
                        return NT_STATUS_OK;