From: Bernhard Breinbauer <
bernhard....@wallner-automation.com>
---
archival/Config.src | 10 ++++++++++
core/cpio_utils.c | 39 +++++++++++++++++++++++++++++++++++++++
core/swupdate.c | 6 +++++-
include/util.h | 1 +
4 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/archival/Config.src b/archival/Config.src
index 3978ced..8d08da6 100644
--- a/archival/Config.src
+++ b/archival/Config.src
@@ -21,6 +21,16 @@ config CPIO
Unless you have a specific application which requires cpio, you
should probably say N here.
+config CPIO_VERIFY_CHECKSUM_BEFORE_UPDATE
+ bool "cpio: verify checksum before update"
+ default y
+ help
+ If activated all of the cpio archive's checksums are verified before
+ starting the update. Otherwise the checksums are verified while/after
+ the update installation.
+ As the pre-installation checksum verification takes some time, this
+ behavior can be deactivated
+
config GUNZIP
bool "gunzip"
default y
diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 877eb1e..26eaf5b 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -206,6 +206,30 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
return 0;
}
+int calc_checksum(int fdin, int nbytes, unsigned long offset,
+ uint32_t *checksum)
+{
+ unsigned long size;
+ int ret;
+
+ if (checksum)
+ *checksum = 0;
+
+ while (nbytes > 0) {
+ size = (nbytes < BUFF_SIZE ? nbytes : BUFF_SIZE);
+
+ if ((ret = fill_buffer(fdin, in, size, &offset, checksum) < 0)) {
+ return ret;
+ }
+
+ nbytes -= size;
+ }
+
+ fill_buffer(fdin, in, NPAD_BYTES(offset), &offset, checksum);
+
+ return 0;
+}
+
int extract_cpio_header(int fd, struct filehdr *fhdr, unsigned long *offset)
{
unsigned char buf[256];
@@ -348,6 +372,9 @@ off_t cpio_scan(int fd, struct swupdate_cfg *cfg, off_t start)
struct filehdr fdh;
unsigned long offset = start;
int file_listed;
+#ifdef CONFIG_CPIO_VERIFY_CHECKSUM_BEFORE_UPDATE
+ uint32_t checksum;
+#endif
while (1) {
file_listed = 0;
@@ -371,6 +398,18 @@ off_t cpio_scan(int fd, struct swupdate_cfg *cfg, off_t start)
(unsigned int)fdh.size,
file_listed ? "REQUIRED" : "not required");
+#ifdef CONFIG_CPIO_VERIFY_CHECKSUM_BEFORE_UPDATE
+ if (calc_checksum(fd, fdh.size, offset, &checksum) != 0) {
+ TRACE("Checksum calculation failed for %s\n",
+ fdh.filename);
+ return -1;
+ }
+ if ((uint32_t)(fdh.chksum) != checksum) {
+ TRACE("Checksum verification failed for %s: %x != %x\n",
+ fdh.filename, (uint32_t)fdh.chksum, checksum);
+ return -1;
+ }
+#endif
/* Skip to the end of the file */
offset += fdh.size;
diff --git a/core/swupdate.c b/core/swupdate.c
index 897d896..4eb1811 100644
--- a/core/swupdate.c
+++ b/core/swupdate.c
@@ -219,7 +219,11 @@ static int install_from_file(char *fname)
exit(1);
}
- cpio_scan(fdsw, &swcfg, pos);
+ pos = cpio_scan(fdsw, &swcfg, pos);
+ if (pos < 0) {
+ close(fdsw);
+ exit(1);
+ }
/*
* Check if all files described in sw-description
diff --git a/include/util.h b/include/util.h
index 65ed6f2..511dbf8 100644
--- a/include/util.h
+++ b/include/util.h
@@ -119,6 +119,7 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
off_t extract_sw_description(int fd);
off_t extract_next_file(int fd, int fdout, off_t start, int compressed);
int openfileoutput(const char *filename);
+int calc_checksum(int fdin, int nbytes, unsigned long offset, uint32_t *checksum);
int register_notifier(notifier client);
void notify(RECOVERY_STATUS status, int error, const char *msg);