Camera: Prevent data size overflow
Add a function to check overflow when calculating metadata
data size.
Bug: 30741779
Change-Id: I6405fe608567a4f4113674050f826f305ecae030
diff --git a/camera/src/camera_metadata.c b/camera/src/camera_metadata.c
index a413f66..3f435eb 100644
--- a/camera/src/camera_metadata.c
+++ b/camera/src/camera_metadata.c
@@ -22,9 +22,10 @@
#include <stdlib.h>
#include <errno.h>
-#define OK 0
-#define ERROR 1
-#define NOT_FOUND -ENOENT
+#define OK 0
+#define ERROR 1
+#define NOT_FOUND -ENOENT
+#define SN_EVENT_LOG_ID 0x534e4554
#define _Alignas(T) \
({struct _AlignasStruct { char c; T field; }; \
@@ -291,6 +292,38 @@
return metadata;
}
+// This method should be used when the camera metadata cannot be trusted. For example, when it's
+// read from Parcel.
+static int validate_and_calculate_camera_metadata_entry_data_size(size_t *data_size, uint8_t type,
+ size_t data_count) {
+ if (type >= NUM_TYPES) return ERROR;
+
+ // Check for overflow
+ if (data_count != 0 &&
+ camera_metadata_type_size[type] > (SIZE_MAX - DATA_ALIGNMENT + 1) / data_count) {
+ android_errorWriteLog(SN_EVENT_LOG_ID, "30741779");
+ return ERROR;
+ }
+
+ size_t data_bytes = data_count * camera_metadata_type_size[type];
+
+ if (data_size) {
+ *data_size = data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT);
+ }
+
+ return OK;
+}
+
+size_t calculate_camera_metadata_entry_data_size(uint8_t type,
+ size_t data_count) {
+ if (type >= NUM_TYPES) return 0;
+
+ size_t data_bytes = data_count *
+ camera_metadata_type_size[type];
+
+ return data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT);
+}
+
int validate_camera_metadata_structure(const camera_metadata_t *metadata,
const size_t *expected_size) {
@@ -400,9 +433,13 @@
return ERROR;
}
- size_t data_size =
- calculate_camera_metadata_entry_data_size(entry.type,
- entry.count);
+ size_t data_size;
+ if (validate_and_calculate_camera_metadata_entry_data_size(&data_size, entry.type,
+ entry.count) != OK) {
+ ALOGE("%s: Entry data size is invalid. type: %u count: %u", __FUNCTION__, entry.type,
+ entry.count);
+ return ERROR;
+ }
if (data_size != 0) {
camera_metadata_data_t *data =
@@ -492,14 +529,6 @@
return clone;
}
-size_t calculate_camera_metadata_entry_data_size(uint8_t type,
- size_t data_count) {
- if (type >= NUM_TYPES) return 0;
- size_t data_bytes = data_count *
- camera_metadata_type_size[type];
- return data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT);
-}
-
static int add_camera_metadata_entry_raw(camera_metadata_t *dst,
uint32_t tag,
uint8_t type,