diff mbox series

[RFC,8/9] config parsing: add handling for chunked_hashes

Message ID 20240603085602.2351411-9-dominique.martinet@atmark-techno.com
State RFC
Headers show
Series Proof of concept of chunked checksums | expand

Commit Message

Dominique Martinet June 3, 2024, 8:56 a.m. UTC
This allows something like this to be fed to the new chunked_hashes code
(libconfig syntax):
-----
  images: (
    {
      filename = "somefile.tar.zst";
      name = "version";
      version = "1";
      install-if-higher = true;
      compressed = "zstd";
      encrypted = true;
      ivt = "3b627a40272e3ba253794680e6f870c9";
      installed-directly = true;
      sha256 = "e437493d207e7dabfba69997072b938bcb93175eea09d4108b96825d1fc2b079";
      chunked_hashes = (
        "3028e787495f7a97bfb6c10110affed016d398374d8c2c02fd7d02bc84f75e68",
        "5280083a531be033af6bb31a579737fb296739c0d9fa100457ce328fdfad01d8",
      );
      type = "archive";
      path = "/tmp/swupdate";
      properties: {
        create-destination = "true";
      };
    },
  );
-----

Note the sha256 is ignored if chunked_hashes is found in copyfile(), but
we've left it so this is installable by older versions of swupdate.

Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
---
 core/cpio_utils.c        |  1 +
 core/installer.c         |  1 +
 core/parsing_library.c   | 50 ++++++++++++++++++++++++++++++++++++++++
 include/parselib.h       |  3 +++
 include/swupdate_image.h |  1 +
 parser/parser.c          |  5 ++++
 6 files changed, 61 insertions(+)
diff mbox series

Patch

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index d296fe8d4525..fd52c9ef0ba6 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -847,6 +847,7 @@  int copyimage(void *out, struct img_type *img, writeimage callback)
 		.compressed = img->compressed,
 		.checksum = &img->checksum,
 		.hash = img->sha256,
+		.chunked_hashes = img->chunked_hashes,
 		.encrypted = img->is_encrypted,
 		.imgivt = img->ivt_ascii,
 	};
diff --git a/core/installer.c b/core/installer.c
index 0cb06b2ca419..2a2b0f6cf32b 100644
--- a/core/installer.c
+++ b/core/installer.c
@@ -512,6 +512,7 @@  static void cleaup_img_entry(struct img_type *img)
 
 void free_image(struct img_type *img) {
 	dict_drop_db(&img->properties);
+	free(img->chunked_hashes);
 	free(img);
 }
 
diff --git a/core/parsing_library.c b/core/parsing_library.c
index 038c6851adf9..b0f0e68df04e 100644
--- a/core/parsing_library.c
+++ b/core/parsing_library.c
@@ -210,6 +210,56 @@  void get_hash_value(parsertype p, void *elem, unsigned char *hash)
 	ascii_to_hash(hash, hash_ascii);
 }
 
+#ifdef CONFIG_CHUNKED_HASH
+int get_chunked_hashes(parsertype p, void *elem, unsigned char **chunked_hashes)
+{
+	void *hashes_node = get_child(p, elem, "chunked_hashes");
+
+	/* does not have chunked hashes */
+	if (!hashes_node)
+		return 0;
+
+	int count = get_array_length(p, hashes_node);
+	if (!count) {
+		ERROR("chunked_hashes is not an array");
+		return -EINVAL;
+	}
+
+	unsigned char *hashes = malloc((count+1) * SHA256_HASH_LENGTH);
+	if (!hashes) {
+		ERROR("No memory: failed for %d bytes", (count+1) * SHA256_HASH_LENGTH);
+		return -ENOMEM;
+	}
+
+	int idx;
+	for (idx = 0; idx < count; idx++) {
+		void *hash_node = get_elem_from_idx(p, hashes_node, idx);
+		if (!hash_node) {
+			ERROR("Could not get %dth hash in %d long array?", idx, count);
+			free(hashes);
+			return -EINVAL;
+		}
+		const char *hash_str = get_field_string(p, hash_node, NULL);
+		if (!hash_str) {
+			ERROR("%dth hash in chunked hashes array was not a string?", idx);
+			free(hashes);
+			return -EINVAL;
+		}
+		if (ascii_to_hash(hashes + idx * SHA256_HASH_LENGTH, hash_str) < 0) {
+			ERROR("Invalid hash %s", hash_str);
+			free(hashes);
+			return -EINVAL;
+		}
+	}
+
+	/* zero final hash marking end of array */
+	memset(hashes + count * SHA256_HASH_LENGTH, 0, SHA256_HASH_LENGTH);
+
+	*chunked_hashes = hashes;
+	return 0;
+}
+#endif
+
 bool set_find_path(const char **nodes, const char *newpath, char ***tmp)
 {
 	char **paths;
diff --git a/include/parselib.h b/include/parselib.h
index 48f38d2a8c92..0a8c3842e3fb 100644
--- a/include/parselib.h
+++ b/include/parselib.h
@@ -61,6 +61,9 @@  void iterate_field(parsertype p, void *e, iterate_callback cb, void *data);
 void get_field(parsertype p, void *e, const char *path, void *dest, field_type_t type);
 int exist_field_string(parsertype p, void *e, const char *path);
 void get_hash_value(parsertype p, void *elem, unsigned char *hash);
+#ifdef CONFIG_CHUNKED_HASH
+int get_chunked_hashes(parsertype p, void *elem, unsigned char **chunked_hashes);
+#endif
 void check_field_string(const char *src, char *dst, const size_t max_len);
 void *find_root(parsertype p, void *root, const char **nodes);
 void *get_node(parsertype p, void *root, const char **nodes);
diff --git a/include/swupdate_image.h b/include/swupdate_image.h
index e214aafc2965..cb51da4325a3 100644
--- a/include/swupdate_image.h
+++ b/include/swupdate_image.h
@@ -75,6 +75,7 @@  struct img_type {
 	long long size;
 	unsigned int checksum;
 	unsigned char sha256[SHA256_HASH_LENGTH];	/* SHA-256 is 32 byte */
+	unsigned char *chunked_hashes;
 	LIST_ENTRY(img_type) next;
 };
 
diff --git a/parser/parser.c b/parser/parser.c
index 2273796e0452..12420554837c 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -421,6 +421,11 @@  static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
 	GET_FIELD_STRING(p, elem, "type", image->type);
 	GET_FIELD_STRING(p, elem, "data", image->type_data);
 	get_hash_value(p, elem, image->sha256);
+#ifdef CONFIG_CHUNKED_HASH
+	if (get_chunked_hashes(p, elem, &image->chunked_hashes)) {
+		return -1;
+	}
+#endif
 
 	/*
 	 * offset can be set as number or string. As string,