vfs_fruit: allocate ad_data buffer up to AD_XATTR_MAX_HDR_SIZE bytes
authorRalph Boehme <slow@samba.org>
Tue, 10 Oct 2017 14:04:29 +0000 (16:04 +0200)
committerRalph Boehme <slow@samba.org>
Fri, 13 Oct 2017 15:40:07 +0000 (17:40 +0200)
This is in preperation of reading potential xattr header data from the
AppleDouble file, not just reading a fixed amount of bytes.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13076

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
source3/modules/vfs_fruit.c

index 37e8d8d24f9e0363784184fc25dc650786656010..aea3ad682ebd4a69a4e0b481bb4b4abb1765b824 100644 (file)
@@ -578,6 +578,10 @@ static bool ad_pack(struct adouble *ad)
        uint32_t       offset = 0;
 
        bufsize = talloc_get_size(ad->ad_data);
+       if (bufsize < AD_DATASZ_DOT_UND) {
+               DBG_ERR("bad buffer size [0x%" PRIx32 "]\n", bufsize);
+               return false;
+       }
 
        if (offset + ADEDLEN_MAGIC < offset ||
                        offset + ADEDLEN_MAGIC >= bufsize) {
@@ -1021,22 +1025,44 @@ static ssize_t ad_read_rsrc_adouble(struct adouble *ad,
        char *p_ad = NULL;
        char *p_meta_ad = NULL;
        ssize_t len;
+       size_t size;
        int ret;
        bool ok;
 
-       len = sys_pread(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
-       if (len != AD_DATASZ_DOT_UND) {
-               DBG_NOTICE("%s %s: bad size: %zd\n",
-                          smb_fname->base_name, strerror(errno), len);
-               return -1;
-       }
-
        ret = sys_fstat(ad->ad_fd, &sbuf, lp_fake_directory_create_times(
                                SNUM(ad->ad_handle->conn)));
        if (ret != 0) {
                return -1;
        }
 
+       /*
+        * AppleDouble file header content and size, two cases:
+        *
+        * - without xattrs it is exactly AD_DATASZ_DOT_UND (82) bytes large
+        * - with embedded xattrs it can be larger, up to AD_XATTR_MAX_HDR_SIZE
+        *
+        * Read as much as we can up to AD_XATTR_MAX_HDR_SIZE.
+        */
+       size = sbuf.st_ex_size;
+       if (size > talloc_array_length(ad->ad_data)) {
+               if (size > AD_XATTR_MAX_HDR_SIZE) {
+                       size = AD_XATTR_MAX_HDR_SIZE;
+               }
+               p_ad = talloc_realloc(ad, ad->ad_data, char, size);
+               if (p_ad == NULL) {
+                       return -1;
+               }
+               ad->ad_data = p_ad;
+       }
+
+       len = sys_pread(ad->ad_fd, ad->ad_data,
+                       talloc_array_length(ad->ad_data), 0);
+       if (len != talloc_array_length(ad->ad_data)) {
+               DBG_NOTICE("%s %s: bad size: %zd\n",
+                          smb_fname->base_name, strerror(errno), len);
+               return -1;
+       }
+
        /* Now parse entries */
        ok = ad_unpack(ad, ADEID_NUM_DOT_UND, sbuf.st_ex_size);
        if (!ok) {
@@ -1452,9 +1478,9 @@ static int ad_fset(struct adouble *ad, files_struct *fsp)
                len = SMB_VFS_NEXT_PWRITE(ad->ad_handle,
                                          fsp,
                                          ad->ad_data,
-                                         talloc_get_size(ad->ad_data),
+                                         AD_DATASZ_DOT_UND,
                                          0);
-               if (len != (ssize_t)talloc_get_size(ad->ad_data)) {
+               if (len != AD_DATASZ_DOT_UND) {
                        DBG_ERR("short write on %s: %zd", fsp_str_dbg(fsp), len);
                        return -1;
                }