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

Fix .bss initialization #551

Merged
merged 2 commits into from
Apr 18, 2023
Merged

Conversation

Kensan
Copy link
Contributor

@Kensan Kensan commented Apr 16, 2023

With the changes to the linker scripts in #546, the ELF segment containing the bss section is no longer of type PT_LOAD. This means it is not being processed by the Muen script and thus no longer initialized to zero. Explicitly set it to PT_LOAD in the linker script again to restore the original behavior. This was discovered when running Muen test unikernels on hardware, where memory is actually uninitialized and not zeroized as is done on most hypervisors.

Note that the same behavior goes for the common tender ELF loader, see

solo5/tenders/common/elf.c

Lines 249 to 250 in 7d5b70f

if (phdr[ph_i].p_filesz == 0 || phdr[ph_i].p_type != PT_LOAD)
continue;
, thus I believe the same issue is present and the same fix is necessary for the other bindings.

@hannesm
Copy link
Contributor

hannesm commented Apr 17, 2023

Thanks for your report and pull request. I agree this is should be done (and adapted to hvt/spt at least). @palainp any remarks on this?

@palainp
Copy link
Contributor

palainp commented Apr 17, 2023

I'm sorry for that issue and I also agree that it should be fixed.

With Ocaml 5+ a PT_TLS section is now mandatory in the linker script with lld and I suppose that setting only .bss to PT_LOAD will report the same issue on the .tbss section, but setting .tbss as PT_LOAD too will remove the PT_TLS section that lld needs. @Kensan I don't use muen, could it be possible to try an unikernel that have a __thread int variable or run tests/tls.c with a clang/lld suite?

With Xen the zeroization of .tbss and .bss is done by giving _edata (end address of loaded code+data) and _ebss (end address of zeroed area):

.long _edata
.

Re-reading the elf loader, it seems to add the memsize of every PT_LOAD section (and wipe bss section

if (add_overflow(p_vaddr, p_filesz, temp))
and below) but it doesn't seem to be any trouble here (memory is probably already zeroed).
I added phdr[ph_i].p_filesz == 0 || because if there is no __thread variable the .tdata section is empty (now it's at least 1 page do it's not needed anymore) and the following lines cause a failure.

@Kensan
Copy link
Contributor Author

Kensan commented Apr 17, 2023

With Ocaml 5+ a PT_TLS section is now mandatory in the linker script with lld and I suppose that setting only .bss to PT_LOAD will report the same issue on the .tbss section, but setting .tbss as PT_LOAD too will remove the PT_TLS section that lld needs. @Kensan I don't use muen, could it be possible to try an unikernel that have a __thread int variable or run tests/tls.c with a clang/lld suite?

I tried running test_tls but it failed with a pagefault in set_data, when trying to write to the _data thread variable. I think the environment (on Muen) is not setup correctly for this use case. What is the expected behavior for the .tdata and .tbss sections, i.e. how should they be set up prior to execution of the unikernel?

@palainp
Copy link
Contributor

palainp commented Apr 17, 2023

.tdata is .data but for __thread variables (_data_not_bss in tests/test_tls.c), and the same for .tbss and .bss (_data in the test .c file).
To me .tdata should be loaded as it's a PT_LOAD section, but .tbss probably suffers from the same issue as .bss before this PR (not loaded as it's PT_NULL). You probably can validate the correct loading of .tdata by copying lines 97-98 just before set_data(1);

Could it be possible to load PT_LOAD and PT_TLS in muen?

@Kensan
Copy link
Contributor Author

Kensan commented Apr 17, 2023

I see, thanks for the information.

Could it be possible to load PT_LOAD and PT_TLS in muen?

Yes. I will look into it. The TLS test can probably be made to run without changes to Solo5.

@Kensan
Copy link
Contributor Author

Kensan commented Apr 17, 2023

Since there seems to be agreement, that the fix for the .bss loading is also necessary for the other bindings, I will update this PR with the necessary changes.

Make .bss part of a PT_LOAD segment again so it is properly initialized
to zero.
@dinosaure
Copy link
Collaborator

Thanks!

@dinosaure dinosaure merged commit b9b2888 into Solo5:master Apr 18, 2023
@dinosaure
Copy link
Collaborator

So it's normal that bss does not have PT_LOAD for virto/xen? (/cc @palainp, @Kensan). Otherwise, I can do a quick patch to extend this PR with PT_LOAD on these targets.

@Kensan
Copy link
Contributor Author

Kensan commented Apr 18, 2023

So it's normal that bss does not have PT_LOAD for virto/xen? (/cc @palainp, @Kensan). Otherwise, I can do a quick patch to extend this PR with PT_LOAD on these targets.

I did not change those linker scripts (and also stub) because from the discussion I got the impression that it is not necessary, due to the way they are loaded (Multiboot). From a consistency perspective it would probably be nicer, if the ELF files look the same. Plus, in my opinion it seems appropriate that the .bss segment would have type LOAD, but my knowledge of ELF is not all that deep.

@Kensan Kensan deleted the fix-bss-initialization branch April 18, 2023 19:03
@Kensan
Copy link
Contributor Author

Kensan commented Apr 18, 2023

Could it be possible to load PT_LOAD and PT_TLS in muen?

Yes. I will look into it. The TLS test can probably be made to run without changes to Solo5.

I could get the TLS test to pass with only minor changes on the Muen side. Thanks @palainp for the discussion.

@palainp
Copy link
Contributor

palainp commented Apr 19, 2023

I'm also in favor of having coherent scripts when it isn't mandatory to put differences. So apply a similar change for the remaining scripts should be better to my opinion.

Thank you @Kensan for your time. Do you think we also need to update the elf reader in hvt and spt tenders in the same way you changes muen (whatever you've done)? I'm still a bit puzzled now loading bss but not tbss :)

@Kensan
Copy link
Contributor Author

Kensan commented Apr 19, 2023

Thank you @Kensan for your time. Do you think we also need to update the elf reader in hvt and spt tenders in the same way you changes muen (whatever you've done)? I'm still a bit puzzled now loading bss but not tbss :)

My understanding is, that tbss (along with tdata and the tcb) is allocated on the heap for each thread, thus there is no need to have the section processed by the ELF loader. For Muen I had to do minor adjustments to correctly process sections that have a filesize of 0 but a virtual size > 0.

Regarding the ELF loader of HVT/SPT tenders: what was the reason that the zero size check was added? Is it still required?

if (phdr[ph_i].p_filesz == 0 || phdr[ph_i].p_type != PT_LOAD)

@palainp
Copy link
Contributor

palainp commented Apr 20, 2023

Yes you're right, blanking .tbss should be done done on thread creation. I was wondering this because (at common/elf.c:252 and after) the elf loader is doing some things with addresses, and with a non empty .tbss section didn't follow this code path we might have bitroted values.

Concerning filesz check, this was needed (but not anymore, I added an alignment into the linker scripts to force .tdata to be non empty

. = ALIGN(CONSTANT(MAXPAGESIZE));
<- this also might be something we don't want?) because .tdata could be empty and still PT_LOADed, failling one assertion later, but I can't remember where :(

dinosaure added a commit to dinosaure/opam-repository that referenced this pull request Apr 25, 2023
* Be able to build `spt`, `virtio`, `muen` and `xen` targets on OpenBSD
  (@adamsteen, Solo5/solo5#544). This change does not allow us to "run" these
  targets on OpenBSD
* Fix linker scripts with TLS (Thread Local Storage) sections
  (@palainp, @hannesm, @dinosaure, Solo5/solo5#542)
* Export TLS symbols (@palainp, @hannesm, @dinosaure, Solo5/solo5#546)
  **breaking change** due to Solo5/solo5#542 & Solo5/solo5#546, tenders must be
  **upgraded**. Indeed, solo5.0.7.* tenders will not be able to load correctly
  unikernels compiled with solo5.0.8.0. The internal ABI version for
  `solo5-hvt`/`solo5-spt` was upgraded accordingly.

  This version implements Thread Local Storage. The user can initialise a TLS
  block with `solo5_tls_init` on a pointer to `solo5_tls_size()` free bytes.
  Then, the user is able to set the `tp` (Thread Pointer) pointer via
  `solo5_set_tls_base(solo5_tls_tp_offset(tls_block))`. More details are
  available into `solo5.h`.

  Note: this change does not allow a Solo5 unikernel to use multiple cores! It
  only provides an API required by OCaml 5 / pthread to launch, at most, one
  thread.
* Fix tests reported by NixOS (@greydot, @ehmry, Solo5/solo5#547)
* Split out the `time.c` implementation between Muen and HVT
  (@dinosaure, @Kensan, Solo5/solo5#552)
* User hypercall instead of TSC-based clock when the user asks for the
  wall-clock (@dinosaure, @reynir, Solo5/solo5#549, Solo5/solo5#550)

  Note: only hvt & virtio are updated to avoid a clock drift on the wall-clock.
  Indeed, when the unikernel is suspended, the wall-clock is not updated. Muen
  & Xen still use a TSC-based wall-clock. The spt target was already in sync
  with the host's wall-clock.
* Improve the muen clock (@Kensan, Solo5/solo5#553)
* Fix the `.bss` section according to Solo5/solo5#542 & Solo5/solo5#546. The
  `.bss` section is tagged with `PT_LOAD`. Tenders are available to load this
  section properly. (@Kensan, @dinosaure, Solo5/solo5#551, Solo5/solo5#554)
* Fix the cross-compilation of Solo5 for `aarch64`
  (@dinosaure, @palainp, @hannes, Solo5/solo5#555)
dinosaure added a commit to dinosaure/opam-repository that referenced this pull request Apr 25, 2023
  (@adamsteen, Solo5/solo5#544). This change does not allow us to "run" these
  targets on OpenBSD
* Fix linker scripts with TLS (Thread Local Storage) sections
  (@palainp, @hannesm, @dinosaure, Solo5/solo5#542)
* Export TLS symbols (@palainp, @hannesm, @dinosaure, Solo5/solo5#546)
  **breaking change** due to Solo5/solo5#542 & Solo5/solo5#546, tenders must be
  **upgraded**. Indeed, solo5.0.7.* tenders will not be able to load correctly
  unikernels compiled with solo5.0.8.0. The internal ABI version for
  `solo5-hvt`/`solo5-spt` was upgraded accordingly.

  This version implements Thread Local Storage. The user can initialise a TLS
  block with `solo5_tls_init` on a pointer to `solo5_tls_size()` free bytes.
  Then, the user is able to set the `tp` (Thread Pointer) pointer via
  `solo5_set_tls_base(solo5_tls_tp_offset(tls_block))`. More details are
  available into `solo5.h`.

  Note: this change does not allow a Solo5 unikernel to use multiple cores! It
  only provides an API required by OCaml 5 / pthread to launch, at most, one
  thread.
* Fix tests reported by NixOS (@greydot, @ehmry, Solo5/solo5#547)
* Split out the `time.c` implementation between Muen and HVT
  (@dinosaure, @Kensan, Solo5/solo5#552)
* User hypercall instead of TSC-based clock when the user asks for the
  wall-clock (@dinosaure, @reynir, Solo5/solo5#549, Solo5/solo5#550)

  Note: only hvt & virtio are updated to avoid a clock drift on the wall-clock.
  Indeed, when the unikernel is suspended, the wall-clock is not updated. Muen
  & Xen still use a TSC-based wall-clock. The spt target was already in sync
  with the host's wall-clock.
* Improve the muen clock (@Kensan, Solo5/solo5#553)
* Fix the `.bss` section according to Solo5/solo5#542 & Solo5/solo5#546. The
  `.bss` section is tagged with `PT_LOAD`. Tenders are available to load this
  section properly. (@Kensan, @dinosaure, Solo5/solo5#551, Solo5/solo5#554)
* Fix the cross-compilation of Solo5 for `aarch64`
  (@dinosaure, @palainp, @hannes, Solo5/solo5#555)
dinosaure added a commit to dinosaure/opam-repository that referenced this pull request Apr 28, 2023
* Be able to build `spt`, `virtio`, `muen` and `xen` targets on OpenBSD
  (@adamsteen, Solo5/solo5#544). This change does not allow us to "run" these
  targets on OpenBSD
* Fix linker scripts with TLS (Thread Local Storage) sections
  (@palainp, @hannesm, @dinosaure, Solo5/solo5#542)
* Export TLS symbols (@palainp, @hannesm, @dinosaure, Solo5/solo5#546)
  **breaking change** due to Solo5/solo5#542 & Solo5/solo5#546, tenders must be
  **upgraded**. Indeed, solo5.0.7.* tenders will not be able to load correctly
  unikernels compiled with solo5.0.8.0. The internal ABI version for
  `solo5-hvt`/`solo5-spt` was upgraded accordingly.

  This version implements Thread Local Storage. The user can initialise a TLS
  block with `solo5_tls_init` on a pointer to `solo5_tls_size()` free bytes.
  Then, the user is able to set the `tp` (Thread Pointer) pointer via
  `solo5_set_tls_base(solo5_tls_tp_offset(tls_block))`. More details are
  available into `solo5.h`.

  Note: this change does not allow a Solo5 unikernel to use multiple cores! It
  only provides an API required by OCaml 5 / pthread to launch, at most, one
  thread.
* Fix tests reported by NixOS (@greydot, @ehmry, Solo5/solo5#547)
* Split out the `time.c` implementation between Muen and HVT
  (@dinosaure, @Kensan, Solo5/solo5#552)
* User hypercall instead of TSC-based clock when the user asks for the
  wall-clock (@dinosaure, @reynir, Solo5/solo5#549, Solo5/solo5#550)

  Note: only hvt & virtio are updated to avoid a clock drift on the wall-clock.
  Indeed, when the unikernel is suspended, the wall-clock is not updated. Muen
  & Xen still use a TSC-based wall-clock. The spt target was already in sync
  with the host's wall-clock.
* Improve the muen clock (@Kensan, Solo5/solo5#553)
* Fix the `.bss` section according to Solo5/solo5#542 & Solo5/solo5#546. The
  `.bss` section is tagged with `PT_LOAD`. Tenders are available to load this
  section properly. (@Kensan, @dinosaure, Solo5/solo5#551, Solo5/solo5#554)
* Fix the cross-compilation of Solo5 for `aarch64`
  (@dinosaure, @palainp, @hannesm, Solo5/solo5#555)
* Increase the Muen ABI (2 to 3) due to TLS changes (@Kensan, ocaml#557)
* Support lifecycle management for Muen (@Kensan, ocaml#557)
  The user is able to configure automatic restarting of unikernels that invokes
  `solo5_ext()`
* Fix the `test_fpu` test & ensure the alignment of variables (@Kensan, ocaml#557)
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.

4 participants