public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Laszlo Ersek" <lersek@redhat.com>
To: Roman Kagan <rkagan@virtuozzo.com>, devel@edk2.groups.io
Subject: Re: [edk2-devel] static data in dxe_runtime modules
Date: Sat, 3 Aug 2019 04:03:04 +0200	[thread overview]
Message-ID: <8d18d4f6-5f33-44e9-2758-46350b43c5ec@redhat.com> (raw)
In-Reply-To: <20190801191621.GB14235@rkaganb.sw.ru>

On 08/01/19 21:16, Roman Kagan wrote:
> I'm trying to come up with a solution to the problem that OpenSSL
> internally uses static variables ("per-thread" in no-threads config) to
> store pointers, which remain unadjusted upon SetVirtualAddressMap and
> cause the guest OS crash.
> 
> More specifically, trying to set a signed variable leads to the
> following call chain:
> 
> VariableServiceSetVariable
>   ProcessVarWithPk
>     VerifyTimeBasedPayloadAndUpdate
>       Pkcs7GetSigners
> 	ASN1_item_d2i
> 	  asn1_item_embed_d2i
> 	    asn1_template_ex_d2i
> 	      asn1_template_noexp_d2i
> 		asn1_item_embed_d2i
> 		  asn1_template_ex_d2i
> 		    asn1_template_noexp_d2i
> 		      asn1_item_embed_d2i
> 			asn1_template_ex_d2i
> 			  asn1_template_noexp_d2i
> 			    asn1_item_embed_d2i
> 			      pubkey_cb
> 				ERR_set_mark
> 				  ERR_get_state
> 
> The latter performs one-time initialization if needed, and then returns
> a pointer maintained in a static array using CRYPTO_THREAD_get_local().
> If a signed variable is set before SetVirtualAddressMap and (another
> one) after it, the pointer is initialized while in the old mapping and
> dereferenced while in the new one, crashing the OS.
> 
> The real-world reproducer: install Windows Server 2016 in a VM with
> OVMF, shut it down, replace the varstore with a fresh template copy,
> boot Windows, try to update, say, "dbx" from within Windows => BSOD.
> The reason is that the Windows bootloader stores a secure variable
> "CurrentPolicy" if it isn't there, triggering the above callchain while
> still in identity mapping.
> (This problem isn't widely noticed because during the installation the
> bootloader stores CurrentPolicy, but the OS is soon rebooted, before it
> attempts to update dbx; upon that CurrentPolicy remains in the varstore
> and on further boots the bootloader skips setting it.)

This is a serious bug. Thank you for reporting and analyzing it. Can you
file it in the TianoCore Bugzilla too, please?

I think it's of general interest; virtualization is one way to reproduce
it, but it's not exclusive. Loss or wipign of UEFI variables can occur
on physical hardware too.

I wonder how far in OpenSSL history this issue goes back. Is this a
regression from the latest OpenSSL rebase in edk2?

> What would be the best way to fix it?
> 
> One option is to audit OpenSSL and make sure it either doesn't put
> pointers into static storage or properly cleans them up (and call the
> cleanup function in RuntimeCryptLibAddressChangeEvent); then assume the
> rest of EDKII code is safe in this regard.
> 
> Another is to assume that no static data in dxe_runtime modules should
> survive SetVirtualAddressMap, and thus make
> PeCoffLoaderRelocateImageForRuntime reinitialize the modules from
> scratch instead of re-applying the relocations only.
> 
> I must admit I don't yet quite understand the full consequences of
> either option.  Perhaps there are better ones.
> Any suggestion is appreciated.

If the runtime driver remembers pointer *values* from before
SetVirtualAddressMap() -- i.e. it saves pointer values into some
storage, for de-referencing at OS runtime --, those stored values have
to be converted in the virtual address change event notification function.

If your runtime driver says

  Ptr = &mGlobalVariable;
  Ptr->Field = 1;

at runtime, you don't have to do anything. If your driver says

  mPtr = &mGlobalVariable;

at boot time, and then at OS runtime it does

  mPtr->Field = 1;

then "mPtr" has to be converted, with EfiConvertPointer() in
"MdePkg/Library/UefiRuntimeLib/RuntimeLib.c".

PE/COFF massaging is unneeded.

The "thread_local_storage" array from
"CryptoPkg/Library/OpensslLib/openssl/crypto/threads_none.c" has to be
exposed to RuntimeCryptLibAddressChangeEvent() somehow.

Perhaps OpenSSL should allow edk2 to bring its own CRYPTO_THREAD_* APIs.

Thanks
Laszlo

  parent reply	other threads:[~2019-08-03  2:03 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-01 19:16 static data in dxe_runtime modules Roman Kagan
2019-08-02 23:54 ` [edk2-devel] " Andrew Fish
2019-08-03  2:03 ` Laszlo Ersek [this message]
2019-08-05 10:18   ` Roman Kagan
2019-08-07 17:29     ` Laszlo Ersek
2019-08-07 17:41       ` Andrew Fish
2019-08-08 17:39         ` Laszlo Ersek
2019-08-09 16:07           ` Roman Kagan
     [not found]           ` <15B94CD6CF07DEE2.13696@groups.io>
2019-08-12 18:43             ` Roman Kagan
2019-08-13  9:10               ` Laszlo Ersek
2019-08-13 11:23                 ` Roman Kagan
2019-08-14 15:16                   ` Laszlo Ersek
2019-08-14 16:26                     ` Andrew Fish
2019-08-16 15:22                       ` Laszlo Ersek
2019-08-16 17:00                       ` Roman Kagan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8d18d4f6-5f33-44e9-2758-46350b43c5ec@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox