[PATCH] Fix bug 10775 - smbd crashes when accessing garbage filenames
David Disseldorp
ddiss at suse.de
Fri Aug 29 08:47:29 MDT 2014
Hi Jeremy,
On Thu, 28 Aug 2014 13:07:58 -0700, Jeremy Allison wrote:
...
>
> This was a little tricky to implement the
> right way, as our main function to push
> strings into a client return buffer, srvstr_push()
> doesn't report conversion errors back. What
> we really need to do is convert the listing
> functions to propagate an NTSTATUS return
> all the way back to the top level SMB1/SMB2
> file server code, so we can sanely and in
> one place make policy decisions like what
> to do in conversion failures etc. Doing this
> actually simplified quite a bit of code,
> and actually allowed me to remove a hated
> voodoo 'bool *' flag parameter (out_of_space),
> so I'm quite pleased with how much easier
> it makes this code to understand :-).
>
> The early work in this patchset fixes
> up the return paths to propagate an NTSTATUS,
> and the last parts actually do the fix to
> filter out the bad conversions.
>
> There's only one tricky case, explained
> in patch [0009]. The last patch [0010] is
> a regression test suite change that ensures we behave
> correctly in the face of bad filenames, including
> those containing an invalid Windows filename
> character (such as ':').
>
> Reviews welcome !
s3: smbd: srvstr_push() was changed to never return -1, so don't check for that as an error.
Looks good.
s3: smbd: Ensure types for all variables called 'len' used in srvstr_push() are correct.
case SMB_QUERY_FILE_UNIX_LINK:
{
- int len;
+ ssize_t link_len = 0;
char *buffer = talloc_array(mem_ctx, char, PATH_MAX+1);
if (!buffer) {
@@ -5025,13 +5023,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
#else
return NT_STATUS_DOS(ERRDOS, ERRbadlink);
#endif
- len = SMB_VFS_READLINK(conn,
+ link_len = SMB_VFS_READLINK(conn,
smb_fname->base_name,
buffer, PATH_MAX);
smb_vfs_call_readlink() returns an int, so this specific type change
isn't necessary.
s3: smbd: Change the function signature of srvstr_push() from returning a length to returning an NTSTATUS with a length param.
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 3430cd0..adaf3ff 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1178,10 +1178,15 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
shadow_data->num_volumes, fsp_str_dbg(fsp)));
if (labels && shadow_data->labels) {
for (i=0; i<shadow_data->num_volumes; i++) {
- srvstr_push(cur_pdata, req_flags,
+ size_t len = 0;
+ status = srvstr_push(cur_pdata, req_flags,
cur_pdata, shadow_data->labels[i],
2 * sizeof(SHADOW_COPY_LABEL),
- STR_UNICODE|STR_TERMINATE);
+ STR_UNICODE|STR_TERMINATE, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(shadow_data);
+ return status;
+ }
Looks like cur_pdata/*out_data leaks on error here.
- return push_string_base(base_ptr, smb_flags2, dest, src,
+ len = push_string_base(base_ptr, smb_flags2, dest, src,
dest_len, flags);
+
+ if (errno != 0) {
+ /*
+ * Special case E2BIG, EILSEQ, EINVAL
+ * as they mean conversion errors here,
+ * but we don't generically map them as
+ * they can mean different things in
+ * generic filesystem calls (such as
+ * read xattrs).
+ */
+ if (errno == E2BIG || errno == EILSEQ || errno == EINVAL) {
+ status = NT_STATUS_ILLEGAL_CHARACTER;
+ } else {
+ status = map_nt_error_from_unix_common(errno);
+ }
+ DEBUG(10,("character conversion failure "
+ "on string (%s) (%s)\n",
+ src, strerror(errno)));
+ } else {
+ /* Success - restore untouched errno. */
+ errno = saved_errno;
+ *ret_len = len;
+ status = NT_STATUS_OK;
+ }
Can't say I'm a fan of the errno-catch error handling here, but it
looks like propagating error values all the way through to
convert_string_error_handle() would be a pretty massive change :-/
s3: smbd: Change smbd_marshall_dir_entry() to return an NTSTATUS. Returns STATUS_MORE_ENTRIES on out of space.
s3: smbd: smbd_marshall_dir_entry() no longer needs explicit 'out_of_space' parameter.
srvstr_push() EAGAIN, EINTR, ENOBUFS and EWOULDBLOCK errors would also
be propagated through as STATUS_MORE_ENTRIES. Could we get these from
the iconv layer? I think I'd prefer to keep the explicit out_of_space
parameter, rather than audit all return paths for potential
STATUS_MORE_ENTRIES values.
Am going to stop here. I'd like to see what the others think of the
approach taken here.
Cheers, David
More information about the samba-technical
mailing list