Patches: Fix bug 10106

Volker Lendecke Volker.Lendecke at SerNet.DE
Tue Aug 27 08:11:01 MDT 2013


Hi!

Attached find a bugfix that intends to fix bug 10106.

Please review & push.

Thanks,

Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de

*****************************************************************
visit us on it-sa:IT security exhibitions in Nürnberg, Germany
October 8th - 10th 2013, hall 12, booth 333
free tickets available via code 270691 on: www.it-sa.de/gutschein
******************************************************************
-------------- next part --------------
From 2352c090cfc12cac26d5bbc8ca509869cf86c6a1 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 23 Aug 2013 13:57:03 +0000
Subject: [PATCH 1/9] torture3: add clipathinfo-bufsize

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/torture/proto.h           |  1 +
 source3/torture/test_buffersize.c | 56 +++++++++++++++++++++++++++++++++++++++
 source3/torture/torture.c         |  1 +
 source3/wscript_build             |  1 +
 4 files changed, 59 insertions(+)
 create mode 100644 source3/torture/test_buffersize.c

diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 4f4c9e2..f6453fd 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -111,5 +111,6 @@ bool run_notify_bench3(int dummy);
 bool run_dbwrap_watch1(int dummy);
 bool run_idmap_tdb_common_test(int dummy);
 bool run_local_dbwrap_ctdb(int dummy);
+bool run_qpathinfo_bufsize(int dummy);
 
 #endif /* __TORTURE_H__ */
diff --git a/source3/torture/test_buffersize.c b/source3/torture/test_buffersize.c
new file mode 100644
index 0000000..6e86374
--- /dev/null
+++ b/source3/torture/test_buffersize.c
@@ -0,0 +1,56 @@
+/*
+   Unix SMB/CIFS implementation.
+   Test buffer sizes in cli_qpathinfo
+   Copyright (C) Volker Lendecke 2012
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/proto.h"
+#include "libsmb/libsmb.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/secdesc.h"
+#include "libcli/security/security.h"
+#include "trans2.h"
+#include "source3/libsmb/clirap.h"
+
+bool run_qpathinfo_bufsize(int dummy)
+{
+	struct cli_state *cli = NULL;
+	NTSTATUS status, status2;
+	bool ret = false;
+	int i;
+
+	printf("Starting qpathinfo_bufsize\n");
+
+	if (!torture_open_connection(&cli, 0)) {
+		printf("torture_open_connection failed\n");
+		goto fail;
+	}
+
+	for (i=0; i<500; i++) {
+		uint8_t *rdata;
+		uint32_t num_rdata;
+		cli_qpathinfo(cli, cli, "\\", SMB_FILE_ALL_INFORMATION,
+			      0, i, &rdata, &num_rdata);
+	}
+
+	ret = true;
+fail:
+	if (cli != NULL) {
+		torture_close_connection(cli);
+	}
+	return ret;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 4a8e3ed..359baa9 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -9579,6 +9579,7 @@ static struct {
 	{ "local-tdb-opener", run_local_tdb_opener, 0 },
 	{ "local-tdb-writer", run_local_tdb_writer, 0 },
 	{ "LOCAL-DBWRAP-CTDB", run_local_dbwrap_ctdb, 0 },
+	{ "qpathinfo-bufsize", run_qpathinfo_bufsize, 0 },
 	{NULL, NULL, 0}};
 
 /*
diff --git a/source3/wscript_build b/source3/wscript_build
index e166b16..e4417ea 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -560,6 +560,7 @@ SMBTORTURE_SRC1 = '''torture/torture.c torture/nbio.c torture/scanner.c torture/
                 torture/test_dbwrap_watch.c
                 torture/test_idmap_tdb_common.c
                 torture/test_dbwrap_ctdb.c
+                torture/test_buffersize.c
                 torture/t_strappend.c'''
 
 SMBTORTURE_SRC = '''${SMBTORTURE_SRC1}
-- 
1.8.1.2


From 162d375a0eba714e28689c9a9fca310d46874776 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:06:27 +0000
Subject: [PATCH 2/9] smbd: qfilepathinfo has fixed/variable buffers

The error message will have to change depending whether the buffer is
too small for the fixed or variable buffers

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/globals.h      |  1 +
 source3/smbd/smb2_getinfo.c |  2 ++
 source3/smbd/trans2.c       | 22 ++++++++++++++++++++++
 3 files changed, 25 insertions(+)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index d618aea..6ccb57e 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -138,6 +138,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			       char *lock_data,
 			       uint16_t flags2,
 			       unsigned int max_data_bytes,
+			       size_t *fixed_portion,
 			       char **ppdata,
 			       unsigned int *pdata_size);
 
diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index 4420f94..0d75c36 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -293,6 +293,7 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 		struct ea_list *ea_list = NULL;
 		int lock_data_count = 0;
 		char *lock_data = NULL;
+		size_t fixed_portion;
 
 		ZERO_STRUCT(write_time_ts);
 
@@ -380,6 +381,7 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 					       lock_data,
 					       STR_UNICODE,
 					       in_output_buffer_length,
+					       &fixed_portion,
 					       &data,
 					       &data_size);
 		if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index b6cb3cc..1d55dbe 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -4388,6 +4388,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			       char *lock_data,
 			       uint16_t flags2,
 			       unsigned int max_data_bytes,
+			       size_t *fixed_portion,
 			       char **ppdata,
 			       unsigned int *pdata_size)
 {
@@ -4528,6 +4529,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 	   BasicFileInformationTest. -tpot */
 	file_index = get_FileIndex(conn, psbuf);
 
+	*fixed_portion = 0;
+
 	switch (info_level) {
 		case SMB_INFO_STANDARD:
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
@@ -4674,6 +4677,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			DEBUG(5,("write: %s ", ctime(&mtime)));
 			DEBUG(5,("change: %s ", ctime(&c_time)));
 			DEBUG(5,("mode: %x\n", mode));
+			*fixed_portion = data_size;
 			break;
 
 		case SMB_FILE_STANDARD_INFORMATION:
@@ -4687,6 +4691,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			SCVAL(pdata,20,delete_pending?1:0);
 			SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
 			SSVAL(pdata,22,0); /* Padding. */
+			*fixed_portion = 24;
 			break;
 
 		case SMB_FILE_EA_INFORMATION:
@@ -4696,6 +4701,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			    estimate_ea_size(conn, fsp,	smb_fname);
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
 			data_size = 4;
+			*fixed_portion = 4;
 			SIVAL(pdata,0,ea_size);
 			break;
 		}
@@ -4717,6 +4723,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 					  STR_UNICODE);
 			data_size = 4 + len;
 			SIVAL(pdata,0,len);
+			*fixed_portion = 8;
 			break;
 		}
 
@@ -4780,6 +4787,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			SIVAL(pdata,0,len);
 			pdata += 4 + len;
 			data_size = PTR_DIFF(pdata,(*ppdata));
+			*fixed_portion = 10;
 			break;
 		}
 
@@ -4817,6 +4825,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			SIVAL(pdata,0,len);
 			pdata += 4 + len;
 			data_size = PTR_DIFF(pdata,(*ppdata));
+			*fixed_portion = 104;
 			break;
 		}
 		case SMB_FILE_INTERNAL_INFORMATION:
@@ -4824,12 +4833,14 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
 			SBVAL(pdata, 0, file_index);
 			data_size = 8;
+			*fixed_portion = 8;
 			break;
 
 		case SMB_FILE_ACCESS_INFORMATION:
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
 			SIVAL(pdata, 0, access_mask);
 			data_size = 4;
+			*fixed_portion = 4;
 			break;
 
 		case SMB_FILE_NAME_INFORMATION:
@@ -4847,24 +4858,28 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
 			data_size = 1;
 			SCVAL(pdata,0,delete_pending);
+			*fixed_portion = 1;
 			break;
 
 		case SMB_FILE_POSITION_INFORMATION:
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
 			data_size = 8;
 			SOFF_T(pdata,0,pos);
+			*fixed_portion = 8;
 			break;
 
 		case SMB_FILE_MODE_INFORMATION:
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
 			SIVAL(pdata,0,mode);
 			data_size = 4;
+			*fixed_portion = 4;
 			break;
 
 		case SMB_FILE_ALIGNMENT_INFORMATION:
 			DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
 			SIVAL(pdata,0,0); /* No alignment needed. */
 			data_size = 4;
+			*fixed_portion = 4;
 			break;
 
 		/*
@@ -4909,6 +4924,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
 			TALLOC_FREE(streams);
 
+			*fixed_portion = 32;
+
 			break;
 		}
 		case SMB_QUERY_COMPRESSION_INFO:
@@ -4918,6 +4935,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			SIVAL(pdata,8,0); /* ??? */
 			SIVAL(pdata,12,0); /* ??? */
 			data_size = 16;
+			*fixed_portion = 16;
 			break;
 
 		case SMB_FILE_NETWORK_OPEN_INFORMATION:
@@ -4931,6 +4949,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			SIVAL(pdata,48,mode);
 			SIVAL(pdata,52,0); /* ??? */
 			data_size = 56;
+			*fixed_portion = 56;
 			break;
 
 		case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
@@ -4938,6 +4957,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 			SIVAL(pdata,0,mode);
 			SIVAL(pdata,4,0);
 			data_size = 8;
+			*fixed_portion = 8;
 			break;
 
 		/*
@@ -5211,6 +5231,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
 	struct ea_list *ea_list = NULL;
 	int lock_data_count = 0;
 	char *lock_data = NULL;
+	size_t fixed_portion;
 	NTSTATUS status = NT_STATUS_OK;
 
 	if (!params) {
@@ -5570,6 +5591,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 				       ea_list,
 				       lock_data_count, lock_data,
 				       req->flags2, max_data_bytes,
+				       &fixed_portion,
 				       ppdata, &data_size);
 	if (!NT_STATUS_IS_OK(status)) {
 		reply_nterror(req, status);
-- 
1.8.1.2


From 20af936c60f19b8c87845e83a0ec04739a632fea Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:06:27 +0000
Subject: [PATCH 3/9] smbd: qfsinfo has fixed/variable buffers

The error message will have to change depending whether the buffer is
too small for the fixed or variable buffers

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/globals.h      |  1 +
 source3/smbd/smb2_getinfo.c |  2 ++
 source3/smbd/trans2.c       | 10 ++++++++++
 3 files changed, 13 insertions(+)

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 6ccb57e..9ea5e25 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -156,6 +156,7 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
 			 uint16_t info_level,
 			 uint16_t flags2,
 			 unsigned int max_data_bytes,
+			 size_t *fixed_portion,
 			 struct smb_filename *smb_fname,
 			 char **ppdata,
 			 int *ret_data_len);
diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index 0d75c36..698e775 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -410,6 +410,7 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 		uint16_t file_info_level;
 		char *data = NULL;
 		int data_size = 0;
+		size_t fixed_portion;
 
 		/* the levels directly map to the passthru levels */
 		file_info_level = in_file_info_class + 1000;
@@ -418,6 +419,7 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 					 file_info_level,
 					 STR_UNICODE,
 					 in_output_buffer_length,
+					 &fixed_portion,
 					 fsp->fsp_name,
 					 &data,
 					 &data_size);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 1d55dbe..37f578c 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -3068,6 +3068,7 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
 			 uint16_t info_level,
 			 uint16_t flags2,
 			 unsigned int max_data_bytes,
+			 size_t *fixed_portion,
 			 struct smb_filename *fname,
 			 char **ppdata,
 			 int *ret_data_len)
@@ -3124,6 +3125,8 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
 	memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
 	end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
 
+	*fixed_portion = 0;
+
 	switch (info_level) {
 		case SMB_INFO_ALLOCATION:
 		{
@@ -3222,6 +3225,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
 				data_len = max_data_bytes;
 				status = STATUS_BUFFER_OVERFLOW;
 			}
+			*fixed_portion = 16;
 			break;
 
 		case SMB_QUERY_FS_LABEL_INFO:
@@ -3258,6 +3262,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
 				data_len = max_data_bytes;
 				status = STATUS_BUFFER_OVERFLOW;
 			}
+			*fixed_portion = 24;
 			break;
 
 		case SMB_QUERY_FS_SIZE_INFO:
@@ -3290,6 +3295,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
 			SBIG_UINT(pdata,8,dfree);
 			SIVAL(pdata,16,sectors_per_unit);
 			SIVAL(pdata,20,bytes_per_sector);
+			*fixed_portion = 24;
 			break;
 		}
 
@@ -3323,6 +3329,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
 			SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
 			SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
 			SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
+			*fixed_portion = 32;
 			break;
 		}
 
@@ -3337,6 +3344,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
 			data_len = 8;
 			SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
 			SIVAL(pdata,4,characteristics);
+			*fixed_portion = 8;
 			break;
 		}
 
@@ -3645,6 +3653,7 @@ static void call_trans2qfsinfo(connection_struct *conn,
 	char *params = *pparams;
 	uint16_t info_level;
 	int data_len = 0;
+	size_t fixed_portion;
 	NTSTATUS status;
 
 	if (total_params < 2) {
@@ -3670,6 +3679,7 @@ static void call_trans2qfsinfo(connection_struct *conn,
 				 info_level,
 				 req->flags2,
 				 max_data_bytes,
+				 &fixed_portion,
 				 NULL,
 				 ppdata, &data_len);
 	if (!NT_STATUS_IS_OK(status)) {
-- 
1.8.1.2


From fcfeae27971998996ced138a8d456a9ba257e7df Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:36:03 +0000
Subject: [PATCH 4/9] smbd: Correctly return INFO_LENGTH_MISMATCH in
 smb2_getinfo

We have to return this error if the client offered less than the fixed
portion of the infolevel data requires

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/smb2_getinfo.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index 698e775..c6a1433 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -392,6 +392,12 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
+		if (in_output_buffer_length < fixed_portion) {
+			SAFE_FREE(data);
+			tevent_req_nterror(
+				req, NT_STATUS_INFO_LENGTH_MISMATCH);
+			return tevent_req_post(req, ev);
+		}
 		if (data_size > 0) {
 			state->out_output_buffer = data_blob_talloc(state,
 								    data,
@@ -434,6 +440,12 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
+		if (in_output_buffer_length < fixed_portion) {
+			SAFE_FREE(data);
+			tevent_req_nterror(
+				req, NT_STATUS_INFO_LENGTH_MISMATCH);
+			return tevent_req_post(req, ev);
+		}
 		if (data_size > 0) {
 			state->out_output_buffer = data_blob_talloc(state,
 								    data,
-- 
1.8.1.2


From d673650e6cca75e81d29705c0c358b5e95fdea7d Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:37:34 +0000
Subject: [PATCH 5/9] smbd: Correctly return BUFFER_OVERFLOW in smb2_getinfo

Also, don't overflow the client buffer

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/smb2_getinfo.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index c6a1433..4111aa1 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -406,6 +406,11 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 			if (tevent_req_nomem(state->out_output_buffer.data, req)) {
 				return tevent_req_post(req, ev);
 			}
+			if (data_size > in_output_buffer_length) {
+				state->out_output_buffer.length =
+					in_output_buffer_length;
+				status = STATUS_BUFFER_OVERFLOW;
+			}
 		}
 		SAFE_FREE(data);
 		break;
@@ -454,6 +459,11 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 			if (tevent_req_nomem(state->out_output_buffer.data, req)) {
 				return tevent_req_post(req, ev);
 			}
+			if (data_size > in_output_buffer_length) {
+				state->out_output_buffer.length =
+					in_output_buffer_length;
+				status = STATUS_BUFFER_OVERFLOW;
+			}
 		}
 		SAFE_FREE(data);
 		break;
-- 
1.8.1.2


From c80e601606d9d8771a9dd5f0f12f55392d7c6932 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:38:29 +0000
Subject: [PATCH 6/9] smbd: Revert a93f9c3

This was too broad and has been replaced by finer-grained error checks

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/smb2_getinfo.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index 4111aa1..449aeb3 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -530,11 +530,6 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	if (state->out_output_buffer.length > in_output_buffer_length) {
-		tevent_req_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
-		return tevent_req_post(req, ev);
-	}
-
 	state->status = status;
 	tevent_req_done(req);
 	return tevent_req_post(req, ev);
-- 
1.8.1.2


From 61b44463894bd269363714efb12042415f7f76c1 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:39:17 +0000
Subject: [PATCH 7/9] smbd: Fix error return for STREAM_INFO

The stream_info marshalling follows its own rules. This needs unifying
eventually...

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/trans2.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 37f578c..576e289 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -4243,6 +4243,10 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams,
 	unsigned int i;
 	unsigned int ofs = 0;
 
+	if (max_data_bytes < 32) {
+		return NT_STATUS_INFO_LENGTH_MISMATCH;
+	}
+
 	for (i = 0; i < num_streams; i++) {
 		unsigned int next_offset;
 		size_t namelen;
-- 
1.8.1.2


From a4f50ecf003a48dccc51e5208cea4154e7e3646f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:40:19 +0000
Subject: [PATCH 8/9] smbd: Correctly return INFO_LENGTH_MISMATCH for smb1

This is required if the client offered less buffer than the fixed portion
of the info level data requires

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/smbd/trans2.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 576e289..aaf0e62 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -5611,6 +5611,10 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 		reply_nterror(req, status);
 		return;
 	}
+	if (fixed_portion > max_data_bytes) {
+		reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
+		return;
+	}
 
 	send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
 			    max_data_bytes);
-- 
1.8.1.2


From 01827c0bbbfbc360f5e7c98eeabf19039b0588f6 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Aug 2013 09:41:13 +0000
Subject: [PATCH 9/9] torture: Add buffercheck tests

Make sure we get the smb2 infolevel fixed portions right

I could not find correct #defines for the infolevels

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10106
Signed-off-by: Volker Lendecke <vl at samba.org>
---
 selftest/knownfail             |   3 +
 source4/torture/smb2/getinfo.c | 244 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 229 insertions(+), 18 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index dd536df..6fe7ce5 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -171,6 +171,9 @@
 ^samba4.smb2.oplock.batch20\(.*\)$ # samba 4 oplocks are a mess
 ^samba4.smb2.oplock.stream1 # samba 4 oplocks are a mess
 ^samba4.smb2.getinfo.complex # streams on directories does not work
+^samba4.smb2.getinfo.qfs_buffercheck # S4 does not do the INFO_LENGTH_MISMATCH/BUFFER_OVERFLOW thingy
+^samba4.smb2.getinfo.qfile_buffercheck # S4 does not do the INFO_LENGTH_MISMATCH/BUFFER_OVERFLOW thingy
+^samba4.smb2.getinfo.qsec_buffercheck # S4 does not do the BUFFER_TOO_SMALL thingy
 ^samba4.ntvfs.cifs.krb5.base.createx_access.createx_access\(.*\)$
 ^samba4.rpc.lsa.forest.trust #Not fully provided by Samba4
 ^samba4.blackbox.kinit\(.*\).kinit with user password for expired password\(.*\) # We need to work out why this fails only during the pw change
diff --git a/source4/torture/smb2/getinfo.c b/source4/torture/smb2/getinfo.c
index 10dd550..fafc36c 100644
--- a/source4/torture/smb2/getinfo.c
+++ b/source4/torture/smb2/getinfo.c
@@ -22,9 +22,11 @@
 #include "includes.h"
 #include "libcli/smb2/smb2.h"
 #include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smbXcli_base.h"
 
 #include "torture/torture.h"
 #include "torture/smb2/proto.h"
+#include "torture/util.h"
 
 static struct {
 	const char *name;
@@ -154,41 +156,243 @@ static bool torture_smb2_fsinfo(struct torture_context *tctx)
 	return true;
 }
 
+static bool torture_smb2_buffercheck_err(struct torture_context *tctx,
+					 struct smb2_tree *tree,
+					 struct smb2_getinfo *b,
+					 size_t fixed,
+					 DATA_BLOB full)
+{
+	size_t i;
 
-/*
-  test for buffer size handling
-*/
-static bool torture_smb2_buffercheck(struct torture_context *tctx)
+	for (i=0; i<=full.length; i++) {
+		NTSTATUS status;
+
+		b->in.output_buffer_length = i;
+
+		status = smb2_getinfo(tree, tree, b);
+
+		if (i < fixed) {
+			torture_assert_ntstatus_equal(
+				tctx, status, NT_STATUS_INFO_LENGTH_MISMATCH,
+				"Wrong error code small buffer");
+			continue;
+		}
+
+		if (i<full.length) {
+			torture_assert_ntstatus_equal(
+				tctx, status, STATUS_BUFFER_OVERFLOW,
+				"Wrong error code for large buffer");
+			/*
+			 * TODO: compare the output buffer. That seems a bit
+			 * difficult, because for level 5 for example the
+			 * label length is adjusted to what is there. And some
+			 * reserved fields seem to be not initialized to 0.
+			 */
+			TALLOC_FREE(b->out.blob.data);
+			continue;
+		}
+
+		torture_assert_ntstatus_equal(
+			tctx, status, NT_STATUS_OK,
+			"Wrong error code for right sized buffer");
+	}
+
+	return true;
+}
+
+struct level_buffersize {
+	int level;
+	size_t fixed;
+};
+
+static bool torture_smb2_qfs_buffercheck(struct torture_context *tctx)
 {
 	bool ret;
 	struct smb2_tree *tree;
 	NTSTATUS status;
 	struct smb2_handle handle;
-	struct smb2_getinfo b;
+	int i;
+
+	struct level_buffersize levels[] = {
+		{ 1, 24 },	/* We don't have proper defines here */
+		{ 3, 24 },
+		{ 4, 8 },
+		{ 5, 16 },
+		{ 6, 48 },
+		{ 7, 32 },
+		{ 11, 28 },
+	};
 
-	printf("Testing buffer size handling\n");
+	printf("Testing SMB2_GETINFO_FS buffer sizes\n");
 
 	ret = torture_smb2_connection(tctx, &tree);
 	torture_assert(tctx, ret, "connection failed");
 
 	status = smb2_util_roothandle(tree, &handle);
-	torture_assert_ntstatus_ok(tctx, status, "Unable to create root handle");
+	torture_assert_ntstatus_ok(
+		tctx, status, "Unable to create root handle");
+
+	for (i=0; i<ARRAY_SIZE(levels); i++) {
+		struct smb2_getinfo b;
+
+		if (TARGET_IS_SAMBA3(tctx) &&
+		    ((levels[i].level == 6) || (levels[i].level == 11))) {
+			continue;
+		}
+
+		ZERO_STRUCT(b);
+		b.in.info_type			= SMB2_GETINFO_FS;
+		b.in.info_class			= levels[i].level;
+		b.in.file.handle		= handle;
+		b.in.output_buffer_length	= 65535;
+
+		status = smb2_getinfo(tree, tree, &b);
+
+		torture_assert_ntstatus_equal(
+			tctx, status, NT_STATUS_OK,
+			"Wrong error code for large buffer");
+
+		ret = torture_smb2_buffercheck_err(
+			tctx, tree, &b, levels[i].fixed, b.out.blob);
+		if (!ret) {
+			return ret;
+		}
+	}
+
+	return true;
+}
+
+static bool torture_smb2_qfile_buffercheck(struct torture_context *tctx)
+{
+	bool ret;
+	struct smb2_tree *tree;
+	struct smb2_create c;
+	NTSTATUS status;
+	struct smb2_handle handle;
+	int i;
+
+	struct level_buffersize levels[] = {
+		{ 4, 40 },
+		{ 5, 24 },
+		{ 6, 8 },
+		{ 7, 4 },
+		{ 8, 4 },
+		{ 16, 4 },
+		{ 17, 4 },
+		{ 18, 104 },
+		{ 21, 8 },
+		{ 22, 32 },
+		{ 28, 16 },
+		{ 34, 56 },
+		{ 35, 8 },
+	};
+
+	printf("Testing SMB2_GETINFO_FILE buffer sizes\n");
+
+	ret = torture_smb2_connection(tctx, &tree);
+	torture_assert(tctx, ret, "connection failed");
+
+	ZERO_STRUCT(c);
+	c.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+	c.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
+	c.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+	c.in.share_access =
+		NTCREATEX_SHARE_ACCESS_DELETE|
+		NTCREATEX_SHARE_ACCESS_READ|
+		NTCREATEX_SHARE_ACCESS_WRITE;
+	c.in.create_options = 0;
+	c.in.fname = "bufsize.txt";
+
+	c.in.eas.num_eas = 2;
+	c.in.eas.eas = talloc_array(tree, struct ea_struct, 2);
+	c.in.eas.eas[0].flags = 0;
+	c.in.eas.eas[0].name.s = "EAONE";
+	c.in.eas.eas[0].value = data_blob_talloc(c.in.eas.eas, "VALUE1", 6);
+	c.in.eas.eas[1].flags = 0;
+	c.in.eas.eas[1].name.s = "SECONDEA";
+	c.in.eas.eas[1].value = data_blob_talloc(c.in.eas.eas, "ValueTwo", 8);
+
+	status = smb2_create(tree, tree, &c);
+	torture_assert_ntstatus_ok(
+		tctx, status, "Unable to create test file");
+
+	handle = c.out.file.handle;
+
+	for (i=0; i<ARRAY_SIZE(levels); i++) {
+		struct smb2_getinfo b;
+
+		ZERO_STRUCT(b);
+		b.in.info_type			= SMB2_GETINFO_FILE;
+		b.in.info_class			= levels[i].level;
+		b.in.file.handle		= handle;
+		b.in.output_buffer_length	= 65535;
+
+		status = smb2_getinfo(tree, tree, &b);
+		torture_assert_ntstatus_equal(
+			tctx, status, NT_STATUS_OK,
+			"Wrong error code for large buffer");
+
+		ret = torture_smb2_buffercheck_err(
+			tctx, tree, &b, levels[i].fixed, b.out.blob);
+		if (!ret) {
+			return ret;
+		}
+	}
+	return true;
+}
+
+static bool torture_smb2_qsec_buffercheck(struct torture_context *tctx)
+{
+	struct smb2_getinfo b;
+	bool ret;
+	struct smb2_tree *tree;
+	struct smb2_create c;
+	NTSTATUS status;
+	struct smb2_handle handle;
+	int i;
+
+	printf("Testing SMB2_GETINFO_SECURITY buffer sizes\n");
+
+	ret = torture_smb2_connection(tctx, &tree);
+	torture_assert(tctx, ret, "connection failed");
+
+	ZERO_STRUCT(c);
+	c.in.oplock_level = 0;
+	c.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE |
+		SEC_DIR_LIST | SEC_STD_READ_CONTROL;
+	c.in.file_attributes   = 0;
+	c.in.create_disposition = NTCREATEX_DISP_OPEN;
+	c.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+		NTCREATEX_SHARE_ACCESS_DELETE;
+	c.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
+	c.in.fname = "";
+
+	status = smb2_create(tree, tree, &c);
+	torture_assert_ntstatus_ok(
+		tctx, status, "Unable to create root handle");
+
+	handle = c.out.file.handle;
 
 	ZERO_STRUCT(b);
-	b.in.info_type            = SMB2_GETINFO_FS;
-	b.in.info_class           = 1;
-	b.in.output_buffer_length = 0x1;
-	b.in.input_buffer_length  = 0;
-	b.in.file.handle          = handle;
+	b.in.info_type			= SMB2_GETINFO_SECURITY;
+	b.in.info_class			= 0;
+	b.in.file.handle		= handle;
+	b.in.output_buffer_length	= 0;
 
 	status = smb2_getinfo(tree, tree, &b);
-	torture_assert_ntstatus_equal(tctx, status,
-				      NT_STATUS_INFO_LENGTH_MISMATCH,
-				      "Wrong error code for small buffer");
+	torture_assert_ntstatus_equal(
+		tctx, status, NT_STATUS_BUFFER_TOO_SMALL,
+		"Wrong error code for large buffer");
+
+	b.in.output_buffer_length	= 1;
+	status = smb2_getinfo(tree, tree, &b);
+	torture_assert_ntstatus_equal(
+		tctx, status, NT_STATUS_BUFFER_TOO_SMALL,
+		"Wrong error code for large buffer");
+
 	return true;
 }
 
-
 /* basic testing of all SMB2 getinfo levels
 */
 static bool torture_smb2_getinfo(struct torture_context *torture)
@@ -231,7 +435,11 @@ struct torture_suite *torture_smb2_getinfo_init(void)
 
 	torture_suite_add_simple_test(suite, "complex", torture_smb2_getinfo);
 	torture_suite_add_simple_test(suite, "fsinfo",  torture_smb2_fsinfo);
-	torture_suite_add_simple_test(suite, "buffercheck",
-				      torture_smb2_buffercheck);
+	torture_suite_add_simple_test(suite, "qfs_buffercheck",
+				      torture_smb2_qfs_buffercheck);
+	torture_suite_add_simple_test(suite, "qfile_buffercheck",
+				      torture_smb2_qfile_buffercheck);
+	torture_suite_add_simple_test(suite, "qsec_buffercheck",
+				      torture_smb2_qsec_buffercheck);
 	return suite;
 }
-- 
1.8.1.2



More information about the samba-technical mailing list