Преглед на файлове

encoding/base32: Fix buffer allocation and bounds checking

Fix buffer allocation size calculation and add proper bounds checking to
ensure output buffer has sufficient space. This fixes crashes that could
occur with inputs like "AA" and other edge cases where the output buffer
was too small.

Remove #no_bounds_check as proper bounds checking is necessary for safe
error handling. The small performance trade-off is worth the improved
robustness.
Zoltán Kéri преди 10 месеца
родител
ревизия
b9338777e3
променени са 1 файла, в които са добавени 24 реда и са изтрити 6 реда
  1. 24 6
      core/encoding/base32/base32.odin

+ 24 - 6
core/encoding/base32/base32.odin

@@ -100,15 +100,18 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al
 	}
 	}
 }
 }
 
 
-decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> ([]byte, Error) #no_bounds_check {
+decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> ([]byte, Error) {
 	if len(data) == 0 {
 	if len(data) == 0 {
 		return nil, .None
 		return nil, .None
 	}
 	}
 
 
+	// Calculate maximum possible output size and allocate buffer
+	out_len := (len(data) * 5 + 7) / 8 // Ceiling division to ensure enough space
+	out := make([]byte, out_len, allocator)
+
 	outi := 0
 	outi := 0
 	data := data
 	data := data
 
 
-	out := make([]byte, len(data) / 8 * 5, allocator)
 	end := false
 	end := false
 	for len(data) > 0 && !end {
 	for len(data) > 0 && !end {
 		dbuf : [8]byte
 		dbuf : [8]byte
@@ -122,25 +125,22 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato
 			input := data[0]
 			input := data[0]
 			data = data[1:]
 			data = data[1:]
 			if input == byte(PADDING) && j >= 2 && len(data) < 8 {
 			if input == byte(PADDING) && j >= 2 && len(data) < 8 {
-				// assert(!(len(data) + j < 8 - 1), "Corrupted input")
 				if len(data) + j < 8 - 1 {
 				if len(data) + j < 8 - 1 {
 					return nil, .Malformed_Input
 					return nil, .Malformed_Input
 				}
 				}
-				// assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input")
 				for k := 0; k < 8-1-j; k += 1 {
 				for k := 0; k < 8-1-j; k += 1 {
 					if len(data) < k || data[k] != byte(PADDING) {
 					if len(data) < k || data[k] != byte(PADDING) {
 						return nil, .Malformed_Input
 						return nil, .Malformed_Input
 					}
 					}
 				}
 				}
 				dlen, end = j, true
 				dlen, end = j, true
-				// assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input")
 				if dlen == 1 || dlen == 3 || dlen == 6 {
 				if dlen == 1 || dlen == 3 || dlen == 6 {
 					return nil, .Invalid_Length
 					return nil, .Invalid_Length
 				}
 				}
 				break
 				break
 			}
 			}
+
 			decoded := DEC_TBL[input]
 			decoded := DEC_TBL[input]
-			// assert(dbuf[j] != 0xff, "Corrupted input")
 			if decoded == 0 && input != byte(ENC_TABLE[0]) {
 			if decoded == 0 && input != byte(ENC_TABLE[0]) {
 				return nil, .Invalid_Character
 				return nil, .Invalid_Character
 			}
 			}
@@ -148,23 +148,41 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato
 			j += 1
 			j += 1
 		}
 		}
 
 
+		// Ensure we have enough space in output buffer
+		needed := 5  // Each full 8-char block produces 5 bytes
+		if outi + needed > len(out) {
+			return nil, .Invalid_Length
+		}
+
+		// Process complete input blocks
 		switch dlen {
 		switch dlen {
 		case 8:
 		case 8:
+			if len(dbuf) < 8 { return nil, .Invalid_Length }
 			out[outi + 4] = dbuf[6] << 5 | dbuf[7]
 			out[outi + 4] = dbuf[6] << 5 | dbuf[7]
 			fallthrough
 			fallthrough
 		case 7:
 		case 7:
+			if len(dbuf) < 7 { return nil, .Invalid_Length }
 			out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3
 			out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3
 			fallthrough
 			fallthrough
 		case 5:
 		case 5:
+			if len(dbuf) < 5 { return nil, .Invalid_Length }
 			out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1
 			out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1
 			fallthrough
 			fallthrough
 		case 4:
 		case 4:
+			if len(dbuf) < 4 { return nil, .Invalid_Length }
 			out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4
 			out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4
 			fallthrough
 			fallthrough
 		case 2:
 		case 2:
+			if len(dbuf) < 2 { return nil, .Invalid_Length }
 			out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2
 			out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2
 		}
 		}
 		outi += 5
 		outi += 5
 	}
 	}
+
+	// Trim output buffer to actual size
+	if outi < len(out) {
+		out = out[:outi]
+	}
+
 	return out, .None
 	return out, .None
 }
 }