Skip to content

dist/tools: add firmware metadata generator#6919

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

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

Conversation

@kYc0o

@kYc0o kYc0o commented Apr 18, 2017

Copy link
Copy Markdown
Contributor

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

@aabadie aabadie left a comment

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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 ?

Comment thread 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
Copy Markdown
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 ?

Comment thread dist/tools/firmware_metadata/Makefile Outdated
all: bin bin/generate-metadata

bin:
mkdir bin

Copy link
Copy Markdown
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

Comment thread dist/tools/firmware_metadata/README.md Outdated
follows:

```c
typedef struct FW_metadata {

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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 ?

Comment thread dist/tools/firmware_metadata/Makefile Outdated

all: bin bin/generate-metadata

bin:

Copy link
Copy Markdown
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/

Comment thread dist/tools/firmware_metadata/Makefile Outdated

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

all: bin bin/generate-metadata

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

remove bin

Comment thread dist/tools/firmware_metadata/Makefile Outdated
bin:
mkdir bin

bin/generate-metadata: $(METADATA_HDR) $(METADATA_SRC)

Copy link
Copy Markdown
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

kYc0o commented Apr 19, 2017

Copy link
Copy Markdown
Contributor Author

@aabadie @Kijewski Comments addressed.

Comment thread dist/tools/firmware_metadata/Makefile Outdated
bin/:
mkdir -p bin

bin/generate-metadata: bin/ $(METADATA_HDR) $(METADATA_SRC)

Copy link
Copy Markdown
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
Copy Markdown
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.

@Kijewski Kijewski Apr 20, 2017

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

kYc0o commented Apr 24, 2017

Copy link
Copy Markdown
Contributor Author

@Kijewski addressed.

@aabadie aabadie left a comment

Copy link
Copy Markdown
Contributor

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

Comment thread dist/tools/firmware_metadata/README.md Outdated
@@ -0,0 +1,35 @@
# Metadata generator for firmware verification
This program will generate a binary file containing a metadata structure as

Copy link
Copy Markdown
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...

Comment thread dist/tools/firmware_metadata/README.md Outdated
} firmware_metadata_t;
```

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

Copy link
Copy Markdown
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...

Comment thread dist/tools/firmware_metadata/README.md Outdated

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

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

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

aabadie commented May 11, 2017

Copy link
Copy Markdown
Contributor

@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

kYc0o commented May 11, 2017

Copy link
Copy Markdown
Contributor Author

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

@aabadie aabadie left a comment

Copy link
Copy Markdown
Contributor

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

kYc0o commented May 12, 2017

Copy link
Copy Markdown
Contributor Author

@Kijewski all ok for you?

@aabadie

aabadie commented May 12, 2017

Copy link
Copy Markdown
Contributor

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

@kYc0o

kYc0o commented May 12, 2017

Copy link
Copy Markdown
Contributor Author

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

BTW it needs rebase.

@kYc0o

kYc0o commented May 12, 2017

Copy link
Copy Markdown
Contributor Author

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
Comment thread dist/tools/firmware_metadata/README.md Outdated

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

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

@aabadie aabadie May 14, 2017

Copy link
Copy Markdown
Contributor

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

Comment thread dist/tools/firmware_metadata/README.md Outdated

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
Copy Markdown
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

aabadie commented May 14, 2017

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

kYc0o commented May 22, 2017

Copy link
Copy Markdown
Contributor Author

@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.

@aabadie aabadie left a comment

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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
Copy Markdown
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.

Comment thread dist/tools/firmware_metadata/README.md Outdated
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

kYc0o commented May 22, 2017

Copy link
Copy Markdown
Contributor Author

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

kYc0o commented May 23, 2017

Copy link
Copy Markdown
Contributor Author

@aabadie everything good here for you?

@kaspar030 kaspar030 left a comment

Copy link
Copy Markdown
Contributor

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

kYc0o commented May 23, 2017

Copy link
Copy Markdown
Contributor Author

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

kYc0o commented Jun 9, 2017

Copy link
Copy Markdown
Contributor Author

#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

kYc0o commented Aug 7, 2017

Copy link
Copy Markdown
Contributor Author

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