When the property install-if-hash-different is true,
swupdate checks if the destination already contains
the iexpected data by checking the hash before writting.
Signed-off-by: Philippe Reynes <
philipp...@softathome.com>
---
core/cpio_utils.c | 99 +++++++++++++++++++++++++++++++++++
doc/source/sw-description.rst | 5 ++
handlers/raw_handler.c | 1 +
include/swupdate_image.h | 1 +
include/util.h | 2 +
parser/parse_external.c | 7 +++
parser/parser.c | 1 +
7 files changed, 116 insertions(+)
diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 4a8b2964..689988ff 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -593,6 +593,95 @@ static int hash_compare(void *dgst, unsigned char *hash)
return 0;
}
+static int check_hash(struct swupdate_copy *args)
+{
+ int fdout;
+ void *dgst; /* use a private context for HASH */
+ uint8_t buffer[16384];
+ ssize_t len;
+ long long nbytes;
+ int ret = 0;
+
+ if (!IsValidHash(args->hash)) {
+ ERROR("hash is invalid");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fdout = (args->out != NULL) ? *(int *)args->out : -1;
+ if (fdout < 0) {
+ ERROR("fdout is invalid");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (lseek(fdout, args->seek, SEEK_SET) < 0) {
+ ERROR("lseek has failed");
+ ret = -EIO;
+ goto out;
+ }
+
+ dgst = swupdate_HASH_init(SHA_DEFAULT);
+ if (!dgst) {
+ ERROR("Cannot initialize the hash");
+ ret = -EFAULT;
+ goto out_lseek;
+ }
+
+ nbytes = args->nbytes;
+
+ while (nbytes > 0) {
+ size_t count = sizeof(buffer) < nbytes ? sizeof(buffer) : nbytes;
+ len = read(fdout, buffer, count);
+ if (len < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ ERROR("Failure in stream %d: %s", fdout, strerror(errno));
+ ret = -EFAULT;
+ goto out_lseek;
+ }
+ if (swupdate_HASH_update(dgst, buffer, len) < 0) {
+ ERROR("Cannot update the hash");
+ ret = -EFAULT;
+ goto out_lseek;
+ }
+
+ nbytes -= len;
+ }
+
+ /*
+ * SHA256_HASH_LENGTH should be enough but openssl might write
+ * up to EVP_MAX_MD_SIZE = 64 bytes (sha512 size)
+ */
+ unsigned char md_value[64];
+ unsigned int md_len = 0;
+
+ if (swupdate_HASH_final(dgst, md_value, &md_len) < 0) {
+ ERROR("Cannot compute final hash");
+ ret = -EFAULT;
+ goto out_lseek;
+ }
+
+ if (md_len != SHA256_HASH_LENGTH || swupdate_HASH_compare(args->hash, md_value)) {
+ TRACE("hash is different");
+ ret = -EFAULT;
+ goto out_lseek;
+ }
+
+ out_lseek:
+ /* come back at the beginning of the file */
+ if (lseek(fdout, 0, SEEK_SET) < 0) {
+ ERROR("lseek to 0 has failed");
+ return -EIO;
+ }
+
+ out:
+
+ return ret;
+}
+
int copyfile(struct swupdate_copy *args)
{
unsigned int percent, prevpercent = 0;
@@ -788,6 +877,15 @@ int copyfile(struct swupdate_copy *args)
}
}
+ if (args->check_hash) {
+ TRACE("Checking hash on the destination");
+ if (!check_hash(args)) {
+ TRACE("This file is already on the destination => skipping");
+ ret = 0;
+ goto copyfile_exit;
+ }
+ }
+
if (args->seek) {
int fdout = (args->out != NULL) ? *(int *)args->out : -1;
if (fdout < 0) {
@@ -915,6 +1013,7 @@ int copyimage(void *out, struct img_type *img, writeimage callback)
.offs = (unsigned long*)&img->offset,
.seek = img->seek,
.skip_file = 0,
+ .check_hash = img->install_if_hash_different,
.compressed = img->compressed,
.checksum = &img->checksum,
.hash = img->sha256,
diff --git a/doc/source/sw-description.rst b/doc/source/sw-description.rst
index 2c1e0017..03c4f299 100644
--- a/doc/source/sw-description.rst
+++ b/doc/source/sw-description.rst
@@ -1533,6 +1533,11 @@ There are 4 main sections inside sw-description:
| | | | compared with the entries in |
| | | | sw-versions |
+-------------+----------+------------+---------------------------------------+
+ | install-if\ | bool | images | flag |
+ | -hash-\ | | files | if set, the hash of the image on the |
+ | different | | | board is compared with the hash in |
+ | | | | sw-description |
+ +-------------+----------+------------+---------------------------------------+
| encrypted | string | images | string to indicate the artefact is |
| | | files | encrypted with this cipher. |
| | | scripts | e.g 'encrypted = "aes-cbc"'. |
diff --git a/handlers/raw_handler.c b/handlers/raw_handler.c
index 08912f18..c82d18af 100644
--- a/handlers/raw_handler.c
+++ b/handlers/raw_handler.c
@@ -15,6 +15,7 @@
#include <linux/fs.h>
#endif
+#include "swupdate_crypto.h"
#include "swupdate_image.h"
#include "handler.h"
#include "util.h"
diff --git a/include/swupdate_image.h b/include/swupdate_image.h
index 0d2796a6..cc376b90 100644
--- a/include/swupdate_image.h
+++ b/include/swupdate_image.h
@@ -63,6 +63,7 @@ struct img_type {
char ivt_ascii[33];
char aes_ascii[65]; /* AES_256_KEY_LEN*2+1 */
bool install_directly;
+ bool install_if_hash_different;
int is_script;
int is_partitioner;
struct dict properties;
diff --git a/include/util.h b/include/util.h
index cb90917f..f5e1c7b9 100644
--- a/include/util.h
+++ b/include/util.h
@@ -85,6 +85,8 @@ struct swupdate_copy {
unsigned long long seek;
/* skip callback: only verify input */
int skip_file;
+ /* Check if the output has already the expected data */
+ int check_hash;
/* decompression to use */
enum compression_type compressed;
/* cpio crc checksum */
diff --git a/parser/parse_external.c b/parser/parse_external.c
index e63058f2..58877525 100644
--- a/parser/parse_external.c
+++ b/parser/parse_external.c
@@ -105,6 +105,12 @@ static void sw_set_install_if_higher(struct img_type *img, const char *value)
img->id.install_if_higher = 1;
}
+static void sw_set_install_if_hash_different(struct img_type *img, const char *value)
+{
+ (void)value;
+ img->install_if_hash_different = 1;
+}
+
static const struct stream_handler_entry handlers[] = {
{ "type", sw_set_type },
{ "filename", sw_set_filename },
@@ -125,6 +131,7 @@ static const struct stream_handler_entry handlers[] = {
{ "installed-directly", sw_set_install_directly },
{ "install-if-different", sw_set_install_if_different },
{ "install-if-higher", sw_set_install_if_higher },
+ { "install-if-hash-different", sw_set_install_if_hash_different },
};
static void sw_append_stream(struct img_type *img, const char *key,
diff --git a/parser/parser.c b/parser/parser.c
index 38aba0bc..3a155002 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -519,6 +519,7 @@ static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
GET_FIELD_BOOL(p, elem, "preserve-attributes", &image->preserve_attributes);
GET_FIELD_BOOL(p, elem, "install-if-different", &image->id.install_if_different);
GET_FIELD_BOOL(p, elem, "install-if-higher", &image->id.install_if_higher);
+ GET_FIELD_BOOL(p, elem, "install-if-hash-different", &image->install_if_hash_different);
if ((encrypted = get_field_string(p, elem, "encrypted")) != NULL) {
image->is_encrypted = true;
--
2.43.0