Skip to content

dist/tools: add firmware metadata generator#6919

Closed
kYc0o wants to merge 6 commits intoRIOT-OS:masterfrom
kYc0o:firmware_metadata
Closed

dist/tools: add firmware metadata generator#6919
kYc0o wants to merge 6 commits intoRIOT-OS:masterfrom
kYc0o:firmware_metadata

Conversation

@kYc0o
Copy link
Contributor

@kYc0o kYc0o commented Apr 18, 2017

Since #6450 became a bit complicated to manage, I'll start to split the work in several PRs, with the aim to ease review and have a better picture of the approach.

This PR adds a firmware metadata generator, which will produce a binary file representing a structure of this kind:

typedef struct FW_metadata {
    uint8_t hash[SHA256_DIGEST_LENGTH]; /**< SHA256 Hash of firmware image */
    uint8_t shash[SIGN_LEN];            /**< Signed SHA256 */
    uint16_t version;                   /**< Integer representing firmware version */
    uint32_t size;                      /**< Size of firmware image */
    uint32_t appid;                     /**< Integer representing the application ID */
} FW_metadata_t;

as a simplified way to characterise the contents of a firmware, while adding some security features as the sha256 hash for integrity check, as well as a field for a signed hash, which will come in a following PR.

This approach will use the current RIOT implementation of sha256 to allow portability.

To test the firmware generator, you can run the following command for any RIOT example or application:

make firmware-metadata VERSION=0x1 APPID=0xabcd1234

using VERSION=0x1 and APPID=0xabcd1234 as examples.

The ultimate goal is to put this metadata at the beginning of any firmware, to use it e.g. for a firmware update. This feature will come in an upcoming PR, stay tuned.

@kYc0o kYc0o added Type: new feature The issue requests / The PR implemements a new feature for RIOT Area: tools Area: Supplementary tools labels Apr 18, 2017
@kYc0o kYc0o force-pushed the firmware_metadata branch from 745cc1b to 75b06f7 Compare April 18, 2017 13:09
Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few inline comments. Didn't test locally.


#define FW_METADATA_BIN "firmware-metadata.bin"

typedef struct FW_metadata {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to follow coding conventions, why not use the explicit name: firmware_metadata ? and firmware_metadata_t below ?

Makefile.include Outdated
endif # BUILD_IN_DOCKER

firmware-metadata: all generate-metadata
$(Q)$(FW_METADATA)/bin/./generate-metadata $(BINFILE) $(VERSION) $(APPID) $(METADATA_FILE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you really need the ./ in $(Q)$(FW_METADATA)/bin/./generate-metadata ?

all: bin bin/generate-metadata

bin:
mkdir bin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe use -p to avoid messages like mkdir: cannot create directory ‘bin’: File exists

follows:

```c
typedef struct FW_metadata {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as below about structure name

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2016, Mark Solters <msolters@gmail.com>.
* 2016, Francisco Acosta <francisco.acosta@inria.fr>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should simply put Inria in the copyright

fclose(firmware_bin);

/*
* TODO Sign hash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you plan to address this ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it will come in a following up PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I guess it can be removed from this one.

}

/* Generate FW image metadata */

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this empty line is not needed


(void)argc;

if (!argv[1]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you just check argc value and display the usage in case it's < 4 ?


all: bin bin/generate-metadata

bin:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a slash bin/


CFLAGS += -g -O3 -Wall -Wextra -pedantic -std=c99

all: bin bin/generate-metadata
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove bin

bin:
mkdir bin

bin/generate-metadata: $(METADATA_HDR) $(METADATA_SRC)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

append | bin/

@kYc0o kYc0o force-pushed the firmware_metadata branch 2 times, most recently from f527342 to 13d5d9b Compare April 19, 2017 11:30
@kYc0o
Copy link
Contributor Author

kYc0o commented Apr 19, 2017

@aabadie @Kijewski Comments addressed.

bin/:
mkdir -p bin

bin/generate-metadata: bin/ $(METADATA_HDR) $(METADATA_SRC)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bin/ should be a pre-requirement instead of a requirement. A pre-requirement only needs to exist, but a newer timestamp does not force a rebuild. Creating bin/generate-metadata will touch bin/, which will tell make to recreate bin/generate-metadata in its next invocation. Pre-requirements are placed after the requirements, separated by a pipe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Ok I understand now. However, don't we actually want bin as a requirement? What's really the difference? Anyways,bin can only exists if a build was triggered, and if I understand correctly the contents cannot be changed by other means.

Copy link
Contributor

@Kijewski Kijewski Apr 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a file is changed, then the modification timestamp of its parent folder gets updated. A newer timestamp of a requirement of $X tells Make to rebuild $X (in here $X's parent directory is its requirement). So updating $X will make $X look outdated to Make. Every time you run Make it will update $X, which wastes a tiny amount of wall clock time.

As a rule of thumb directories should always be prerequirements, not requirements, unless you are doing something really odd. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thanks for the explanation, I'll modify this file accordingly.

@@ -0,0 +1,19 @@
RIOTBASE := ../../..
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line should be:

RIOTBASE ?= $(CURDIR)/../../..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think since dist/tools/ is a path that will always exists in any clone of RIOT, we don't really need to define $(CURDIR), and so the relative path will always be the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok you are right.

@kYc0o
Copy link
Contributor Author

kYc0o commented Apr 24, 2017

@Kijewski addressed.

Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few other comments

@@ -0,0 +1,35 @@
# Metadata generator for firmware verification
This program will generate a binary file containing a metadata structure as
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: use present instead of future.
This program generates a binary file...

} firmware_metadata_t;
```

This structure will be filled with the data obtained from the firmware.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: This structure is filled with...


_\<output-path\>_\: The path for fimrware_metadata.bin

The results will be printed if the operation is successful, and a binary
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, with if the sense is conditional (something like might be). Also use present:
If the operation succeeds, the results is printed out and a binary called "firmware-metadata.bin" is created (written?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at generate-metadata.c this is not totally true: the user can set a custom output filename.

fclose(firmware_bin);

/*
* TODO Sign hash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I guess it can be removed from this one.

@aabadie
Copy link
Contributor

aabadie commented May 11, 2017

@kYc0o, what's the status here ?

@kYc0o kYc0o force-pushed the firmware_metadata branch from 0048735 to a61a4d4 Compare May 11, 2017 17:56
@kYc0o
Copy link
Contributor Author

kYc0o commented May 11, 2017

Just addressed your comments.

@Kijewski Kijewski dismissed their stale review May 11, 2017 18:43

addressed

aabadie
aabadie previously approved these changes May 12, 2017
Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes are good to me here. ACK

@aabadie aabadie added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label May 12, 2017
@kYc0o
Copy link
Contributor Author

kYc0o commented May 12, 2017

@Kijewski all ok for you?

@aabadie
Copy link
Contributor

aabadie commented May 12, 2017

@kYc0o, Murdock is reporting errors, can you have a look ?

@kYc0o
Copy link
Contributor Author

kYc0o commented May 12, 2017

It's again related to the pic32 boards... @kaspar030 there is something wrong in the toolchain of Murdock2?

BTW it needs rebase.

@kYc0o
Copy link
Contributor Author

kYc0o commented May 12, 2017

BTW it needs rebase.

I meant squash.

@kYc0o kYc0o force-pushed the firmware_metadata branch from a61a4d4 to f444d1b Compare May 12, 2017 14:12

_\<appid\>_\: ID for the application in 32-bit HEX

_\<output-path\>_\: The path for fimrware_metadata.bin
Copy link
Contributor

@aabadie aabadie May 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fimrware_metadata.bin => firmware_metadata.bin


If the operation succeeds, the results are printed out and a binary called
"firmware-metadata.bin" is written, if no _output-path_ option is specified,
in which case the file is written to the given path with the given name.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in which case should be removed

@aabadie aabadie dismissed their stale review May 14, 2017 13:01

Found problems

@aabadie
Copy link
Contributor

aabadie commented May 14, 2017

Just tested it and had problems:

bin/generate-metadata ~/samr21-default.elf 1.0 1234 ~/.

generate a segfault. Here is what gdb says:

Starting program: /home/aabadie/softs/src/riot/RIOT/dist/tools/firmware_metadata/bin/generate-metadata /home/aabadie/samr21-default.elf 1.0 1234 /home/aabadie/.
Firmware bytes read: 1855452
Firmware Size: 1855452
Firmware Version: 0x1
Firmware APPID: 0x1234
Firmware HASH: ce 9c f5 56 84 44 2f 36 97 50 1f 6b 34 68 56 3f 4c 5d dc a9 a9 48 71 73 59 08 b8 1a ac 65 80 b3 
Firmware signed HASH: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
Metadata size: 76

Program received signal SIGSEGV, Segmentation fault.
__GI__IO_fwrite (buf=0x7fffffffd1d0, size=76, count=1, fp=0x0) at iofwrite.c:37
37	iofwrite.c: No such file or directory.

Leaving the output path empty works fine.


Where:

_\<firmware.bin\>\:_ The firmware in binary format
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use <firmware.bin> instead so it is better readable in raw text?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get exactly what you mean...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @kaspar030 means "use ` ` around <firmware.bin>". +1 on my side

@kYc0o kYc0o force-pushed the firmware_metadata branch from 004c495 to 9f385e4 Compare May 22, 2017 13:32
@kYc0o
Copy link
Contributor Author

kYc0o commented May 22, 2017

@aabadie addressed comments.

Your problem is that you didn't give a file name for the binary with the metadata. I fixed the README.md to be explicit about this.

Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few other comments mainly rephrasing in the README to make things crystal clear.

To use, you should call `generate-metadata` with the following arguments:

```console
./generate-metadata <firmware.bin> <version> <appid> <output-path>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<output-path> should be <output-filename> for clarity

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think <output-filename> would lead to confusion, since we need the full path plus the file name.

This structure is filled with the data obtained from the firmware.

## Usage
To use, you should call `generate-metadata` with the following arguments:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To use it, call generate-metadata with the following arguments:

_\<output-path/filename.bin\>_\: The path and name of the metadata binary file

If the operation succeeds, the results are printed out and a binary called
"firmware-metadata.bin" is written, if no _output-path_ option is specified.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing as first sight.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the confusion?

@@ -0,0 +1,36 @@
# Metadata generator for firmware verification
This program generates a binary file containing a metadata structure as
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add an empty line after title.

Quick question: does the file only contain the metadata or the metadata + the initial firmware ? If it's the second case, it should be more explicit. Otherwise, one can easily understand that the generated binary file only contain the struct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add an empty line after title.

What this will change?

uick question: does the file only contain the metadata or the metadata + the initial firmware ? If it's the second case, it should be more explicit. Otherwise, one can easily understand that the generated binary file only contain the struct.

It is the first case.


Where:

_\<firmware.bin\>\:_ The firmware in binary format
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @kaspar030 means "use ` ` around <firmware.bin>". +1 on my side

char firmware_metadata_path[128];

if (argc < 4) {
puts("Usage: generate-metadata <BINFILE> <VERSION> <APPID> [output path]");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/output path/output filename/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think output path is ok...


sha256_init(&firmware_sha256);

while((bytes_read = fread(firmware_buffer, 1, sizeof(firmware_buffer), firmware_bin))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space after while missing

/* Output metadata .bin file */
FILE *metadata_bin;

uint32_t firmware_size = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be declared static

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter for a native C program? In that case all the variables should be declared static in this program.

@kYc0o
Copy link
Contributor Author

kYc0o commented May 22, 2017

Actually, I don't think that beautify a lot the README would be of any use. This tool is not really meant to be used by a final user, but called automatically by the build system when building firmware updates like in the subsequent PRs.

@kYc0o
Copy link
Contributor Author

kYc0o commented May 23, 2017

@aabadie everything good here for you?

Copy link
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not merge this until we have a set of PR's that actually enable OTA.

@kYc0o
Copy link
Contributor Author

kYc0o commented May 23, 2017

Let's not merge this until we have a set of PR's that actually enable OTA.

What do you mean with that? I'm about to push the last PR which enables the "updates fetch" using CoAP (though the transport method is TFTP). That would be the last PR regarding this topic.

@kYc0o
Copy link
Contributor Author

kYc0o commented Jun 9, 2017

#7167 adds the firmware downloading for OTA updates. I think with this PR the firmware update functionality is complete.

@aabadie aabadie modified the milestone: Release 2017.07 Jun 26, 2017
@kYc0o
Copy link
Contributor Author

kYc0o commented Aug 7, 2017

Closing in favour of #7457.

@kYc0o kYc0o closed this Aug 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: tools Area: Supplementary tools CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants