Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WiP change Intel PHYsical mac (gbe) from Heads #1195

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

tlaurion
Copy link
Collaborator

@tlaurion tlaurion commented Aug 1, 2022

- Addition of nvmutil (nvm) from osboot project to play with gbe (Thanks @githubisnonfree!)
- Addition of ifdtool from coreboot project to extract gbe
  - As of now, its implemented in a hacky way:
    - ifdtool dir is copied over ifdtool_cross at coreboot's module configure step
    - then initrd packing step checks for CONFIG_NVMUTIL and builds and pack ifdtool_cross/ifdtool
    - As a result, what is build under build/coreboot/$BOARD is coreboot's real, where build/coreboot/ content follows Makefile rules
- CONFIG_NVMUTIL in board config adds both ifdtool_cross/ifdtool and nvmutil into initrd
- Added CONFIG_NVMUTIL to all hotp-maximized boards (to test for
 size changes)

Manually tested (working!):
- backup rom from: `flashrom -p internal -r /tmp/backup.rom`
- go to that dir: `cd /tmp`
- extract gbe from ifdtool on backup.rom: `ifdtool -x backup.rom`
- show current PHY mac address: `nvm flashregion_3_gbe.bin dump`
- change mac from nvm on extracted gbe (random): `nvm flashregion_3_gbe.bin setmac`
- show mac to be changed: `nvm flashregion_3_gbe.bin dump`
- insert modified gbe into backup.rom.new with ifdtool: `ifdtool -i gbe:flashregion_3_gbe.bin backup.rom`
- flash back modified gbe only through flashrom: `flashrom -p internal --ifd -i gbe -w backup.rom.new`

Question now is what is the proper workflow from here. New menu options from configuration menu?

  • Generate new MAC address -> show mac address : flash ROM with new mac address (Yes: flash, No: Generate new MAC)
  • Specify new MAC Addresss -> go to console prompt for user to set new mac, validate with nvm output on extracted gbe.bin insertion -> flash if valid?

Fixes #916

@weyounsix
Copy link

weyounsix commented Aug 2, 2022

the flash rom gui menu could use a tweak already IMO. i would like to see all options merged into submenus. It would be nice have it go like this:

Flash New Rom > GPG Settings > MAC Settings > Mount USB and Select rom/GPG > Confirmation

GPG Settings:
- Keep Current GPG
- Add New GPG from USB
- Clean Flash (generate GPG later)

MAC Settings:
- Keep Current MAC
- Generate New MAC
- Specify New MAC

**Mount USB and Select rom/GPG**

Confirmation Dialog: 
- Old Heads vs New Heads version
- Old GPG vs New GPG
- Old MAC vs New MAC

**Flash/Cancel**

first option on both prompts retains settings, making routine updates as simple as possible.

maybe worth noting that the "add to standalone bios and re-flash" options in the existent gpg options menu could be removed as redundant if the Flash menu gets retooled this way.

@Thrilleratplay
Copy link
Contributor

@tlaurion I like this approach. I would be concerns that if a user flashed a maximized version over the standard HEADS rom then modified the MAC address before rebooting then the depending on if flashrom read the IFD from the buffer or from the chip may write to the wrong location. This would prevent that.

An input mask allowing only hex-ish characters (0-9A-F and a-f, :, ) where any missing characters are padded with zeros then sent through sed/tr to be only `0-9A-F``, would prevent the need for a complicated MAC check.

@githubisnonfree
Copy link

i try to be as correct as possible with what status is returned on exit from nvmutil. you can pretty much just run it and do || in your shell script to make it crap out if there's a problem (e.g. invalid checksum, invalid mac address) etc

so like, your build system would let the user specify a mac address and your build system could just...

./nvm gbe.bin setmac macaddresshere || exit 1

or whatever you want after that ||

that's the way i do it in osboot, the simple way. fail early, fail hard is the way i generally do things

@githubisnonfree
Copy link

by the way, this should work on basically all intel ifd based machines, all those gbe regions have the same layout in them, and nvmutil intentionally dosen't set anything unless the checksum is correct, to guard against a future possibility that intel changes it; presumably they'd use a different checksum validation then, or maybe put it in a different place

but it should work just fine on all the thinkpads you support. works on x200/t400 etc aswell. i also use it on t440p machines

@githubisnonfree
Copy link

githubisnonfree commented Aug 2, 2022

i actually checked linux src and pretty much all these nics use that same algorithm for checksum: the words must add up to 0xBABA, and mac address is first 3 words

(linux verifies the checksum before doing anything with the nic, and will actually refuse to set up your nic if both checksums are bad)

@githubisnonfree
Copy link

btw small nitpick it's call nvmutil, not nvmtool

@tlaurion tlaurion force-pushed the igbe_nvmtool_ifdtool_addition branch 2 times, most recently from 01da904 to 78af41d Compare August 2, 2022 18:29
@tlaurion
Copy link
Collaborator Author

tlaurion commented Aug 2, 2022

@tlaurion I like this approach. I would be concerns that if a user flashed a maximized version over the standard HEADS rom then modified the MAC address before rebooting then the depending on if flashrom read the IFD from the buffer or from the chip may write to the wrong location. This would prevent that.

@Thrilleratplay : Yeah thought about that. We could wrap around checking the output of flashrom -p internal output to see if no warning are given there.

An input mask allowing only hex-ish characters (0-9A-F and a-f, :, ) where any missing characters are padded with zeros then sent through sed/tr to be only `0-9A-F``, would prevent the need for a complicated MAC check.

@Thrilleratplay : We could, or we could base ourselves on the validation made by nvmutil (nv). I prefer the latest.

Long term (PR welcome) we could also borrow other MAC randomization tweaks. Some router will not permit some non existing OUI. So it would be logical to randomize only in the "Intel Corp" OUI space but there I do not want to go beyond user's needs?

i try to be as correct as possible with what status is returned on exit from nvmutil. you can pretty much just run it and do || in your shell script to make it crap out if there's a problem (e.g. invalid checksum, invalid mac address) etc

so like, your build system would let the user specify a mac address and your build system could just...

./nvm gbe.bin setmac macaddresshere || exit 1

or whatever you want after that ||

that's the way i do it in osboot, the simple way. fail early, fail hard is the way i generally do things

@githubisnonfree : The goal here is to build against musl-cross-make in the firmware and provide tools for users to change PHY whenever they want and flash back internally from flashrom. We could permit the user to build a ROM with a custom PHY, but that would go against reproducible goal and mode support. Unfortunately in Heads current use case, since we build ifdtool and nvutil from musl-cross-make to be packed in rom (against musl libc) we could document the process of building from the builder machine, but I kinda not see the point if the firmware is doing the proper thing, that being to pack a gbe.bin that is setuped as "DE:AD:C0:FF:EE" in the goal of having everyone having maximized builds to have reproducible roms in the long term, even if those ROMs contain a GBE, ME, IFD and BIOS regions. And have the user decide if he wants to change it. Let's not forget that user's are better having a randomized MAC setuped through NetworkManager nowadays, this feature is mainly aimed as a safeguard, and for Heads users having multiple machines to be able to connect multiple machines on LAN if they do not apply in software mac randomization.

The problem I foresee in the future is that Coreboot is starting to measure other components. 4.17 is now measuring CBFS content, and ME region is desired to be measured since forever. I do not see why GBE (and everything Intel IFD) not being measured at some point. That will modify PCR2 as of now, and in the future we will need to do some tpmfuturecalc to take that into consideration for future upgrades.... Should probably be considered in other future issues, just a note.

@weyounsix

the flash rom gui menu could use a tweak already IMO. i would like to see all options merged into submenus. It would be nice have it go like this:

Flash New Rom > GPG Settings > MAC Settings > Mount USB and Select rom/GPG > Confirmation

GPG Settings:
- Keep Current GPG
- Add New GPG from USB
- Clean Flash (generate GPG later)

MAC Settings:
- Keep Current MAC
- Generate New MAC
- Specify New MAC

**Mount USB and Select rom/GPG**

Confirmation Dialog: 
- Old Heads vs New Heads version
- Old GPG vs New GPG
- Old MAC vs New MAC

**Flash/Cancel**

first option on both prompts retains settings, making routine updates as simple as possible.

maybe worth noting that the "add to standalone bios and re-flash" options in the existent gpg options menu could be removed as redundant if the Flash menu gets retooled this way.

Unfortunately, I am not sure this would please all stake holders here, me not being convinced with the approach either, since those actions are normally desired separately, and one rarely needs to change public key (and if he desires so, can do it under GPG options).

One that wants to change all of this would most definitely simply flash a clean rom without keeping settings and hit the OEM Factory reset/Re-Ownership wizard to accomplish all of this, minus the PHY MAC changing that is subjected here.

@Thrilleratplay @githubisnonfree @weyounsix
What about simply

  • adding a new submenu only if CONFIG_NVMUTIL exists? (BOARDS should not add NVMUTIL if not supported to Change PHY MAC Address (CONFIG_NVMUTIL would need to be exported then to be under /etc/config)
  • Add logic under flash.sh to also take into account CONFIG_NVMUTIL presence, check if mac is different then DE:AD:C0:FF:EE through ifdtool -x backup.com, nvm showmac flashregion_3_gbe.bin and if different then rom, reinject user defined PHY MAC from actual rom? (Backup?)

That would not require any other logic to be modified, would have the MAC persist between firmware upgrades and let users decide if they want to change their mac address? Changing menu and orders of menu options is a complicated matter (check past PRs), where Purism and other boards constructors might not even have a Compatible Intel Ethernet card (those connectors tend to disappear, and if Ethernet port is there, they are not necessarily Intel made).

I prefer small approach and move from there.

As far as this PR goes, it is actually feature complete (but xx20 and xx30 board configurations should add the feature disabled).
A problem here is that I am pretty sure xx20 board owners will as of today not be able to even add a public key (with a picture, or circle of trust signatures included in their public key) might not even fit since this PR is including ifdtool, as all other boards (since ifdtool addition is added for ALL, including platforms that do not have Intel Firmware Descriptor (kgpe-d16 boards, Talos II etc are now including a tool that they will never use.

So basically, next steps prior of being even able to merge this is:

  • Makefile find a way to externalize ifdtool inclusion under nvmtool module? Some ideas based on the current hack on global Makefile, anyone?

@tlaurion
Copy link
Collaborator Author

tlaurion commented Aug 2, 2022

Some notes on actual problems that won't permit t420/x220/w520 to be usable.

Master build log on x220-maximized:

Name                           Offset     Type           Size   Comp
cbfs master header             0x0        cbfs header        32 none
fallback/romstage              0x80       stage           84972 none
cpu_microcode_blob.bin         0x14d00    microcode       26624 none
fallback/ramstage              0x1b580    stage           97628 none
config                         0x33340    raw               776 none
revision                       0x33680    raw               691 none
fallback/dsdt.aml              0x33980    raw             14615 none
vbt.bin                        0x37300    raw              1400 LZMA (3985 decompressed)
cmos_layout.bin                0x378c0    cmos_layout      1848 none
fallback/postcar               0x38040    stage           25816 none
fallback/payload               0x3e580    simple elf    7209415 none
(empty)                        0x71e780   null            71192 none
bootblock                      0x72fdc0   bootblock       65536 none

This PR x220-maximized build log:

FMAP REGION: COREBOOT
Name                           Offset     Type           Size   Comp
cbfs master header             0x0        cbfs header        32 none
fallback/romstage              0x80       stage           84972 none
cpu_microcode_blob.bin         0x14d00    microcode       26624 none
fallback/ramstage              0x1b580    stage           97639 none
config                         0x33340    raw               776 none
revision                       0x33680    raw               691 none
fallback/dsdt.aml              0x33980    raw             14615 none
vbt.bin                        0x37300    raw              1400 LZMA (3985 decompressed)
cmos_layout.bin                0x378c0    cmos_layout      1848 none
fallback/postcar               0x38040    stage           25816 none
fallback/payload               0x3e580    simple elf    7225799 none
(empty)                        0x722780   null            54808 none
bootblock                      0x72fdc0   bootblock       65536 none

So the addition of ifdtool alone consumes from the free space available: 71192 - 54808 = 16384 bytes
54808 bytes is still ok when we add stuff into kernel or initrd (xz compressed) but never forget that when we add stuff with cbfs, those are uncompressed. Let's also remember this is not x220-hotp-maximized which requires additional hotp binaries and libs:

x220-hotp-maximized build log from this PR

Name                           Offset     Type           Size   Comp
cbfs master header             0x0        cbfs header        32 none
fallback/romstage              0x80       stage           84972 none
cpu_microcode_blob.bin         0x14d00    microcode       26624 none
fallback/ramstage              0x1b580    stage           97639 none
config                         0x33340    raw               786 none
revision                       0x336c0    raw               691 none
fallback/dsdt.aml              0x339c0    raw             14615 none
vbt.bin                        0x37340    raw              1400 LZMA (3985 decompressed)
cmos_layout.bin                0x37900    cmos_layout      1848 none
fallback/postcar               0x38080    stage           25816 none
fallback/payload               0x3e5c0    simple elf    7233479 none
(empty)                        0x7245c0   null            47064 none
bootblock                      0x72fdc0   bootblock       65536 none

Only has 47064 bytes free after ifdtool inclusion from global Makefile change.


So merging this PR would be the first case where xx30 and xx20 would differ in features that can be offered.
#590 and some of its subtasks will probably need to be fixed prior of a merge of the current PR.

More direct todos:

@tlaurion tlaurion force-pushed the igbe_nvmtool_ifdtool_addition branch from 78af41d to 6283a3f Compare August 2, 2022 20:58
@githubisnonfree
Copy link

why not just have a script

download it into tmpfs and run it

(after checking signatures)

also, i've recently started porting openbsd userland to linux+musl, i'm months away from completing it probably but i want to replace busybox. when you take all the extra non-posix stuff away until you're left with only the same features as busybox, openbsd code is actually smaller in almost every case i've checked - even ksh is the same size as busybox sh, and that's with all the bells and whistles

i hope to have something to show later this year, that people can really use on their machines. i'm doing it for my own linux i'm working on, but you can be sure i'll be showing it to heads first: i'm doing it because i have the same problem as you: limited flash space. i want a flash distro for osboot, like heads though i'm basing my work off of alpine locally. i'll release later in the year when i have something complete

@githubisnonfree
Copy link

githubisnonfree commented Aug 2, 2022

have a look at chimera linux, they have a few nice things in it

in particular, they have almost (if not entirely, haven't looked in great detail yet) a complete freebsd-based userland on top of linux and musl

they recently ported freebsd sh to linux

freebsd sh is about 12k source lines of code, busybox sh is like 19k last time i checked. you might find more gold like that in chimera linux to try out in your project

here's posix cat for free:

https://vimuser.org/cat.c.txt

(this is my one, after stripping down the openbsd one)

edit: and to be clear i'm recommending this because i'm aware your distro has the problem: 8MB flash setups have limited feature sets due to low flash space. i'm told alpine linux is also working on their own userland but i have no idea about the status of that

@githubisnonfree
Copy link

also, i've been experimenting with various compilers and i've found that in a lot of cases, tcc produces smaller binaries than gcc or clang

in cases where gcc wins (if one of them beats tcc, it's always gcc) like with -Os and LTO, that's uncompressed binaries, those tcc-built binaries when compressed (e.g. in CBFS with LZMA!) really get quite small indeed

freebsd sh (alone) can be made to go down to about 150KB potentially and that's when i built for x86_64, for i686 you can probably get much smaller, whereas busybox ash probably can't get much smaller than say 230KB. these are uncompressed sizes btw

@githubisnonfree
Copy link

how small? well for a program that is about 300KB compiled with GCC or clang, it's not uncommon for me to see that tcc is about 150KB, half the size, and that's with stuff like -Os and -flto used in GCC

you should look into using tcc if you haven't already. it could really save a lot of space in rom when putting all these utils together. tcc is great (also called tinycc)

@tlaurion
Copy link
Collaborator Author

tlaurion commented Aug 2, 2022

@githubisnonfree all those comments unfortunately will be lost under a PR once merged. I think you of all other users (libreboot and osboot main collaborator) understand this.

All those comments are related to #590 and should be added there.

Thanks for your understanding and motivation. Getting away of dropbear would be interesting, while we accomplished a state where dropbear being stripped, as all other binaries and libraries also compressed with xz -9 and -Os missing (700kb freed) I'm not sure moving from musl to tcc is recommended here, where musl have a really good reputation on both security stability and size.

Yet again, #599 would be the place to debate those ideas not here, which will be lost in space and time soon enough tracking those ideas.

@githubisnonfree
Copy link

oh, well musl is a libc and tcc is a c compiler

i don't use github so i don't understand its nuances. i'll post on the issues instead

@tlaurion
Copy link
Collaborator Author

tlaurion commented Aug 2, 2022

@githubisnonfree sorry for the confusion, heads uses local GCC to build musl-cross-make and then builds everything with it, including coreboot's buildstack which then builds itself with it.

Not against those ideas at all, just telling you a PR (merge request equivalent) is not the place to track sidequest ideas.

Issues are. As on notabug ;)

@githubisnonfree
Copy link

i mean notabug sucks. normally i just work with people directly on irc or they email me

@weyounsix
Copy link

Unfortunately, I am not sure this would please all stake holders here, me not being convinced with the approach either, since those actions are normally desired separately, and one rarely needs to change public key (and if he desires so, can do it under GPG options).

for context: my thinking here was merely that it would be nice to only have to flash the bios once for a totally new configuration. i find it strange that gpg operations are separate, considering any such operation involves reflashing. i wouldn't advocate removing the gpg operations menu, but just to merge the relevant options for "standalone bios images" into the flash menu, so that if a new rom is being flashed (not the "running bios" gpg operations) then you are able to fully configure it in one go.

understood and no sweat if this is not desirable. just a thought.

@githubisnonfree
Copy link

@githubisnonfree sorry for the confusion, heads uses local GCC to build musl-cross-make and then builds everything with it, including coreboot's buildstack which then builds itself with it.

Not against those ideas at all, just telling you a PR (merge request equivalent) is not the place to track sidequest ideas.

Issues are. As on notabug ;)

by the way, i've made a note about musl-cross-make. it sounds like exactly the sort of thing i need in my project

@Thrilleratplay
Copy link
Contributor

@tlaurion While having a difference between the xx30 and xx20 isn't ideal, I think using nvmtool is the best approach given the restrains of size. Also keep in mind that is it isn't a feature that is completely denied to the xx20 users as they could still use do this using a prebuilt version in external storage or through an OS. They are only losing the convenience of it being built in. Hopefully, this will be short term.

@githubisnonfree
Copy link

regarding randomization

i think the best way to have random mac addresses would be to implement it in nvmutil. command syntax example:

./nvm gbe.bin setmac 00:11:22:33:44:55

This example above is setting a static address. What if I made it possible to do:

./nvm gbe.bin setmac ??:??:??:??:??:??

or maybe

./nvm gbe.bin setmac 00:?1:??:2?:33:4?:5?

See that?

Basically, any character that is ? would have nvmutil to randomly generate a number.

This is the best way, because you might want a certain pattern. For example, some Intel NICs (on x200/t400 thinkpads) start with 00:1f:16:xx:xx:xx where x characters can be anything.

@tlaurion
Copy link
Collaborator Author

tlaurion commented Aug 4, 2022

Some router will not permit some non existing OUI. So it would be logical to randomize only in the "Intel Corp" OUI space but there I do not want to go beyond user's needs?

The list of Intel Corp possible OUI is large.

This is the best way, because you might want a certain pattern. For example, some Intel NICs (on x200/t400 thinkpads) start with 00:1f:16:xx:xx:xx where x characters can be anything.

@githubisnonfree absolutely, this would fit the need, where collisions on a shared prefix should not happen on LAN.

Under Heads, we could lspci and apply Intel OUI accordingly, and/or define randomization patterns under Heads board config if users want to limit range as well.

From my limited tests, my own locally used switches never stopped me from using totally randomized Mac addresses in the past, as opposed to WiFi controllers. From my limited experience, and outside of NAC enforced network limitations (which reuses wireshark OUI list as pointed in previous post) I do not think wired MAC are filtered, but I might be wrong for certain corner cases (my Cisco switch for example permitted total local randomization as used under /etc/functions as of now under network-recovery-init under Heads, so took it as a positive PoC and good enough)

Would be a nice to have, definitely, though!

@githubisnonfree
Copy link

well C has rand() which is pretty decent. the only question is, what to use as a seed value.

a most conservative choice would be to simply fetch the current time (unix timestamp).

of course, another way is to directly read from /dev/urandom

i will think about this

@githubisnonfree
Copy link

there are libs that do randomization but for our purposes, what i want is something simple and reasonably random. this isn't AES

@githubisnonfree
Copy link

githubisnonfree commented Aug 4, 2022

i think a good sane approach is:

read from /dev/urandom, get numbers from that. urandom is sufficiently random for our purposes

or just return -2 if can't read from urandom

currently, mac address validation returns -1 if invalid mac passed. i'm designing my patch to set -2 if randomization is impossible for whatever reason, then if -2, validation says: randomization failed. then it exists with non-zero status

basically an FU to non-unix systems

@githubisnonfree
Copy link

@tlaurion i did it

patch:
https://notabug.org/osboot/nvmutil/commit/40f25c70d5fb7aeb6e56abf91e562a901c743e42

This adds randomization support for setmac, with the scheme previously described.

@githubisnonfree
Copy link

@tlaurion check again nvmutil git repo. i optimized it a ton. 11224kb compiled with tcc on my x86_64 machine

i'm planning to revive nvmutils too, with these optimized techniques from nvmutil. the benefit there is i could make for you much smaller binaries that only do single tasks

anyway, compressed with lzma, nvmutil when compiled with gcc will currently get you about 5kb, or with tcc, about 3kb. tested: with xz -9e

@githubisnonfree
Copy link

nvmutil 20220828 released!

https://notabug.org/osboot/nvmutil/src/20220828/ChangeLog.md

No new features have been added. This is a code cleanup and bugfix release.

  • General code cleanup (e.g. simpler argument handling)
  • Do not print errno 0 (fixes error when using the libc in OpenBSD)
  • Improved errno handling
  • Endianness portability re-implemented
  • The dump command no longer warns about multicast MAC addresses
    (such a warning is unnecessary, and up to the user to prevent)
  • The setmac command still prevents multicast MAC addresses being
    set, but no longer specifically warns about them (the documentation
    says not to use them already. No need to re-implement documentation
    in code)
  • Bug fix: errno now set, when an invalid file size is detected. The
    previous nvmutil version would exit (no operation) when the file size
    was wrong, but it would return with zero status. It now returns with
    non-zero status
  • The compiled binary size is still roughly the same as in the last
    release; the endianness checks increase the size, but other optimizations
    were made (e.g. cleaner argument handling). Tested with tcc on an x86_64
    machine, where a 0.16% binary size increase was observed.

I have half a mind to submit this to coreboot now. It's in a state where I'm happy for this to go in util/nvmutil in coreboot, if they'll accept it. I will think about it, before submitting the code to them.

@githubisnonfree
Copy link

https://review.coreboot.org/c/coreboot/+/67129

let's see what they do with it. i submitted nvmutil to coreboot, but adapted it for them, and renamed it (in the coreboot patch) to nvmtool; if they do merge it, and the codebases later diverge, i want there to be as little confusion as possible, hence the renaming

@tlaurion
Copy link
Collaborator Author

tlaurion commented Nov 2, 2022

@githubisnonfree no movement on coreboot review, I also see that the project hasn't changed much.
I might take a look at making this progress sooner than later if you confirm that the code is at your satisfaction level.

@githubisnonfree
Copy link

oh, yeah that code is bullet proof

@githubisnonfree
Copy link

but merge the code with the commit just after the release. with this patch included:

https://notabug.org/osboot/nvmutil/commit/debb6d58c35b7b3edce86e5ca6462aadf766487b

that fixes a non-exploitable bug, but a bug nonetheless. it was the only flaw i found really, i've audited that code heavily because i rely on it myself, in my work (i randomise the mac address on every machine i sell to customers)

@githubisnonfree
Copy link

the coreboot review is for the coreboot people to look at. i just put it on review.coreboot.org on a whim. and btw the coreboot one doesn't have the fix i just linked. so you should use nvmutil, from my notabug. cba to update the coreboot one, nobody seems interested so let's just leave it at that. cheers

@githubisnonfree
Copy link

might wanna patch up those prototypes aswell. look at the coreboot one versus the notabug one. just a really pedantic change really, that coreboot's code checker insisted i do (have variable names in prototypes. on the notabug one i just have the types declared, which imo is fine)

@githubisnonfree
Copy link

just one little quirk with nvmutil/nvmtool, and this is intentional:

if it successfully modified a file, but one of the two checksums was incorrect (with that part then not modified accordingly), the program exits with non-zero status, even if the file was successfully and correctly modified

in other words: the only time nvmutil ever returns 0 status is if it successfully opened the file, that the file was the right size, writable (if writes are to be done) and both parts of the gbe image (part 0 and 1) have correct checksums

this is intentional behaviour, but it's really implementation defined. the hardware doesn't care, and those checksums are just there for software to use or ignore

for example, you can actually patch out the checksum check in linux, and the nic will work so long as everything's correct. but by default, kernels do validate those checksums

so it seems only natural that i should make nvmutil always return 1 if one or both of the checksums is wrong

@githubisnonfree
Copy link

yeah and the program doesn't modify a part if the checksum is bad, but will modify the other part. e.g. setmac will update part 0 but not 1, if 1 has a bad checksum, and vice versa, but in that situation the program will return non-zero status

@githubisnonfree
Copy link

you can change that all up according to your preference. my code is there as a heavily audited reference that Just Works

@githubisnonfree
Copy link

i don't plan more changes to the code, at all

@githubisnonfree
Copy link

in practise, it might be desirable to have the program exit with 0 if at least 1 of the checksums are correct, because someone might store two configurations and use the "brick" command to invalidate the one they don't want to use (presumably part 1), yeah and later if they wanted to swap, they'd just do (assume part0 is correct):

./nvm gbe.bin swap

./nvm gbe.bin brick 1

./nvm gbe.bin setchecksum 0

a completely legit way to do things, and i often notice that lots of vendor gbe images have 1 bad and 1 good checksum

@githubisnonfree
Copy link

what do you think?

@githubisnonfree
Copy link

could just add a line at the end, just before it returns, saying something like

if (modified) errno = 0;

just before the return, in main()

that is, if you want to disable the behaviour, and then it'll always return success so long as the file was modified. dump would still make it exit 1 if one of the checksums was wrong, so in the code for dump, after that line where it calls validChecksum(partnum) make it just set errno to 0.

it's up to you really. you know what, wait there and i'll just patch up the code real quick to fix those prototypes

@githubisnonfree
Copy link

alright, the code is slightly more bullet proof now. i'm happy for the new nvmutil 20221103 release to be used as a reference. See:

https://notabug.org/osboot/nvmutil/src/20221103

Changes:

  • Prototypes now fully declared, with variable names
  • Fix implicit type conversion in readFromFile()
  • Always exit with zero status if the file was successfully modified.
    Previously, nvmutil would exit non-zero if one of the parts was invalid,
    even if the other was OK (and successfully modified)
  • Always exit with zero status when running dump, if at least one
    part contained a valid checksum and the file is of the correct size,
    fully readable. Previously, nvmutil would exit non-zero if one or both
    checksums was correct, but it now only does this if both are invalid

Not much different, but I addressed the issues described in previous posts. This new version is a bit more user-friendly, because of how more tolerant it is (regarding zero/non-zero status), also it's slightly more debuggable because it returns the value of errno rather than 1 if errno isn't 0, or 0 if errno 0

(the behaviour is still the same. in unix, errno is 0 unless an error was encountered and it was set, and 0 is success, and anything non-zero is fail)

@githubisnonfree
Copy link

tl;dr errno is absolute

@githubisnonfree
Copy link

in the release tag, i made sure: errno 0 is set if the file is modified in the buffered version, but only before running pwrite

that way, if there's a problem actually writing the changes back, errno (and therefore exit status) will still be non-zero

@githubisnonfree
Copy link

nvmutil 20221106 released.

https://notabug.org/osboot/nvmutil/src/20221106

Very minor bugfix release:

  • Pledge now changed to stdio rpath (instead of stdio wpath), only
    when the dump command is used. (pledge is only used on OpenBSD
    systems; an ifdef rule prevents its use on other systems)
  • Documentation inaccuracies fixed (pertaining to nvmutil exit statuses)
  • Documentation generally tidied up a bit

@githubisnonfree
Copy link

i'm 99.9% sure that the code is perfect now, or if not, any further issues found will be minor enough so as to be irrelevant for the average user

@tlaurion
Copy link
Collaborator Author

tlaurion commented Nov 6, 2022

I will stick on latest release to do testing.
My plan for the moment will be to

  • include nvmutil and ifdtool on maximized boards
  • change flash.sh to extract GBE from backup prior of internal firmware upgrade and reinject it to maintain MAC persistence
  • offer a menu option to randomize the MAC and inject it in current running ROM

Dynamic menus are not so easy to produce with whiptail. Will think about that for further steps, attempting to add a dynamic option when nvmutil is present

@githubisnonfree
Copy link

githubisnonfree commented Dec 11, 2022

The nvmutil code is 99.99% perfect now. I added the extra 0.09% since my last post here.

You should know: the nvmutil repo at the osboot project is now deader than dead. I merged osboot with libreboot, see: https://libreboot.org/news/merge.html

You can find the improved nvmutil under util/nvmutil in lbmk.git, see: https://notabug.org/libreboot/lbmk

The documentation for the assimulated lbmk version is here: https://libreboot.org/docs/install/nvmutil.html

As of this day, 11 December 2022, I can report that the following changes are present, in the lbmk version:

* b495aa09 (HEAD -> master) util/nvmutil: consistent parentheses on comparison
* 17fa25e5 util/nvmutil file reads: skip reading if errno!=0
* 27876c64 util/nvmutil: return error when fstat() is -1
* 960af2d6 (srht/master, origin/master, notabug/master) util/nvmutil: rhex(): fail if errno not zero
* 3d01cf28 util/nvmutil: minor code formatting cleanup
* a5e4416a util/nvmutil: remove errant line break
* c100dd1f util/nvmutil: missing paretheses on if statement
* 036d7107 util/nvmutil: don't initialise rbuf unless needed
* 851892b4 util/nvmutil: rename variable in hextonum
* 0bf3f1ed util/nvmutil: don't reallocate memory in hextonum
* e5a46b46 util/nvmutil: dont report bad size if /dev/urandom
* ededa5dd util/nvmutil: rename variables in hextonum
* e2e321fc util/nvmutil: use BUFSIZ for rmac size in hextonum
* a6d0112d util/nvtutil: fix out of bounds error
* 85937f3f util/nvmutil: reset errno on cmd_swap
* e8eee6dd util/nvmutil: mild refactoring
* 342e5abe util/nvmutil: improved errno handling in main
* d7465efb util/nvmutil: put hextonum in its own function
* 9e5ff5e4 util/nvmutil: move ENOTDIR check to function
* ff88cb1a util/nvmutil: further improved errno handling
* b81b51f9 util/nvmutil: remove errant code
* a94bac81 util/nvmutil: improved error handling
* 55a951a7 util/nvmutil: fix off by one bug
* 0108615f nvmutil copy/swap: actually set nvmPartModified
* 82300f4f util/nvmutil: move cmd copy to own function
* ddf3b76c util/nvmutil: move cmd swap to own function
* c2ed251c util/nvmutil: move cmd brick to own function
* eaad16ed util/nvmutil: cmd setchecksum in own function
* cea1beea util/nvmutil: split "dump" into smaller functions
* 0ae00e88 util/nvmutil: re-factor to reduce code indentation
* 0bbd4f1f util/nvmutil: write gbe files in a function
* b0f9f47e util/nvmutil: human-friendly exit messages, part 2
* 6c12afa9 util/nvmutil: more human-friendly exit messages

EDIT: I actually pushed those last three patches to notabug, since posting the above. I refer to these patches (pasted from above):

* b495aa09 (HEAD -> master) util/nvmutil: consistent parentheses on comparison
* 17fa25e5 util/nvmutil file reads: skip reading if errno!=0
* 27876c64 util/nvmutil: return error when fstat() is -1

@githubisnonfree
Copy link

I wonder if I should re-do the argument handling in nvmutil, to permit multiple operations, and/or operations on multiple files. For this, getopt would be used (just getopt, not getopt_long, because I have a special way I use just getopt, to make the code cleaner than in most other programs that use getopt, but only when you don't use the long version)

@githubisnonfree
Copy link

I committed 3 bangers to nvmutil this morning:

* 448ee510 util/nvmutil: optimise cmd_swap() further
* effcb942 util/nvmutil: greatly optimise cmd_copy()
* 6e5828e4 util/nvmutil: greatly optimise cmd_swap()

As a result of these changes, the swap and copy functions of nvmutil are much faster due to less I/O in memory.

…h gbe region(Thanks @githubisnonfree!)

- Addition of ifdtool from coreboot project to extract gbe
  - As of now, its implemented in a hacky way:
    - ifdtool dir is copied over ifdtool_cross at coreboot's module configure step
    - then initrd packing step checks for CONFIG_NVMUTIL and builds and pack ifdtool_cross/ifdtool
      - As a result, what is build under build/coreboot/$BOARD is coreboot's real, where build/coreboot/ content follows Makefile rules
    - CONFIG_NVMUTIL in board config adds both ifdtool_cross/ifdtool and nvmutil into initrd
    - Added CONFIG_NVMUTIL to limited number of boards (to test for size changes)

Manually tested (working!):
  - backup rom from: `flashrom -p internal -r /tmp/backup.rom`
  - go to that dir: `cd /tmp`
  - extract gbe from ifdtool on backup.rom: `ifdtool -x backup.rom`
  - source shell functions: `. /etc/functions`
  - show current PHY mac address: `nvm flashregion_3_gbe.bin dump`
  - generate mac address from sourced shell functions: `newmac=$(generate_random_mac_address)`
  - show new mac: `echo $newmac`
  - change mac from nvmtool on extracted gbe: `nvm flashregion_3_gbe.bin setmac $newmac`
  - insert modified gbe into backup.rom.new with ifdtool: `ifdtool -i gbe:flashregion_3_gbe.bin backup.rom`
  - flash back modified gbe only through flashrom: `flashrom -p internal --ifd -i gbe -w backup.rom.new`

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
@tlaurion tlaurion force-pushed the igbe_nvmtool_ifdtool_addition branch from a4b5381 to 08a95b4 Compare February 16, 2024 20:17
@tlaurion
Copy link
Collaborator Author

Bumped to latest nvmutil from lmbk (libreboot build system) since osboot was merged into libreboot and nvmutil has stopped changing.

@tlaurion
Copy link
Collaborator Author

Manually tested (working!):

  • backup rom from: flashrom -p internal -r /tmp/backup.rom
  • go to that dir: cd /tmp
  • extract gbe from ifdtool on backup.rom: ifdtool -x backup.rom
  • show current PHY mac address: nvm flashregion_3_gbe.bin dump
  • change mac from nvm on extracted gbe (random): nvm flashregion_3_gbe.bin setmac
  • show mac to be changed: nvm flashregion_3_gbe.bin dump
  • insert modified gbe into backup.rom.new with ifdtool: ifdtool -i gbe:flashregion_3_gbe.bin backup.rom
  • flash back modified gbe only through flashrom: flashrom -p internal --ifd -i gbe -w backup.rom.new

@tlaurion
Copy link
Collaborator Author

tlaurion commented Feb 16, 2024

So next steps here would be

On firmware upgrade:

  • if NVMRAMUTIL defined in board config, we have ifdtool and nvm
    • On flashing of firmware image, if we have ifdtool and nvm
      • on reading of SPI backup, extract ifd regions to /tmp
      • dump mac from gbe, show on screen as info
      • prior of flashing of new rom, inject extracted gbe region into new image prior of flashing

Config:

  • If NVRAMUTIL defined in board config, we have ifdtool and nvm
    • If generate new random mac option selected, read backup, ifdtool -x to get gbe, nv gbe setmac (show mac), ifdtool -i gbe:flashregion_3.bin to backup, flash backup.new

Next would be to set static mac desired but not really a requirement (OS can set static mac per profile, also randomize further. Idea here is to have static MAC in firmware but permit to randomize it and keep it across upgrades so that rom is reproducible per build but kept customized on final machine).

…: with host tools for coreboot and muslt-cross-make for inclusion under tools.cpio

Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature: randomize GBE MAC address from Heads
4 participants