patch-2.4.18 linux/fs/smbfs/proc.c

Next file: linux/fs/super.c
Previous file: linux/fs/smbfs/inode.c
Back to the patch index
Back to the overall index

diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/fs/smbfs/proc.c linux/fs/smbfs/proc.c
@@ -103,6 +103,8 @@
 			  struct nls_table *nls_from,
 			  struct nls_table *nls_to)
 {
+	if (olen < ilen)
+		return -ENAMETOOLONG;
 	memcpy(output, input, ilen);
 	return ilen;
 }
@@ -126,20 +128,21 @@
 		/* convert by changing to unicode and back to the new cp */
 		n = nls_from->char2uni((unsigned char *)input, ilen, &ch);
 		if (n < 0)
-			goto out;
+			goto fail;
 		input += n;
 		ilen -= n;
 
 		n = nls_to->uni2char(ch, output, olen);
 		if (n < 0)
-			goto out;
+			goto fail;
 		output += n;
 		olen -= n;
 
 		len += n;
 	}
-out:
 	return len;
+fail:
+	return n;
 }
 
 static int setcodepage(struct nls_table **p, char *name)
@@ -214,71 +217,79 @@
  * smb_build_path: build the path to entry and name storing it in buf.
  * The path returned will have the trailing '\0'.
  */
-static int smb_build_path(struct smb_sb_info *server, char * buf,
+static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
 			  struct dentry * entry, struct qstr * name)
 {
 	char *path = buf;
 	int len;
 
+	if (maxlen < 2)
+		return -ENAMETOOLONG;
+
+	if (maxlen > SMB_MAXNAMELEN + 1)
+		maxlen = SMB_MAXNAMELEN + 1;
+
 	if (entry == NULL)
 		goto test_name_and_out;
 
 	/*
 	 * If IS_ROOT, we have to do no walking at all.
 	 */
-	if (IS_ROOT(entry)) {
-		*(path++) = '\\';
-		if (name != NULL)
-			goto name_and_out;
-		goto out;
+	if (IS_ROOT(entry) && !name) {
+		*path++ = '\\';
+		*path++ = '\0';
+		return 2;
 	}
 
 	/*
 	 * Build the path string walking the tree backward from end to ROOT
 	 * and store it in reversed order [see reverse_string()]
 	 */
-	for (;;) {
-		if (entry->d_name.len > SMB_MAXNAMELEN)
-			return -ENAMETOOLONG;
-		if (path - buf + entry->d_name.len > SMB_MAXPATHLEN)
+	while (!IS_ROOT(entry)) {
+		if (maxlen < 3)
 			return -ENAMETOOLONG;
 
-		len = server->convert(path, SMB_MAXNAMELEN, 
+		len = server->convert(path, maxlen-2, 
 				      entry->d_name.name, entry->d_name.len,
 				      server->local_nls, server->remote_nls);
+		if (len < 0)
+			return len;
 		reverse_string(path, len);
 		path += len;
-
-		*(path++) = '\\';
+		*path++ = '\\';
+		maxlen -= len+1;
 
 		entry = entry->d_parent;
-
 		if (IS_ROOT(entry))
 			break;
 	}
-
 	reverse_string(buf, path-buf);
 
+	/* maxlen is at least 1 */
 test_name_and_out:
-	if (name != NULL) {
-		*(path++) = '\\';
-name_and_out:
-		len = server->convert(path, SMB_MAXNAMELEN, 
+	if (name) {
+		if (maxlen < 3)
+			return -ENAMETOOLONG;
+		*path++ = '\\';
+		len = server->convert(path, maxlen-2, 
 				      name->name, name->len,
 				      server->local_nls, server->remote_nls);
+		if (len < 0)
+			return len;
 		path += len;
+		maxlen -= len+1;
 	}
-out:
-	*(path++) = '\0';
-	return (path-buf);
+	/* maxlen is at least 1 */
+	*path++ = '\0';
+	return path-buf;
 }
 
-static int smb_encode_path(struct smb_sb_info *server, char *buf,
+static int smb_encode_path(struct smb_sb_info *server, char *buf, int maxlen,
 			   struct dentry *dir, struct qstr *name)
 {
 	int result;
 
-	result = smb_build_path(server, buf, dir, name);
+	result = smb_build_path(server, buf, maxlen, dir, name);
 	if (result < 0)
 		goto out;
 	if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
@@ -287,6 +298,23 @@
 	return result;
 }
 
+static int smb_simple_encode_path(struct smb_sb_info *server, char **p,
+			  struct dentry * entry, struct qstr * name)
+{
+	char *s = *p;
+	int res;
+	int maxlen = ((char *)server->packet + server->packet_size) - s;
+
+	if (!maxlen)
+		return -ENAMETOOLONG;
+	*s++ = 4;
+	res = smb_encode_path(server, s, maxlen-1, entry, name);
+	if (res < 0)
+		return res;
+	*p = s + res;
+	return 0;
+}
+
 /* The following are taken directly from msdos-fs */
 
 /* Linear day numbers of the respective 1sts in non-leap years. */
@@ -965,12 +993,9 @@
 	p = smb_setup_header(server, SMBopen, 2, 0);
 	WSET(server->packet, smb_vwv0, mode);
 	WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
-	*p++ = 4;
-	res = smb_encode_path(server, p, dentry, NULL);
+	res = smb_simple_encode_path(server, &p, dentry, NULL);
 	if (res < 0)
 		goto out;
-	p += res;
-
 	smb_setup_bcc(server, p);
 
 	res = smb_request_ok(server, SMBopen, 7, 0);
@@ -1242,11 +1267,9 @@
 	p = smb_setup_header(server, SMBcreate, 3, 0);
 	WSET(server->packet, smb_vwv0, attr);
 	DSET(server->packet, smb_vwv1, utc2local(server, ctime));
-	*p++ = 4;
-	result = smb_encode_path(server, p, dentry, NULL);
+	result = smb_simple_encode_path(server, &p, dentry, NULL);
 	if (result < 0)
 		goto out;
-	p += result;
 	smb_setup_bcc(server, p);
 
 	result = smb_request_ok(server, SMBcreate, 1, 0);
@@ -1275,19 +1298,12 @@
       retry:
 	p = smb_setup_header(server, SMBmv, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);
-
-	*p++ = 4;
-	result = smb_encode_path(server, p, old_dentry, NULL);
+	result = smb_simple_encode_path(server, &p, old_dentry, NULL);
 	if (result < 0)
 		goto out;
-	p += result;
-
-	*p++ = 4;
-	result = smb_encode_path(server, p, new_dentry, NULL);
+	result = smb_simple_encode_path(server, &p, new_dentry, NULL);
 	if (result < 0)
 		goto out;
-	p += result;
-
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
@@ -1315,11 +1331,9 @@
 
       retry:
 	p = smb_setup_header(server, command, 0, 0);
-	*p++ = 4;
-	result = smb_encode_path(server, p, dentry, NULL);
+	result = smb_simple_encode_path(server, &p, dentry, NULL);
 	if (result < 0)
 		goto out;
-	p += result;
 	smb_setup_bcc(server, p);
 
 	result = smb_request_ok(server, command, 0, 0);
@@ -1385,11 +1399,9 @@
       retry:
 	p = smb_setup_header(server, SMBunlink, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
-	*p++ = 4;
-	result = smb_encode_path(server, p, dentry, NULL);
+	result = smb_simple_encode_path(server, &p, dentry, NULL);
 	if (result < 0)
 		goto out;
-	p += result;
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
@@ -1589,8 +1601,7 @@
 	struct smb_sb_info *server = server_from_dentry(dir);
 	struct qstr qname;
 	struct smb_fattr fattr;
-
-	unsigned char *p;
+	char *p;
 	int result;
 	int i, first, entries_seen, entries;
 	int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
@@ -1612,17 +1623,26 @@
 		p = smb_setup_header(server, SMBsearch, 2, 0);
 		WSET(server->packet, smb_vwv0, entries_asked);
 		WSET(server->packet, smb_vwv1, aDIR);
-		*p++ = 4;
 		if (first == 1) {
-			result = smb_encode_path(server, p, dir, &mask);
+			result = smb_simple_encode_path(server, &p, dir, &mask);
 			if (result < 0)
 				goto unlock_return;
-			p += result;
+			if (p + 3 > (char*)server->packet+server->packet_size) {
+				result = -ENAMETOOLONG;
+				goto unlock_return;
+			}
 			*p++ = 5;
 			WSET(p, 0, 0);
 			p += 2;
 			first = 0;
 		} else {
+			if (p + 5 + SMB_STATUS_SIZE >
+			    (char*)server->packet + server->packet_size) {
+				result = -ENAMETOOLONG;
+				goto unlock_return;
+			}
+				
+			*p++ = 4;
 			*p++ = 0;
 			*p++ = 5;
 			WSET(p, 0, SMB_STATUS_SIZE);
@@ -1861,7 +1881,7 @@
 	 */
 	mask = param + 12;
 
-	mask_len = smb_encode_path(server, mask, dir, &star);
+	mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dir, &star);
 	if (mask_len < 0) {
 		result = mask_len;
 		goto unlock_return;
@@ -2068,7 +2088,7 @@
 	int mask_len, result;
 
 retry:
-	mask_len = smb_encode_path(server, mask, dentry, NULL);
+	mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dentry, NULL);
 	if (mask_len < 0) {
 		result = mask_len;
 		goto out;
@@ -2146,11 +2166,9 @@
 
       retry:
 	p = smb_setup_header(server, SMBgetatr, 0, 0);
-	*p++ = 4;
-	result = smb_encode_path(server, p, dir, NULL);
+	result = smb_simple_encode_path(server, &p, dir, NULL);
 	if (result < 0)
 		goto out;
-	p += result;
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
@@ -2196,7 +2214,7 @@
       retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	result = smb_encode_path(server, param + 6, dir, NULL);
+	result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
 	if (result < 0)
 		goto out;
 	p = param + 6 + result;
@@ -2343,11 +2361,13 @@
 	WSET(server->packet, smb_vwv5, 0);
 	WSET(server->packet, smb_vwv6, 0);
 	WSET(server->packet, smb_vwv7, 0);
-	*p++ = 4;
-	result = smb_encode_path(server, p, dentry, NULL);
+	result = smb_simple_encode_path(server, &p, dentry, NULL);
 	if (result < 0)
 		goto out;
-	p += result;
+	if (p + 2 > (char *)server->packet + server->packet_size) {
+		result = -ENAMETOOLONG;
+		goto out;
+	}
 	*p++ = 4;
 	*p++ = 0;
 	smb_setup_bcc(server, p);
@@ -2444,7 +2464,7 @@
       retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	result = smb_encode_path(server, param + 6, dir, NULL);
+	result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
 	if (result < 0)
 		goto out;
 	p = param + 6 + result;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)