<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">diff -Naur a/smb2misc.c b/smb2misc.c
--- a/smb2misc.c	2023-01-17 10:34:34.291983249 +0800
+++ b/smb2misc.c	2023-01-17 15:17:16.924040490 +0800
@@ -91,11 +91,6 @@
 	*off = 0;
 	*len = 0;
 
-	/* error reqeusts do not have data area */
-	if (hdr-&gt;Status &amp;&amp; hdr-&gt;Status != STATUS_MORE_PROCESSING_REQUIRED &amp;&amp;
-	    (((struct smb2_err_rsp *)hdr)-&gt;StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2_LE)
-		return ret;
-
 	/*
 	 * Following commands have data areas so we have to get the location
 	 * of the data buffer offset and data buffer length for the particular
@@ -137,8 +132,11 @@
 		*len = le16_to_cpu(((struct smb2_read_req *)hdr)-&gt;ReadChannelInfoLength);
 		break;
 	case SMB2_WRITE:
-		if (((struct smb2_write_req *)hdr)-&gt;DataOffset) {
-			*off = le16_to_cpu(((struct smb2_write_req *)hdr)-&gt;DataOffset);
+		if (((struct smb2_write_req *)hdr)-&gt;DataOffset ||
+		    ((struct smb2_write_req *)hdr)-&gt;Length) {
+			*off = max_t(unsigned int,
+				     le16_to_cpu(((struct smb2_write_req *)hdr)-&gt;DataOffset),
+				     offsetof(struct smb2_write_req, Buffer));
 			*len = le32_to_cpu(((struct smb2_write_req *)hdr)-&gt;Length);
 			break;
 		}
diff -Naur a/smb2pdu.c b/smb2pdu.c
--- a/smb2pdu.c	2023-01-17 10:37:20.251390488 +0800
+++ b/smb2pdu.c	2023-01-17 17:25:58.076142662 +0800
@@ -540,9 +540,10 @@
 		struct smb2_query_info_req *req;
 
 		req = smb2_get_msg(work-&gt;request_buf);
-		if (req-&gt;InfoType == SMB2_O_INFO_FILE &amp;&amp;
-		    (req-&gt;FileInfoClass == FILE_FULL_EA_INFORMATION ||
-		     req-&gt;FileInfoClass == FILE_ALL_INFORMATION))
+		if ((req-&gt;InfoType == SMB2_O_INFO_FILE &amp;&amp;
+		     (req-&gt;FileInfoClass == FILE_FULL_EA_INFORMATION ||
+		     req-&gt;FileInfoClass == FILE_ALL_INFORMATION)) ||
+		    req-&gt;InfoType == SMB2_O_INFO_SECURITY)
 			sz = large_sz;
 	}
 
@@ -1146,12 +1147,16 @@
 			       status);
 			rsp-&gt;hdr.Status = status;
 			rc = -EINVAL;
+			kfree(conn-&gt;preauth_info);
+			conn-&gt;preauth_info = NULL;
 			goto err_out;
 		}
 
 		rc = init_smb3_11_server(conn);
 		if (rc &lt; 0) {
 			rsp-&gt;hdr.Status = STATUS_INVALID_PARAMETER;
+			kfree(conn-&gt;preauth_info);
+			conn-&gt;preauth_info = NULL;
 			goto err_out;
 		}
 
@@ -3004,7 +3009,7 @@
 						goto err_out;
 
 					rc = build_sec_desc(user_ns,
-							    pntsd, NULL,
+							    pntsd, NULL, 0,
 							    OWNER_SECINFO |
 							    GROUP_SECINFO |
 							    DACL_SECINFO,
@@ -3861,6 +3866,15 @@
 	return 0;
 }
 
+static int smb2_resp_buf_len(struct ksmbd_work *work, unsigned short hdr2_len)
+{
+	int free_len;
+
+	free_len = (int)(work-&gt;response_sz -
+		(get_rfc1002_len(work-&gt;response_buf) + 4)) - hdr2_len;
+	return free_len;
+}
+
 static int smb2_calc_max_out_buf_len(struct ksmbd_work *work,
 				     unsigned short hdr2_len,
 				     unsigned int out_buf_len)
@@ -3870,9 +3884,7 @@
 	if (out_buf_len &gt; work-&gt;conn-&gt;vals-&gt;max_trans_size)
 		return -EINVAL;
 
-	free_len = (int)(work-&gt;response_sz -
-			 (get_rfc1002_len(work-&gt;response_buf) + 4)) -
-		hdr2_len;
+	free_len = smb2_resp_buf_len(work, hdr2_len);
 	if (free_len &lt; 0)
 		return -EINVAL;
 
@@ -5164,10 +5176,10 @@
 	struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp-&gt;Buffer, *ppntsd = NULL;
 	struct smb_fattr fattr = {{0}};
 	struct inode *inode;
-	__u32 secdesclen;
+	__u32 secdesclen = 0;
 	unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
 	int addition_info = le32_to_cpu(req-&gt;AdditionalInformation);
-	int rc;
+	int rc = 0, ppntsd_size = 0;
 
 	if (addition_info &amp; ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
 			      PROTECTED_DACL_SECINFO |
@@ -5213,11 +5225,14 @@
 
 	if (test_share_config_flag(work-&gt;tcon-&gt;share_conf,
 				   KSMBD_SHARE_FLAG_ACL_XATTR))
-		ksmbd_vfs_get_sd_xattr(work-&gt;conn, user_ns,
-				       fp-&gt;filp-&gt;f_path.dentry, &amp;ppntsd);
-
-	rc = build_sec_desc(user_ns, pntsd, ppntsd, addition_info,
-			    &amp;secdesclen, &amp;fattr);
+		ppntsd_size = ksmbd_vfs_get_sd_xattr(work-&gt;conn, user_ns,
+						     fp-&gt;filp-&gt;f_path.dentry,
+						     &amp;ppntsd);
+
+	/* Check if sd buffer size exceeds response buffer size */
+	if (smb2_resp_buf_len(work, 8) &gt; ppntsd_size)
+		rc = build_sec_desc(user_ns, pntsd, ppntsd, ppntsd_size,
+				    addition_info, &amp;secdesclen, &amp;fattr);
 	posix_acl_release(fattr.cf_acls);
 	posix_acl_release(fattr.cf_dacls);
 	kfree(ppntsd);
@@ -6580,14 +6595,12 @@
 		writethrough = true;
 
 	if (is_rdma_channel == false) {
-		if ((u64)le16_to_cpu(req-&gt;DataOffset) + length &gt;
-		    get_rfc1002_len(work-&gt;request_buf)) {
-			pr_err("invalid write data offset %u, smb_len %u\n",
-			       le16_to_cpu(req-&gt;DataOffset),
-			       get_rfc1002_len(work-&gt;request_buf));
+		if (le16_to_cpu(req-&gt;DataOffset) &lt;
+		    offsetof(struct smb2_write_req, Buffer)) {
 			err = -EINVAL;
 			goto out;
 		}
+
 		data_buf = (char *)(((char *)&amp;req-&gt;hdr.ProtocolId) +
 				    le16_to_cpu(req-&gt;DataOffset));
 
diff -Naur a/smbacl.c b/smbacl.c
--- a/smbacl.c	2023-01-17 16:38:30.244282066 +0800
+++ b/smbacl.c	2023-01-17 17:03:41.689373609 +0800
@@ -722,6 +722,7 @@
 static void set_ntacl_dacl(struct user_namespace *user_ns,
 			   struct smb_acl *pndacl,
 			   struct smb_acl *nt_dacl,
+			   unsigned int aces_size,
 			   const struct smb_sid *pownersid,
 			   const struct smb_sid *pgrpsid,
 			   struct smb_fattr *fattr)
@@ -735,9 +736,19 @@
 	if (nt_num_aces) {
 		ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl));
 		for (i = 0; i &lt; nt_num_aces; i++) {
-			memcpy((char *)pndace + size, ntace, le16_to_cpu(ntace-&gt;size));
-			size += le16_to_cpu(ntace-&gt;size);
-			ntace = (struct smb_ace *)((char *)ntace + le16_to_cpu(ntace-&gt;size));
+			unsigned short nt_ace_size;
+
+			if (offsetof(struct smb_ace, access_req) &gt; aces_size)
+				break;
+
+			nt_ace_size = le16_to_cpu(ntace-&gt;size);
+			if (nt_ace_size &gt; aces_size)
+				break;
+
+			memcpy((char *)pndace + size, ntace, nt_ace_size);
+			size += nt_ace_size;
+			aces_size -= nt_ace_size;
+			ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
 			num_aces++;
 		}
 	}
@@ -910,7 +921,7 @@
 /* Convert permission bits from mode to equivalent CIFS ACL */
 int build_sec_desc(struct user_namespace *user_ns,
 		   struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd,
-		   int addition_info, __u32 *secdesclen,
+		   int ppntsd_size, int addition_info, __u32 *secdesclen,
 		   struct smb_fattr *fattr)
 {
 	int rc = 0;
@@ -970,15 +981,25 @@
 
 		if (!ppntsd) {
 			set_mode_dacl(user_ns, dacl_ptr, fattr);
-		} else if (!ppntsd-&gt;dacloffset) {
-			goto out;
 		} else {
 			struct smb_acl *ppdacl_ptr;
+			unsigned int dacl_offset = le32_to_cpu(ppntsd-&gt;dacloffset);
+			int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset;
+
+			if (!dacl_offset ||
+			    (dacl_offset + sizeof(struct smb_acl) &gt; ppntsd_size))
+				goto out;
+
+			ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset);
+			ppdacl_size = le16_to_cpu(ppdacl_ptr-&gt;size);
+			if (ppdacl_size &gt; ntacl_size ||
+			    ppdacl_size &lt; sizeof(struct smb_acl))
+				goto out;
 
-			ppdacl_ptr = (struct smb_acl *)((char *)ppntsd +
-						le32_to_cpu(ppntsd-&gt;dacloffset));
 			set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr,
-				       nowner_sid_ptr, ngroup_sid_ptr, fattr);
+				       ntacl_size - sizeof(struct smb_acl),
+				       nowner_sid_ptr, ngroup_sid_ptr,
+				       fattr);
 		}
 		pntsd-&gt;dacloffset = cpu_to_le32(offset);
 		offset += le16_to_cpu(dacl_ptr-&gt;size);
@@ -1012,24 +1033,31 @@
 	struct smb_sid owner_sid, group_sid;
 	struct dentry *parent = path-&gt;dentry-&gt;d_parent;
 	struct user_namespace *user_ns = mnt_user_ns(path-&gt;mnt);
-	int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0;
-	int rc = 0, num_aces, dacloffset, pntsd_type, acl_len;
+	int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size;
+	int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
 	char *aces_base;
 	bool is_dir = S_ISDIR(d_inode(path-&gt;dentry)-&gt;i_mode);
 
-	acl_len = ksmbd_vfs_get_sd_xattr(conn, user_ns,
-					 parent, &amp;parent_pntsd);
-	if (acl_len &lt;= 0)
+	pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
+					    parent, &amp;parent_pntsd);
+	if (pntsd_size &lt;= 0)
 		return -ENOENT;
 	dacloffset = le32_to_cpu(parent_pntsd-&gt;dacloffset);
-	if (!dacloffset) {
+	if (!dacloffset || (dacloffset + sizeof(struct smb_acl) &gt; pntsd_size)) {
 		rc = -EINVAL;
 		goto free_parent_pntsd;
 	}
 
 	parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
+	acl_len = pntsd_size - dacloffset;
 	num_aces = le32_to_cpu(parent_pdacl-&gt;num_aces);
 	pntsd_type = le16_to_cpu(parent_pntsd-&gt;type);
+	pdacl_size = le16_to_cpu(parent_pdacl-&gt;size);
+
+	if (pdacl_size &gt; acl_len || pdacl_size &lt; sizeof(struct smb_acl)) {
+		rc = -EINVAL;
+		goto free_parent_pntsd;
+	}
 
 	aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL);
 	if (!aces_base) {
@@ -1040,11 +1068,23 @@
 	aces = (struct smb_ace *)aces_base;
 	parent_aces = (struct smb_ace *)((char *)parent_pdacl +
 			sizeof(struct smb_acl));
+	aces_size = acl_len - sizeof(struct smb_acl);
 
 	if (pntsd_type &amp; DACL_AUTO_INHERITED)
 		inherited_flags = INHERITED_ACE;
 
 	for (i = 0; i &lt; num_aces; i++) {
+		int pace_size;
+
+		if (offsetof(struct smb_ace, access_req) &gt; aces_size)
+			break;
+
+		pace_size = le16_to_cpu(parent_aces-&gt;size);
+		if (pace_size &gt; aces_size)
+			break;
+
+		aces_size -= pace_size;
+
 		flags = parent_aces-&gt;flags;
 		if (!smb_inherit_flags(flags, is_dir))
 			goto pass;
@@ -1089,8 +1129,7 @@
 		aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces-&gt;size));
 		ace_cnt++;
 pass:
-		parent_aces =
-			(struct smb_ace *)((char *)parent_aces + le16_to_cpu(parent_aces-&gt;size));
+		parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size);
 	}
 
 	if (nt_size &gt; 0) {
@@ -1185,7 +1224,7 @@
 	struct smb_ntsd *pntsd = NULL;
 	struct smb_acl *pdacl;
 	struct posix_acl *posix_acls;
-	int rc = 0, acl_size;
+	int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset;
 	struct smb_sid sid;
 	int granted = le32_to_cpu(*pdaccess &amp; ~FILE_MAXIMAL_ACCESS_LE);
 	struct smb_ace *ace;
@@ -1194,37 +1233,33 @@
 	struct smb_ace *others_ace = NULL;
 	struct posix_acl_entry *pa_entry;
 	unsigned int sid_type = SIDOWNER;
-	char *end_of_acl;
+	unsigned short ace_size;
 
 	ksmbd_debug(SMB, "check permission using windows acl\n");
-	acl_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
-					  path-&gt;dentry, &amp;pntsd);
-	if (acl_size &lt;= 0 || !pntsd || !pntsd-&gt;dacloffset) {
-		kfree(pntsd);
-		return 0;
-	}
+	pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
+					    path-&gt;dentry, &amp;pntsd);
+	if (pntsd_size &lt;= 0 || !pntsd)
+		goto err_out;
+
+	dacl_offset = le32_to_cpu(pntsd-&gt;dacloffset);
+	if (!dacl_offset ||
+	    (dacl_offset + sizeof(struct smb_acl) &gt; pntsd_size))
+		goto err_out;
 
 	pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd-&gt;dacloffset));
-	end_of_acl = ((char *)pntsd) + acl_size;
-	if (end_of_acl &lt;= (char *)pdacl) {
-		kfree(pntsd);
-		return 0;
-	}
+	acl_size = pntsd_size - dacl_offset;
+	pdacl_size = le16_to_cpu(pdacl-&gt;size);
 
-	if (end_of_acl &lt; (char *)pdacl + le16_to_cpu(pdacl-&gt;size) ||
-	    le16_to_cpu(pdacl-&gt;size) &lt; sizeof(struct smb_acl)) {
-		kfree(pntsd);
-		return 0;
-	}
+	if (pdacl_size &gt; acl_size || pdacl_size &lt; sizeof(struct smb_acl))
+		goto err_out;
 
 	if (!pdacl-&gt;num_aces) {
-		if (!(le16_to_cpu(pdacl-&gt;size) - sizeof(struct smb_acl)) &amp;&amp;
+		if (!(pdacl_size - sizeof(struct smb_acl)) &amp;&amp;
 		    *pdaccess &amp; ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) {
 			rc = -EACCES;
 			goto err_out;
 		}
-		kfree(pntsd);
-		return 0;
+		goto err_out;
 	}
 
 	if (*pdaccess &amp; FILE_MAXIMAL_ACCESS_LE) {
@@ -1232,11 +1267,16 @@
 			DELETE;
 
 		ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+		aces_size = acl_size - sizeof(struct smb_acl);
 		for (i = 0; i &lt; le32_to_cpu(pdacl-&gt;num_aces); i++) {
+			if (offsetof(struct smb_ace, access_req) &gt; aces_size)
+				break;
+			ace_size = le16_to_cpu(ace-&gt;size);
+			if (ace_size &gt; aces_size)
+				break;
+			aces_size -= ace_size;
 			granted |= le32_to_cpu(ace-&gt;access_req);
 			ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace-&gt;size));
-			if (end_of_acl &lt; (char *)ace)
-				goto err_out;
 		}
 
 		if (!pdacl-&gt;num_aces)
@@ -1248,7 +1288,15 @@
 	id_to_sid(uid, sid_type, &amp;sid);
 
 	ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+	aces_size = acl_size - sizeof(struct smb_acl);
 	for (i = 0; i &lt; le32_to_cpu(pdacl-&gt;num_aces); i++) {
+		if (offsetof(struct smb_ace, access_req) &gt; aces_size)
+			break;
+		ace_size = le16_to_cpu(ace-&gt;size);
+		if (ace_size &gt; aces_size)
+			break;
+		aces_size -= ace_size;
+
 		if (!compare_sids(&amp;sid, &amp;ace-&gt;sid) ||
 		    !compare_sids(&amp;sid_unix_NFS_mode, &amp;ace-&gt;sid)) {
 			found = 1;
@@ -1258,8 +1306,6 @@
 			others_ace = ace;
 
 		ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace-&gt;size));
-		if (end_of_acl &lt; (char *)ace)
-			goto err_out;
 	}
 
 	if (*pdaccess &amp; FILE_MAXIMAL_ACCESS_LE &amp;&amp; found) {
diff -Naur a/smbacl.h b/smbacl.h
--- a/smbacl.h	2023-01-17 17:09:11.618949941 +0800
+++ b/smbacl.h	2023-01-17 17:10:10.681651570 +0800
@@ -196,7 +196,7 @@
 int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
 		   int acl_len, struct smb_fattr *fattr);
 int build_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
-		   struct smb_ntsd *ppntsd, int addition_info,
+		   struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info,
 		   __u32 *secdesclen, struct smb_fattr *fattr);
 int init_acl_state(struct posix_acl_state *state, int cnt);
 void free_acl_state(struct posix_acl_state *state);
diff -Naur a/vfs.c b/vfs.c
--- a/vfs.c	2023-01-17 17:10:33.910672093 +0800
+++ b/vfs.c	2023-01-17 17:11:28.493111948 +0800
@@ -1708,6 +1708,11 @@
 	}
 
 	*pntsd = acl.sd_buf;
+	if (acl.sd_size &lt; sizeof(struct smb_ntsd)) {
+		pr_err("sd size is invalid\n");
+		goto out_free;
+	}
+
 	(*pntsd)-&gt;osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)-&gt;osidoffset) -
 					   NDR_NTSD_OFFSETOF);
 	(*pntsd)-&gt;gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)-&gt;gsidoffset) -
</pre></body></html>