The Embedded Software Developer diaries gopher://example.conf:70/1/esd-diaries/ Hardening dropbear gopher://example.conf:70/0/esd-diaries/2024-01-11.txt The joy of libclang in Yocto gopher://example.conf:70/0/esd-diaries/2023-10-02.txt Yocto, native and nativesdk gopher://example.conf:70/0/esd-diaries/2023-09-30.txt Notes on storage gopher://example.conf:70/0/esd-diaries/2023-04-23.txt Quest for software verification (2) gopher://example.conf:70/0/esd-diaries/2023-04-21.txt Quest for software verification gopher://example.conf:70/0/esd-diaries/2023-04-11.txt Compilation with security flags (2) gopher://example.conf:70/0/esd-diaries/2023-01-10.txt Linux explorations: flash memory (2) gopher://example.conf:70/0/esd-diaries/2022-12-28.txt common for storage, e.g. USB drives, [e]MMC... * Common: Reset of a block turns every bit into 1. Programming turns selected bits into 0. It is feasible (not necessarily implemented) to update words as long as done by turning further 1 bits into 0. * Serial Flash (e.g. via SPI bus): Common as it makes the PCB design simpler. A RAM buffer might be placed between the SPI bus and the flash, to increase the speed of data modifications. A RAM buffer might be placed between the SPI bus and the CPU, to improve speed (code shadowing). == 2. MTD documentation http://www.linux-mtd.infradead.org/doc/general.html I found this one interesting: http://www.linux-mtd.infradead.org/doc/nand.html ]]> Linux explorations: flash memory (1) gopher://example.conf:70/0/esd-diaries/2022-12-27.txt Compilation with security flags (1) gopher://example.conf:70/0/esd-diaries/2022-12-22.txt write beyond boundary overwrites them). Would it work to have an upwards-growing stack? https://security.stackexchange.com/questions/44801/smashing-the-stack-if-it-grows-upwards Short answer: no, it just improves the protection of the "closest" stack frame, but that's hardly an improvement. == 5. Also Keep intermediate object codes with CMake: pass '--debug-trycompile' when invoking cmake. == 6. Updates (edit from a few days later) After studying the matter, and getting some clue on how stack smashing protection works, I started to experiment on the target system. The target is a bare-metal build (no operating system) on a ARM CPU. We are using Newlib, in which I could find some code implementing some stack smashing protection. Such code relies on file descriptors and such, which are not available in our firmware. So I was expecting -D_FORTIFY_SOURCE to produce some link-time issues at least, but I did not see anything. Unsurprisingly, I tried to smash the stack on purpose with no effect. Then I did a comparison among binaries compiled with and without the macro: nothing changed at all. Later (next working day) I gave another try, using -fstack-protector instead of _FORTIFY_SOURCE. This time I started to see some linking problem, which meant I was on the right track. A quick analysis of the object file (`objdump -t`) showed that the compiled code was depending on a symbol called __stack_chk_fail. A disassembly (`objdump -D`) showed how this is implemented: a canary value and conditional jump (assembly instruction bl) to __stack_chk_fail. I used the --wrap linker flag to replace the unsuitable __stack_chk_fail handler from Newlib with a function called __wrap___stack_chk_fail, that I implemented. The handler implementation is simple: print an error message on the UART and halt the firmware execution. A little but nice detail is that the error message shows the content of the lr register. The lr register is set with the return address by the bl assembly instruction, so by printing it the handler can tell were, in the object code, the stack smashing happened. ]]> U-boot environment again. gopher://example.conf:70/0/esd-diaries/2022-12-09.txt Reading ARM docs gopher://example.conf:70/0/esd-diaries/2022-11-01.txt Yocto, deploy.bbclass and dependencies gopher://example.conf:70/0/esd-diaries/2022-10-12.txt X (Y depends on X) will ensure that the sysroot of Y will be populated with the artefacts installed (do_install) by the recipe X. 2. The sysroot is meant for things that should appear on the filesystem in the linux userspace. This is not the case for the kernel, or u-boot (quoting qshultz) 3. There's no guarrantee that the files of X would be deployed by the time do_configure starts in Y (quoting vm1). DEPENDS doesn't give warranty binaries are deployed (confirmed by qshultz) 4. If deployed artifacts from X are needed in Y's do_compile, a dependency can be specified in a way that looks like this (quoting qshultz, not verified): do_compile[depends] += "do_deploy:recipeX" Example: trusted firmware needed for compiling u-boot, not meaningful in the sysroot. [1] https://docs.yoctoproject.org/ref-manual/variables.html#term-DEPLOYDIR [2] https://docs.yoctoproject.org/ref-manual/variables.html#term-DEPLOY_DIR_IMAGE ]]> Acquired wisdom gopher://example.conf:70/0/esd-diaries/2022-07-15.txt What the heck does that mean? gopher://example.conf:70/0/esd-diaries/2022-07-13.txt Readings of the day gopher://example.conf:70/0/esd-diaries/2022-07-08.txt Readings of the day gopher://example.conf:70/0/esd-diaries/2022-07-06.txt A quick recap gopher://example.conf:70/0/esd-diaries/2022-06-29.txt The unreasonable difficulty of string-to-number gopher://example.conf:70/0/esd-diaries/2022-05-11.txt is included. 4. Bonus gotcha: strtoul seems to happily accept negative integers. In other words, `strtoul("-123", NULL, 10)` will return `(unsigned long)-123`. This works at least on glibc. I should check if this holds everywhere. Astonished at first, I started to find it reasonable, after reading paragraph 6.3.1.3 of the C standard: When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged. Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type. Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised. Yet, this might lead to bad surprises! ~~~ A big shout out to the good folks in #c, on freenode! References: [1] https://en.cppreference.com/w/c/language/generic [2] https://www.iso-9899.info/n1570.html#6.2.5p15 [3] http://www.iso-9899.info/n1570.html#FOOTNOTE.45 ]]> Readings of the day gopher://example.conf:70/0/esd-diaries/2022-04-06.txt