From: Andrew Walker Date: Fri, 7 May 2021 10:37:25 +0000 (-0400) Subject: s3:smbd - support streams larger than 64 KiB X-Git-Tag: tevent-0.11.0~932 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=21934c09bdcad04633f0e77ad8136b8f2c21b9e5;p=thirdparty%2Fsamba.git s3:smbd - support streams larger than 64 KiB Add support for streams that are larger than 64 KiB in size. Upper and lower bound are controlled by the parameters smbd max_xattr_size. Testing against ReFS on Windows (where ADS size is limited in size shows the server responding with STATUS_FILESYSTEM_LIMITATION. Do the same in samba for this case. Currently, large xattrs are supported in FreeBSD. Signed-off-by: Andrew Walker Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Mon May 10 20:16:21 UTC 2021 on sn-devel-184 --- diff --git a/docs-xml/smbdotconf/misc/smbdmaxxattrsize.xml b/docs-xml/smbdotconf/misc/smbdmaxxattrsize.xml new file mode 100644 index 00000000000..3ae91a37890 --- /dev/null +++ b/docs-xml/smbdotconf/misc/smbdmaxxattrsize.xml @@ -0,0 +1,28 @@ + + + + This parameter controls the maximum size of extended attributes + that may be written to the server as EAs or as alternate data + streams if vfs_streams_xattr is enabled. The maximum size of + extended attributes depends on the Samba server's operating system + and the underlying filesystem. The Linux VFS currently sets an + upper boundary of 64 KiB per extended attribute. FreeBSD does not + set a practical upper limit, but since pread() and pwrite() are not + possible via the extattr on FreeBSD, it is not recommended to + increase this value above a few MiB. + + If a client attempts to write an overly-large alternate datastream, + the Samba server will return STATUS_FILESYSTEM_LIMITATION. + If this error is encountered, users may try increasing the maximum + size supported for xattr writes. If this is not possible, and + writes are from a MacOS client and to an AFP_Resource extended + attribute, the user may enable the vfs_fruit module and configure + to allow stream writes for AFP_Resource to an alternative storage + location. See vfs_fruit documentation for further details. + + +65536 + diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index adfba67652e..b674858e706 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2956,6 +2956,10 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) "client protection", "default"); + lpcfg_do_global_parameter(lp_ctx, + "smbd max xattr size", + "65536"); + for (i = 0; parm_table[i].label; i++) { if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) { lp_ctx->flags[i] |= FLAG_DEFAULT; diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index cbe82ad6f33..78a2baf40d5 100644 --- a/source3/modules/vfs_streams_xattr.c +++ b/source3/modules/vfs_streams_xattr.c @@ -957,6 +957,27 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle, return -1; } + if ((offset + n) >= lp_smbd_max_xattr_size(SNUM(handle->conn))) { + /* + * Requested write is beyond what can be read based on + * samba configuration. + * ReFS returns STATUS_FILESYSTEM_LIMITATION, which causes + * entire file to be skipped by File Explorer. VFAT returns + * NT_STATUS_OBJECT_NAME_COLLISION causes user to be prompted + * to skip writing metadata, but copy data. + */ + DBG_ERR("Write to xattr [%s] on file [%s] exceeds maximum " + "supported extended attribute size. " + "Depending on filesystem type and operating system " + "(OS) specifics, this value may be increased using " + "the value of the parameter: " + "smbd max xattr size = . Consult OS and " + "filesystem manpages prior to increasing this limit.\n", + sio->xattr_name, sio->base); + errno = EOVERFLOW; + return -1; + } + /* Create an smb_filename with stream_name == NULL. */ smb_fname_base = synthetic_smb_fname(talloc_tos(), sio->base, diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 55184e9b798..85e578eda9e 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -197,6 +197,7 @@ static const struct loadparm_service _sDefault = .map_hidden = false, .map_archive = true, .store_dos_attributes = true, + .smbd_max_xattr_size = 65536, .dmapi_support = false, .locking = true, .strict_locking = Auto, diff --git a/source3/smbd/smb2_write.c b/source3/smbd/smb2_write.c index e49e623d796..612c89d59d1 100644 --- a/source3/smbd/smb2_write.c +++ b/source3/smbd/smb2_write.c @@ -193,7 +193,12 @@ static NTSTATUS smb2_write_complete_internal(struct tevent_req *req, files_struct *fsp = state->fsp; if (nwritten == -1) { - status = map_nt_error_from_unix(err); + if (err == EOVERFLOW && + is_ntfs_stream_smb_fname(fsp->fsp_name)) { + status = NT_STATUS_FILE_SYSTEM_LIMITATION; + } else { + status = map_nt_error_from_unix(err); + } DEBUG(2, ("smb2_write failed: %s, file %s, " "length=%lu offset=%lu nwritten=-1: %s\n", diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index de843117581..9aa2495792e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -249,6 +249,7 @@ NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, size_t attr_size = 256; char *val = NULL; ssize_t sizeret; + size_t max_xattr_size = lp_smbd_max_xattr_size(SNUM(conn)); again: @@ -264,8 +265,8 @@ NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, ea_name, val, attr_size); } - if (sizeret == -1 && errno == ERANGE && attr_size != 65536) { - attr_size = 65536; + if (sizeret == -1 && errno == ERANGE && attr_size < max_xattr_size) { + attr_size = max_xattr_size; goto again; } @@ -501,6 +502,17 @@ static NTSTATUS get_ea_list_from_fsp(TALLOC_CTX *mem_ctx, */ TALLOC_FREE(listp); continue; + } else if (listp->ea.value.length > 65536) { + /* + * SMB clients may report error with file + * if large EA is presented to them. + */ + DBG_ERR("EA [%s] on file [%s] exceeds " + "maximum permitted EA size of 64KiB: %zu\n.", + listp->ea.name, fsp_str_dbg(fsp), + listp->ea.value.length); + TALLOC_FREE(listp); + continue; } push_ascii_fstring(dos_ea_name, listp->ea.name);