1. Stefan Saasen
  2. git

Commits

Nicolas Pitre  committed 8960844

check patch_delta bounds more carefully

Let's avoid going south with invalid delta data.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>

  • Participants
  • Parent commits 7d6c447
  • Branches master

Comments (0)

Files changed (3)

File delta.h

View file
  • Ignore whitespace
  * This must be called twice on the delta data buffer, first to get the
  * expected reference buffer size, and again to get the result buffer size.
  */
-static inline unsigned long get_delta_hdr_size(const unsigned char **datap)
+static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
+					       const unsigned char *top)
 {
 	const unsigned char *data = *datap;
 	unsigned char cmd;
 		cmd = *data++;
 		size |= (cmd & ~0x80) << i;
 		i += 7;
-	} while (cmd & 0x80);
+	} while (cmd & 0x80 && data < top);
 	*datap = data;
 	return size;
 }

File patch-delta.c

View file
  • Ignore whitespace
 	top = delta_buf + delta_size;
 
 	/* make sure the orig file size matches what we expect */
-	size = get_delta_hdr_size(&data);
+	size = get_delta_hdr_size(&data, top);
 	if (size != src_size)
 		return NULL;
 
 	/* now the result size */
-	size = get_delta_hdr_size(&data);
+	size = get_delta_hdr_size(&data, top);
 	dst_buf = malloc(size + 1);
 	if (!dst_buf)
 		return NULL;
 			if (cmd & 0x20) cp_size |= (*data++ << 8);
 			if (cmd & 0x40) cp_size |= (*data++ << 16);
 			if (cp_size == 0) cp_size = 0x10000;
+			if (cp_off + cp_size < cp_size ||
+			    cp_off + cp_size > src_size ||
+			    cp_size > size)
+				goto bad;
 			memcpy(out, src_buf + cp_off, cp_size);
 			out += cp_size;
-		} else {
+			size -= cp_size;
+		} else if (cmd) {
+			if (cmd > size)
+				goto bad;
 			memcpy(out, data, cmd);
 			out += cmd;
 			data += cmd;
+			size -= cmd;
+		} else {
+			/*
+			 * cmd == 0 is reserved for future encoding
+			 * extensions. In the mean time we must fail when
+			 * encountering them (might be data corruption).
+			 */
+			goto bad;
 		}
 	}
 
 	/* sanity check */
-	if (data != top || out - dst_buf != size) {
+	if (data != top || size != 0) {
+		bad:
 		free(dst_buf);
 		return NULL;
 	}
 
-	*dst_size = size;
+	*dst_size = out - dst_buf;
 	return dst_buf;
 }

File sha1_file.c

View file
  • Ignore whitespace
 		 * the result size.
 		 */
 		data = delta_head;
-		get_delta_hdr_size(&data); /* ignore base size */
+
+		/* ignore base size */
+		get_delta_hdr_size(&data, delta_head+sizeof(delta_head));
 
 		/* Read the result size */
-		result_size = get_delta_hdr_size(&data);
+		result_size = get_delta_hdr_size(&data, delta_head+sizeof(delta_head));
 		*sizep = result_size;
 	}
 	return 0;