vfs_fruit: avoid dereferencing fsp->base_fsp in fruit_fstat_meta_stream()
[amitay/samba.git] / source3 / modules / vfs_fruit.c
index efe88efcaeb307ce3c18d33a837df92cc492d44c..19101efba740ce6de504cc97c2219add7101c34d 100644 (file)
@@ -4534,6 +4534,12 @@ static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle,
        }
 
        if (ai_empty_finderinfo(ai)) {
+               /*
+                * Writing an all 0 blob to the metadata stream results in the
+                * stream being removed on a macOS server. This ensures we
+                * behave the same and it verified by the "delete AFP_AfpInfo by
+                * writing all 0" test.
+                */
                ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, 0);
                if (ret != 0) {
                        DBG_ERR("SMB_VFS_NEXT_FTRUNCATE on [%s] failed\n",
@@ -4606,6 +4612,12 @@ static ssize_t fruit_pwrite_meta_netatalk(vfs_handle_struct *handle,
                return n;
        }
 
+       /*
+        * Writing an all 0 blob to the metadata stream results in the stream
+        * being removed on a macOS server. This ensures we behave the same and
+        * it verified by the "delete AFP_AfpInfo by writing all 0" test.
+        */
+
        ok = set_delete_on_close(
                fsp,
                true,
@@ -4626,34 +4638,67 @@ static ssize_t fruit_pwrite_meta(vfs_handle_struct *handle,
 {
        struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
        ssize_t nwritten;
+       uint8_t buf[AFP_INFO_SIZE];
+       size_t to_write;
+       size_t to_copy;
+       int cmp;
 
-       /*
-        * Writing an all 0 blob to the metadata stream
-        * results in the stream being removed on a macOS
-        * server. This ensures we behave the same and it
-        * verified by the "delete AFP_AfpInfo by writing all
-        * 0" test.
-        */
-       if (n != AFP_INFO_SIZE || offset != 0) {
-               DBG_ERR("unexpected offset=%jd or size=%jd\n",
-                       (intmax_t)offset, (intmax_t)n);
+       if (fio == NULL) {
+               DBG_ERR("Failed to fetch fsp extension");
                return -1;
        }
 
-       if (fio == NULL) {
-               DBG_ERR("Failed to fetch fsp extension");
+       if (n < 3) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (offset != 0 && n < 60) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       cmp = memcmp(data, "AFP", 3);
+       if (cmp != 0) {
+               errno = EINVAL;
                return -1;
        }
 
+       if (n <= AFP_OFF_FinderInfo) {
+               /*
+                * Nothing to do here really, just return
+                */
+               return n;
+       }
+
+       offset = 0;
+
+       to_copy = n;
+       if (to_copy > AFP_INFO_SIZE) {
+               to_copy = AFP_INFO_SIZE;
+       }
+       memcpy(buf, data, to_copy);
+
+       to_write = n;
+       if (to_write != AFP_INFO_SIZE) {
+               to_write = AFP_INFO_SIZE;
+       }
+
        switch (fio->config->meta) {
        case FRUIT_META_STREAM:
-               nwritten = fruit_pwrite_meta_stream(handle, fsp, data,
-                                                   n, offset);
+               nwritten = fruit_pwrite_meta_stream(handle,
+                                                   fsp,
+                                                   buf,
+                                                   to_write,
+                                                   offset);
                break;
 
        case FRUIT_META_NETATALK:
-               nwritten = fruit_pwrite_meta_netatalk(handle, fsp, data,
-                                                     n, offset);
+               nwritten = fruit_pwrite_meta_netatalk(handle,
+                                                     fsp,
+                                                     buf,
+                                                     to_write,
+                                                     offset);
                break;
 
        default:
@@ -4661,7 +4706,14 @@ static ssize_t fruit_pwrite_meta(vfs_handle_struct *handle,
                return -1;
        }
 
-       return nwritten;
+       if (nwritten != to_write) {
+               return -1;
+       }
+
+       /*
+        * Return the requested amount, verified against macOS SMB server
+        */
+       return n;
 }
 
 static ssize_t fruit_pwrite_rsrc_stream(vfs_handle_struct *handle,
@@ -5152,6 +5204,7 @@ static int fruit_fstat_meta_stream(vfs_handle_struct *handle,
                                   SMB_STRUCT_STAT *sbuf)
 {
        struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+       struct smb_filename smb_fname;
        ino_t ino;
        int ret;
 
@@ -5171,11 +5224,15 @@ static int fruit_fstat_meta_stream(vfs_handle_struct *handle,
                return 0;
        }
 
-       ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
+       smb_fname = (struct smb_filename) {
+               .base_name = fsp->fsp_name->base_name,
+       };
+
+       ret = fruit_stat_base(handle, &smb_fname, false);
        if (ret != 0) {
                return -1;
        }
-       *sbuf = fsp->base_fsp->fsp_name->st;
+       *sbuf = smb_fname.st;
 
        ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);