[PATCH RFC 5/5] tools/nolibc: tests: add test for -fstack-protector

From: Thomas Weißschuh
Date: Tue Mar 07 2023 - 17:24:31 EST


Test the previously introduce stack protector functionality in nolibc.

Signed-off-by: Thomas Weißschuh <linux@xxxxxxxxxxxxxx>
---
tools/testing/selftests/nolibc/nolibc-test.c | 74 +++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index fb2d4872fac9..4990b2750279 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -45,6 +45,7 @@ char **environ;
struct test {
const char *name; // test name
int (*func)(int min, int max); // handler
+ char skip_by_default; // don't run by default
};

#ifndef _NOLIBC_STDLIB_H
@@ -667,6 +668,70 @@ int run_stdlib(int min, int max)
return ret;
}

+#if defined(__clang__)
+__attribute__((optnone))
+#elif defined(__GNUC__)
+__attribute__((optimize("O0")))
+#endif
+static int run_smash_stack(int min, int max)
+{
+ char buf[100];
+
+ for (size_t i = 0; i < 200; i++)
+ buf[i] = 15;
+
+ return 1;
+}
+
+int run_stackprotector(int min, int max)
+{
+ int llen = 0;
+
+ llen += printf("0 ");
+
+#if !defined(NOLIBC_STACKPROTECTOR)
+ llen += printf("stack smashing detection not supported");
+ pad_spc(llen, 64, "[SKIPPED]\n");
+ return 0;
+#endif
+
+ pid_t pid = fork();
+
+ switch (pid) {
+ case -1:
+ llen += printf("fork()");
+ pad_spc(llen, 64, "[FAIL]\n");
+ return 1;
+
+ case 0:
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ char *const argv[] = {
+ "/proc/self/exe",
+ "_smash_stack",
+ NULL,
+ };
+ execve("/proc/self/exe", argv, NULL);
+ return 1;
+
+ default: {
+ int status;
+
+ pid = waitpid(pid, &status, 0);
+
+ if (pid == -1 || !WIFSIGNALED(status) || WTERMSIG(status) != SIGABRT) {
+ llen += printf("waitpid()");
+ pad_spc(llen, 64, "[FAIL]\n");
+ return 1;
+ }
+ llen += printf("stack smashing detected");
+ pad_spc(llen, 64, " [OK]\n");
+ return 0;
+ }
+ }
+}
+
/* prepare what needs to be prepared for pid 1 (stdio, /dev, /proc, etc) */
int prepare(void)
{
@@ -719,8 +784,11 @@ int prepare(void)
/* This is the definition of known test names, with their functions */
static const struct test test_names[] = {
/* add new tests here */
- { .name = "syscall", .func = run_syscall },
- { .name = "stdlib", .func = run_stdlib },
+ { .name = "syscall", .func = run_syscall },
+ { .name = "stdlib", .func = run_stdlib },
+ { .name = "stackprotector", .func = run_stackprotector, },
+ { .name = "_smash_stack", .func = run_smash_stack,
+ .skip_by_default = 1 },
{ 0 }
};

@@ -811,6 +879,8 @@ int main(int argc, char **argv, char **envp)
} else {
/* no test mentioned, run everything */
for (idx = 0; test_names[idx].name; idx++) {
+ if (test_names[idx].skip_by_default)
+ continue;
printf("Running test '%s'\n", test_names[idx].name);
err = test_names[idx].func(min, max);
ret += err;

--
2.39.2