ubootenv and security

59 views
Skip to first unread message

Łukasz Zemła

unread,
Apr 24, 2019, 7:38:26 AM4/24/19
to swupdate
Hello,

This may be a little OT, but I'd like to ask how anyone of you deal with ubootenv and security / SecureBoot.
In general, swupdate requires write access to mtd partition storing U-Boot env. So, if intruder gains access to that partition, he may modify ANY env variable, including most critical ones like bootcmd, bootargs - resulting in booting for example different kernel, bypassing FIT authentication (verify=no), etc.
How to prevent that?

From Security point of view, the best would be to configure U-Boot with CONFIG_ENV_IS_NOWHERE, but then we have to write own Linux '(swupdate) <-> U-Boo't communication mechanism by hand (we lose benefits provided by U-Boot env, like redundancy, checksums, etc.). Have anyone tried to implement some other machanism, like CONFIG_ENV_IS_NOWHERE with whitelists (where only swupdate flags are read from env partition, the other ones like bootcmd are read from U-Boot binary)? Or use 2 U-Boot env partitions - one (write protected) for critical variables, the other one for swupdate variables? Other solutions?

Best regards,
Lukasz

Stefano Babic

unread,
Apr 24, 2019, 9:04:06 AM4/24/19
to Łukasz Zemła, swupdate
Hi Łukasz,

On 24/04/19 13:38, Łukasz Zemła wrote:
> Hello,
>
> This may be a little OT,

It is not.

> but I'd like to ask how anyone of you deal with
> ubootenv and security / SecureBoot.

Yes.

> In general, swupdate requires write access to mtd partition storing
> U-Boot env. So, if intruder gains access to that partition, he may
> modify ANY env variable, including most critical ones like bootcmd,
> bootargs - resulting in booting for example different kernel, bypassing
> FIT authentication (verify=no), etc.

Right.

> How to prevent that?

Let's start with the history. A thread on both U-Boot and SWUpdate MLs :

http://u-boot.10912.n7.nabble.com/SWUpdate-U-Boot-environment-library-dependency-td340530.html#a348700

This has already touched some of this requiremennts. The thing is not
only that the MTD are writable. An attacker can take the device and via
a flash programmer change it (or destroying) to change the behavior.

U-Boot was not thought from the beginning with security in mind and this
is also not the main focus for the bootloader. A bootloader must start
the kernel in the smallest amount of time.

To ensure that the environment is not touched by attacker, I have used
environment flags. In fact, each variable has some associate flags and
it is possible to set variable / scripts as readonly. This forbids that
a variable can be changed from the default, even if the environment in
flash contains a new value.
flags can set the type for a variable (integer/string/boolean). Setting
most variable as integer (strings is default) avoids that an attacker
can insert an own script in the boot process.

Just one variable indicating which software-set must be booted can be
modified by SWUpdate. But again, this variable is of type "int", and no
script can be inserted by malware.

However, this process requires a high effort - I had to check each
variable, and the device was then reviewed by an external company (they
do review for security) to verify that there are no leaks.

Not only, a patch (not applied to U-Boot because conflicts with other
things..) must be applied to U-Boot to be sure that the default
environment is always loaded before the environment in flash - this
allows to verify the flags for each variable.

Another option I would like to propose (and you gave me the chance,
thanks !) is to sign the environment. U-Boot has already the possibility
to verify an image (a public key is not a problem). Such as extension
could flow easy into U-Boot. The environment must then be signed in user
space by SWUpdate. It remains the general problem how to hide the key,
but this can be done with TPM or if rootfs is encrypted.

This is also a reason for me to start the "libubootenv" project, because
it is independent from U-Boot (it could be extended to other
bootloaders, too) and it is easier to add new features. This library can
be extended to sign the environment, and the bootloader must verify it.
As drawback, "saveenv" in U-Boot is lost, because U-Boot cannot sign -
but if security is requested, some compromises must be accepted.

Apart how to store the key (this is often project specific), it is me
clear what is possible to do, I need sponsors for that ;-)

>
> From Security point of view, the best would be to configure U-Boot with
> CONFIG_ENV_IS_NOWHERE,

This does not work in case of update because there is no way to
communicate with the bootloader.

> but then we have to write own Linux '(swupdate)
> <-> U-Boo't communication mechanism by hand

By hand ? Anyway, you are just moving the problem away. You still need a
safe way that U-Boot can trust it. Then this can be solved by verifying
the environment, isn't it ?

> (we lose benefits provided
> by U-Boot env, like redundancy, checksums, etc.). Have anyone tried to
> implement some other machanism, like CONFIG_ENV_IS_NOWHERE with
> whitelists

whitelists are the "flags" in u-boot, see above. Rather, there is no
"whitelists" itself and each variable must be checked and set.

> (where only swupdate flags are read from env partition, the
> other ones like bootcmd are read from U-Boot binary)?

See above.

> Or use 2 U-Boot
> env partitions - one (write protected) for critical variables, the other
> one for swupdate variables?

This does not help - again, it moves the issue. You can also try to
"write protect" a partition, but this protection is useless with
external tools.

> Other solutions?

See above.

Best regards,
Stefano Babic


--
=====================================================================
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sba...@denx.de
=====================================================================

Łukasz Zemła

unread,
Apr 25, 2019, 11:48:46 AM4/25/19
to swupdate
On Wednesday, April 24, 2019 at 3:04:06 PM UTC+2, Stefano Babic wrote:
[...]

> Let's start with the history. A thread on both U-Boot and SWUpdate MLs :
>
> http://u-boot.10912.n7.nabble.com/SWUpdate-U-Boot-environment-library-dependency-td340530.html#a348700
>
> This has already touched some of this requiremennts. The thing is not
> only that the MTD are writable. An attacker can take the device and via
> a flash programmer change it (or destroying) to change the behavior.

Well... I am afraid mostly of ability to modify remotely 'bootcmd', 'bootargs' and 'verify'.
If someone has physical access to flash memory, then device
is in big troubles and almost everything may happen.

[...]

> To ensure that the environment is not touched by attacker, I have used
> environment flags. In fact, each variable has some associate flags and
> it is possible to set variable / scripts as readonly. This forbids that
> a variable can be changed from the default, even if the environment in
> flash contains a new value.
> flags can set the type for a variable (integer/string/boolean). Setting
> most variable as integer (strings is default) avoids that an attacker
> can insert an own script in the boot process.
>
> Just one variable indicating which software-set must be booted can be
> modified by SWUpdate. But again, this variable is of type "int", and no
> script can be inserted by malware.
>
> However, this process requires a high effort - I had to check each
> variable, and the device was then reviewed by an external company (they
> do review for security) to verify that there are no leaks.
>
> Not only, a patch (not applied to U-Boot because conflicts with other
> things..) must be applied to U-Boot to be sure that the default
> environment is always loaded before the environment in flash - this
> allows to verify the flags for each variable.

Is everything in the quoted block above (starting with 'To ensure that environment
is not touched') part of your U-boot patch?

As far as I know U-Boot, access flags are only gentleman agreement which
are promised to be obeyed by fw_setenv/libubootenv and U-Boot itself. Intruder may use
his own version of fw_setenv/library which will just ignore flags.
Eventually he may overwrite complete ENV by image with all flags as he wishes.


> Another option I would like to propose (and you gave me the chance,
> thanks !) is to sign the environment. U-Boot has already the possibility
> to verify an image (a public key is not a problem). Such as extension
> could flow easy into U-Boot. The environment must then be signed in user
> space by SWUpdate. It remains the general problem how to hide the key,
> but this can be done with TPM or if rootfs is encrypted.

Most probably/precisely signing environment should be done in libubootenv -
to be able to share this functionality to custom userspacve programs.


> This is also a reason for me to start the "libubootenv" project, because
> it is independent from U-Boot (it could be extended to other
> bootloaders, too) and it is easier to add new features.

Just a stupid question - is U-Boot environment format portable across all
U-Boot versions? Let's say 2014.10 and latest master?

[...]

> >
> > From Security point of view, the best would be to configure U-Boot with
> > CONFIG_ENV_IS_NOWHERE,
>
> This does not work in case of update because there is no way to
> communicate with the bootloader.

For that purpose, we may use another MTD partition (where critical U-Boot variables
are not stored)


> > but then we have to write own Linux '(swupdate)
> > <-> U-Boo't communication mechanism by hand
>
> By hand ?

I meant 'manually implement/duplicate environment functions to operate on separate MTD partition'.


> Anyway, you are just moving the problem away. You still need a
> safe way that U-Boot can trust it. Then this can be solved by verifying
> the environment, isn't it ?

Then I am making some step - modification of critical U-Boot variables is not possible.
There is still problem of trust, but side effects are a way smaller: in symmetric mode
intruder may force to run older version of the system. In asymmetric mode, force system
to boot and stay in recovery waiting for new .swu file.
In my case, recovery system expects to find already downloaded swu file at known location.
If file is missing or authentication fails, then recovery may switch the gear again and reboot
to Linux.
But in general - yes, you are absolutely right about signing environment.

The other workaround which came to my mind is to patch U-Boot to ignore completely
bootcmd/bootargs and just hardcode equivalent actions in C code. This way U-Boot reads
swupdate flags only (yes - we have again mentioned by you 'trust' problem) and then makes
approporiate C-only actions. But I am not sure about overall effort (don't know how deeply
environment variables are tight into U-Boot.).
 
Best regards,
Lukasz

Stefano Babic

unread,
Apr 25, 2019, 12:14:15 PM4/25/19
to Łukasz Zemła, swupdate
Hi Łukasz,

On 25/04/19 17:48, Łukasz Zemła wrote:
> On Wednesday, April 24, 2019 at 3:04:06 PM UTC+2, Stefano Babic wrote:
> [...]
>> Let's start with the history. A thread on both U-Boot and SWUpdate MLs :
>>
>>
> http://u-boot.10912.n7.nabble.com/SWUpdate-U-Boot-environment-library-dependency-td340530.html#a348700
>>
>> This has already touched some of this requiremennts. The thing is not
>> only that the MTD are writable. An attacker can take the device and via
>> a flash programmer change it (or destroying) to change the behavior.
>
> Well... I am afraid mostly of ability to modify remotely 'bootcmd',
> 'bootargs' and 'verify'.> If someone has physical access to flash memory, then device
> is in big troubles and almost everything may happen.

Not true - if someone can do remotely, you have another problem that is
not addressed here. That meansm your device is not safe enough and it
gets exploited. These are two different topic: in fact, if an attacker
gets a root shell remotely, he can also write to any MTD partition he
wants. If a real "secure boot" is provided, the whole trust of chain
must not be broken, starting from the bootloader that *must* be verified
by the SOC.

>
> [...]
>> To ensure that the environment is not touched by attacker, I have used
>> environment flags. In fact, each variable has some associate flags and
>> it is possible to set variable / scripts as readonly. This forbids that
>> a variable can be changed from the default, even if the environment in
>> flash contains a new value.
>> flags can set the type for a variable (integer/string/boolean). Setting
>> most variable as integer (strings is default) avoids that an attacker
>> can insert an own script in the boot process.
>>
>> Just one variable indicating which software-set must be booted can be
>> modified by SWUpdate. But again, this variable is of type "int", and no
>> script can be inserted by malware.
>>
>> However, this process requires a high effort - I had to check each
>> variable, and the device was then reviewed by an external company (they
>> do review for security) to verify that there are no leaks.
>>
>> Not only, a patch (not applied to U-Boot because conflicts with other
>> things..) must be applied to U-Boot to be sure that the default
>> environment is always loaded before the environment in flash - this
>> allows to verify the flags for each variable.
>
> Is everything in the quoted block above (starting with 'To ensure that
> environment
> is not touched') part of your U-boot patch?

The patch just loads the "initial" environment (that means, the
environment if flash is corrupted) *before* loading the environment from
flash. In this way, flags are active and verified. If an attacker has
changed the environment on flash, this has no consequence because ro
variable are checked before applying the loaded env.

>
> As far as I know U-Boot, access flags are only gentleman agreement which
> are promised to be obeyed by fw_setenv/libubootenv and U-Boot itself.

flags are verified by U-Boot, they are not just something cosmetic in
fw_setenv

> Intruder may use
> his own version of fw_setenv/library which will just ignore flags.

And ? It does not matter. As I say, he could also turn off the device,
rewrite the MTD partitions with an external programmer. But his
environment is not taken, even if it has a valid CRC (the trick is the
patch I mentioned before).

> Eventually he may overwrite complete ENV by image with all flags as he
> wishes.

It does not matter, his environment has no worth. flags are set in the
initial environment, that means together with CONFIG_EXTRA_ENV. And if
secure boot is active, this image is verified by the SOC itself.

He can replace completeley the environment in flasg, U-Boot will discard
it if it does not comply to the linked flags.

>
>> Another option I would like to propose (and you gave me the chance,
>> thanks !) is to sign the environment. U-Boot has already the possibility
>> to verify an image (a public key is not a problem). Such as extension
>> could flow easy into U-Boot. The environment must then be signed in user
>> space by SWUpdate. It remains the general problem how to hide the key,
>> but this can be done with TPM or if rootfs is encrypted.
>
> Most probably/precisely signing environment should be done in libubootenv -
> to be able to share this functionality to custom userspacve programs.

That is correct - libubootenv should sign, and U-Boot can verify it. The
code to verify an image signed with a RSA key is already in U-Boot to
verify the kernel, so this looks to me a straightforward change.

>
>> This is also a reason for me to start the "libubootenv" project, because
>> it is independent from U-Boot (it could be extended to other
>> bootloaders, too) and it is easier to add new features.
>
> Just a stupid question - is U-Boot environment format portable across all
> U-Boot versions? Let's say 2014.10 and latest master?
>

Yes, it is. Even an older U-Boot 200X.XX is compatible. The format on
the storage is the same and part of U-Boot API. How the environment is
handled internally, is changed with the time - the big change was with
the introduction of the "env" command.

> [...]
>> >
>> > From Security point of view, the best would be to configure U-Boot with
>> > CONFIG_ENV_IS_NOWHERE,
>>
>> This does not work in case of update because there is no way to
>> communicate with the bootloader.
>
> For that purpose, we may use another MTD partition (where critical
> U-Boot variables
> are not stored)

You are just adding complexity without solving the problem - in some
way, U-Boot must load both environment, and an attacker can change both
of them.

>
>> > but then we have to write own Linux '(swupdate)
>> > <-> U-Boo't communication mechanism by hand
>>
>> By hand ?
>
> I meant 'manually implement/duplicate environment functions to operate
> on separate MTD partition'.

I do not see that you increase security.

>
>> Anyway, you are just moving the problem away. You still need a
>> safe way that U-Boot can trust it. Then this can be solved by verifying
>> the environment, isn't it ?
>
> Then I am making some step - modification of critical U-Boot variables
> is not possible.
> There is still problem of trust, but side effects are a way smaller: in
> symmetric mode
> intruder may force to run older version of the system.

True - where "--no-downgrading" is requested, the stand-by copy after a
successful update is made invalid. That means system cannot boot from
that and the attacker cannot switch.

> In asymmetric
> mode, force system
> to boot and stay in recovery waiting for new .swu file.

Treu, but this is a use case - ther eis no risk. The condition to avoid
is that an attacker can load and start its own software replacing the
delivered.

> In my case, recovery system expects to find already downloaded swu file
> at known location.
> If file is missing or authentication fails, then recovery may switch the
> gear again and reboot
> to Linux.
> But in general - yes, you are absolutely right about signing environment.

Yes

>
> The other workaround which came to my mind is to patch U-Boot to ignore
> completely
> bootcmd/bootargs and just hardcode equivalent actions in C code.

It is still not enough if you have a symmetric approach because the
software set to be booted is not fixed.

And to make the update power-cut safe, you need also to evaluate the
"recovery_status" variable set by SWUpdate in asymmetric mode.

> This
> way U-Boot reads
> swupdate flags only (yes - we have again mentioned by you 'trust'
> problem) and then makes
> approporiate C-only actions. But I am not sure about overall effort
> (don't know how deeply
> environment variables are tight into U-Boot.).

Best regards,
Reply all
Reply to author
Forward
0 new messages