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

mbedtls fails to initialize if run under qemu which does not support getrandom #1212

Closed
randombit opened this Issue Dec 15, 2017 · 5 comments

Comments

Projects
None yet
4 participants
@randombit
Copy link

randombit commented Dec 15, 2017

  • Type: Bug
  • OS: Linux (Ubuntu 16.04)
  • Mbed TLS version 2.6.0

Expected behavior

That it is possible to run an application using mbedtls under qemu.

Actual behavior

qemu: Unsupported syscall: 384
curl: (51) Failed - mbedTLS: ctr_drbg_init returned (-0x0034) CTR_DRBG - The entropy source failed

The problem is that the version of qemu in Ubuntu 16.04 does not support getrandom syscall. But mbedtls expects that as long as the uname is at least 3.17 then getrandom must work, and just fails when qemu returns an error. Instead, it should fall back to trying /dev/random, which works fine under qemu.

Doing this would actually seem to simplify the code by allowing to completely remove the version check (calling uname, parsing the output, etc) - try calling the syscall, if it returns ENOSYS then mark getrandom as unavailable and continue with /dev/urandom.

Steps to reproduce

Compile mbedtls using ARM cross compiler. Then cross-compile curl, linking against mbedtls. Run it under qemu 2.5.0, trying to access an https url.

@RonEld

This comment has been minimized.

Copy link
Contributor

RonEld commented Dec 17, 2017

@randombit Thank you for reporting this issue!
Please elaborate what platform you are trying to emulate. according to the syscall value I believe it is aarch64.
It is strange that you are receiving this, because we are using getrandom() only if SYS_getrandom is defined, and only on kernel higher than 3.17, as it was introduced there, as you mentioned.

@ciarmcom

This comment has been minimized.

Copy link
Member

ciarmcom commented Dec 17, 2017

ARM Internal Ref: IOTSSL-1948

@randombit

This comment has been minimized.

Copy link

randombit commented Dec 18, 2017

@RonEld This is armv7 (based on my kernel headers, aarch64 uses 278 for getrandom).

The problem is the code is being built on a machine with recent kernel headers (so SYS_getrandom is defined) and the x86-64 host is running a 4.x kernel (which does in fact support getrandom). But older versions of qemu don't know about the syscall, so it fails at runtime.

@hanno-arm

This comment has been minimized.

Copy link
Contributor

hanno-arm commented Oct 18, 2018

Thanks @randombit bit raising this, and apologies this issue was silent for so long.

For reference, I reproduced the issue on my Ubuntu 16.04 machine in the following way:

  1. Make sure to have gcc-5-arm-linux-gnueabihf (for cross-compilation) and qemu-user (for syscall emulation) installed.
  2. From the Mbed TLS base directory, compile via make CC=arm-linux-gnueabihf-gcc-5 AR=arm-linux-gnueabihf-gcc-ar-5
  3. Confirm that ssl_server2 in fact an ARM binary
$ file ./programs/ssl/ssl_server2
./programs/ssl/ssl_server2: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=c548cd405e0394a0e936164b682d7dfa388b8442, not stripped
  1. Run ssl_server2 (automagically using qemu under the hood): ./programs/ssl/ssl_server2.

Observe failure propagated from qemu: Unsupported syscall: 384.

I tested the fix proposed by @randombit and it works fine. I will open a PR for it where we can continue the discussion.

hanno-arm added a commit to hanno-arm/mbedtls that referenced this issue Oct 18, 2018

Entropy: Fall through to /dev/random if getrandom() syscall unknown
This commit fixes issue ARMmbed#1212 related to platform-specific entropy
polling in an syscall-emulated environment.

Previously, the implementation of the entropy gathering function
`mbedtls_platform_entropy_poll()` for linux machines used the
following logic to determine how to obtain entropy from the kernel:

1. If the getrandom() system call identifier SYS_getrandom is present and
   the kernel version is 3.17 or higher, use syscall( SYS_getrandom, ... )
2. Otherwise, fall back to reading from /dev/random.

There are two issues with this:

1. Portability:
   When cross-compiling the code for a different
   architecture and running it through system call
   emulation in qemu, qemu reports the host kernel
   version through uname but, as of v.2.5.0,
   doesn't support emulating the getrandom() syscall.
   This leads to `mbedtls_platform_entropy_poll()`
   failing even though reading from /dev/random would
   have worked.

2. Style:
   Extracting the linux kernel version from
   the output of `uname` is slightly tedious.

This commit fixes both by implementing the suggestion in ARMmbed#1212:
- It removes the kernel-version detection through uname().
- Instead, it checks whether `syscall( SYS_getrandom, ... )`
  fails with errno set to ENOSYS indicating an unknown system call.
  If so, it falls through to trying to read from /dev/random.

Fixes ARMmbed#1212.
@hanno-arm

This comment has been minimized.

Copy link
Contributor

hanno-arm commented Oct 18, 2018

@randombit I opened #2117 to address this. Thanks again for your report and the suggested fix. Could you please let me know how you would like to be credited in the ChangeLog. For now, I credited you under your GitHub name.

hanno-arm added a commit to hanno-arm/mbedtls that referenced this issue Oct 30, 2018

Entropy: Fall through to /dev/random if getrandom() syscall unknown
This commit fixes issue ARMmbed#1212 related to platform-specific entropy
polling in an syscall-emulated environment.

Previously, the implementation of the entropy gathering function
`mbedtls_platform_entropy_poll()` for linux machines used the
following logic to determine how to obtain entropy from the kernel:

1. If the getrandom() system call identifier SYS_getrandom is present and
   the kernel version is 3.17 or higher, use syscall( SYS_getrandom, ... )
2. Otherwise, fall back to reading from /dev/random.

There are two issues with this:

1. Portability:
   When cross-compiling the code for a different
   architecture and running it through system call
   emulation in qemu, qemu reports the host kernel
   version through uname but, as of v.2.5.0,
   doesn't support emulating the getrandom() syscall.
   This leads to `mbedtls_platform_entropy_poll()`
   failing even though reading from /dev/random would
   have worked.

2. Style:
   Extracting the linux kernel version from
   the output of `uname` is slightly tedious.

This commit fixes both by implementing the suggestion in ARMmbed#1212:
- It removes the kernel-version detection through uname().
- Instead, it checks whether `syscall( SYS_getrandom, ... )`
  fails with errno set to ENOSYS indicating an unknown system call.
  If so, it falls through to trying to read from /dev/random.

Fixes ARMmbed#1212.

hanno-arm added a commit to hanno-arm/mbedtls that referenced this issue Oct 30, 2018

Entropy: Fall through to /dev/random if getrandom() syscall unknown
This commit fixes issue ARMmbed#1212 related to platform-specific entropy
polling in an syscall-emulated environment.

Previously, the implementation of the entropy gathering function
`mbedtls_platform_entropy_poll()` for linux machines used the
following logic to determine how to obtain entropy from the kernel:

1. If the getrandom() system call identifier SYS_getrandom is present and
   the kernel version is 3.17 or higher, use syscall( SYS_getrandom, ... )
2. Otherwise, fall back to reading from /dev/random.

There are two issues with this:

1. Portability:
   When cross-compiling the code for a different
   architecture and running it through system call
   emulation in qemu, qemu reports the host kernel
   version through uname but, as of v.2.5.0,
   doesn't support emulating the getrandom() syscall.
   This leads to `mbedtls_platform_entropy_poll()`
   failing even though reading from /dev/random would
   have worked.

2. Style:
   Extracting the linux kernel version from
   the output of `uname` is slightly tedious.

This commit fixes both by implementing the suggestion in ARMmbed#1212:
- It removes the kernel-version detection through uname().
- Instead, it checks whether `syscall( SYS_getrandom, ... )`
  fails with errno set to ENOSYS indicating an unknown system call.
  If so, it falls through to trying to read from /dev/random.

Fixes ARMmbed#1212.

@Patater Patater closed this in #2117 Dec 7, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment