From ef258166ba6806df73994d5666c949c12c7719b9 Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Fri, 12 Apr 2024 13:34:46 +0200 Subject: [PATCH] posix: Introduce getentropy() function The function writes random data to the provided buffer. Maximum permitted buffer size is 256 bytes. On success the function returns 0, otherwise it returns -1 and sets errno to appropriate value. Signed-off-by: Patryk Duda --- include/zephyr/posix/unistd.h | 1 + lib/posix/options/CMakeLists.txt | 1 + lib/posix/options/Kconfig | 1 + lib/posix/options/Kconfig.getentropy | 14 +++++++ lib/posix/options/getentropy.c | 45 +++++++++++++++++++++ tests/posix/getentropy/CMakeLists.txt | 10 +++++ tests/posix/getentropy/prj.conf | 4 ++ tests/posix/getentropy/src/main.c | 57 +++++++++++++++++++++++++++ tests/posix/getentropy/testcase.yaml | 20 ++++++++++ 9 files changed, 153 insertions(+) create mode 100644 lib/posix/options/Kconfig.getentropy create mode 100644 lib/posix/options/getentropy.c create mode 100644 tests/posix/getentropy/CMakeLists.txt create mode 100644 tests/posix/getentropy/prj.conf create mode 100644 tests/posix/getentropy/src/main.c create mode 100644 tests/posix/getentropy/testcase.yaml diff --git a/include/zephyr/posix/unistd.h b/include/zephyr/posix/unistd.h index 89fc159f27..c8974fdc86 100644 --- a/include/zephyr/posix/unistd.h +++ b/include/zephyr/posix/unistd.h @@ -263,6 +263,7 @@ extern char *optarg; extern int opterr, optind, optopt; #endif +int getentropy(void *buffer, size_t length); pid_t getpid(void); unsigned sleep(unsigned int seconds); int usleep(useconds_t useconds); diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt index 68794e442e..96995cbeeb 100644 --- a/lib/posix/options/CMakeLists.txt +++ b/lib/posix/options/CMakeLists.txt @@ -36,6 +36,7 @@ zephyr_library() add_subdirectory_ifdef(CONFIG_GETOPT getopt) zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) zephyr_library_sources_ifdef(CONFIG_FNMATCH fnmatch.c) +zephyr_library_sources_ifdef(CONFIG_GETENTROPY getentropy.c) zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) zephyr_library_sources_ifdef(CONFIG_POSIX_ASYNCHRONOUS_IO aio.c) zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK clock.c) diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig index 1f0da85318..2197148bca 100644 --- a/lib/posix/options/Kconfig +++ b/lib/posix/options/Kconfig @@ -35,6 +35,7 @@ rsource "Kconfig.eventfd" rsource "Kconfig.fdtable" rsource "Kconfig.fnmatch" rsource "Kconfig.fs" +rsource "Kconfig.getentropy" rsource "Kconfig.getopt" rsource "Kconfig.key" rsource "Kconfig.mqueue" diff --git a/lib/posix/options/Kconfig.getentropy b/lib/posix/options/Kconfig.getentropy new file mode 100644 index 0000000000..7445413501 --- /dev/null +++ b/lib/posix/options/Kconfig.getentropy @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +DT_CHOSEN_ZEPHYR_ENTROPY := zephyr,entropy + +config GETENTROPY + bool "Support for getentropy" + depends on !NATIVE_APPLICATION + select NATIVE_LIBC_INCOMPATIBLE + depends on ENTROPY_HAS_DRIVER + depends on $(dt_chosen_enabled,$(DT_CHOSEN_ZEPHYR_ENTROPY)) + help + Enable support for getentropy() function. diff --git a/lib/posix/options/getentropy.c b/lib/posix/options/getentropy.c new file mode 100644 index 0000000000..dcc271617c --- /dev/null +++ b/lib/posix/options/getentropy.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#define ENTROPY_NODE DT_CHOSEN(zephyr_entropy) + +int getentropy(void *buffer, size_t length) +{ + const struct device * const entropy = DEVICE_DT_GET(ENTROPY_NODE); + + if (!buffer) { + errno = EFAULT; + return -1; + } + + if (length > 256) { + errno = EIO; + return -1; + } + + if (!device_is_ready(entropy)) { + errno = EIO; + return -1; + } + + /* + * getentropy() uses size_t to represent buffer size, but Zephyr uses + * uint16_t. The length check above allows us to safely cast without + * overflow. + */ + if (entropy_get_entropy(entropy, buffer, (uint16_t)length)) { + errno = EIO; + return -1; + } + + return 0; +} diff --git a/tests/posix/getentropy/CMakeLists.txt b/tests/posix/getentropy/CMakeLists.txt new file mode 100644 index 0000000000..27970bfe2a --- /dev/null +++ b/tests/posix/getentropy/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(getentropy) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/posix/getentropy/prj.conf b/tests/posix/getentropy/prj.conf new file mode 100644 index 0000000000..58160099e3 --- /dev/null +++ b/tests/posix/getentropy/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ENTROPY_GENERATOR=y +CONFIG_GETENTROPY=y +CONFIG_POSIX_API=y +CONFIG_ZTEST=y diff --git a/tests/posix/getentropy/src/main.c b/tests/posix/getentropy/src/main.c new file mode 100644 index 0000000000..a276c4b966 --- /dev/null +++ b/tests/posix/getentropy/src/main.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +ZTEST(getentropy_test_suite, test_getentropy_too_large) +{ + uint8_t buf[256 + 1] = { 0 }; + int ret; + + ret = getentropy(buf, sizeof(buf)); + zassert_equal(ret, -1); + zassert_equal(errno, EIO); +} + +ZTEST(getentropy_test_suite, test_getentropy_null_buffer) +{ + int ret; + + ret = getentropy(NULL, 0); + zassert_equal(ret, -1); + zassert_equal(errno, EFAULT); +} + +ZTEST(getentropy_test_suite, test_getentropy_max_size) +{ + uint8_t buf[256] = { 0 }; + int ret; + + ret = getentropy(buf, sizeof(buf)); + zassert_equal(ret, 0); +} + +ZTEST(getentropy_test_suite, test_getentropy) +{ + uint8_t zero[16] = { 0 }; + uint8_t buf1[16]; + uint8_t buf2[16]; + int ret; + + ret = getentropy(buf1, sizeof(buf1)); + zassert_equal(ret, 0); + + ret = getentropy(buf2, sizeof(buf2)); + zassert_equal(ret, 0); + + zassert_true(memcmp(buf1, zero, sizeof(zero)) != 0); + zassert_true(memcmp(buf2, zero, sizeof(zero)) != 0); + zassert_true(memcmp(buf1, buf2, sizeof(buf1)) != 0); +} + +ZTEST_SUITE(getentropy_test_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/getentropy/testcase.yaml b/tests/posix/getentropy/testcase.yaml new file mode 100644 index 0000000000..b8b4fc41d8 --- /dev/null +++ b/tests/posix/getentropy/testcase.yaml @@ -0,0 +1,20 @@ +common: + filter: dt_chosen_enabled("zephyr,entropy") and CONFIG_ENTROPY_HAS_DRIVER and + not CONFIG_NATIVE_LIBC + integration_platforms: + - native_sim + tags: + - posix + - getentropy +tests: + portability.posix.getentropy: {} + portability.posix.getentropy.newlib: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED + extra_configs: + - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=4096 + portability.posix.getentropy.picolibc: + tags: picolibc + filter: CONFIG_PICOLIBC_SUPPORTED + extra_configs: + - CONFIG_PICOLIBC=y