Patch series "Selftests: Fix compilation warnings due to missing _GNU_SOURCE definition", v2. Since kselftest_harness.h introduces asprintf()[1], many selftests have compilation warnings or errors due to missing _GNU_SOURCE definitions. The issue stems from a lack of a LINE_MAX definition in Android (see commit38c957f070
), which is the reason why asprintf() was introduced. We tried adding _GNU_SOURCE definitions to more selftests to fix, but asprintf() may continue to cause problems, and since it is quite late in the 6.9 cycle, we would like to revert8092162335
first to provide testing for forks[2]. [1] https://lore.kernel.org/all/20240411231954.62156-1-edliaw@google.com [2] https://lore.kernel.org/linux-kselftest/ZjuA3aY_iHkjP7bQ@google.com This patch (of 2): This reverts commit8092162335
. asprintf() is declared in stdio.h when defining _GNU_SOURCE, but stdio.h is so common that many files don't define _GNU_SOURCE before including stdio.h, and defining _GNU_SOURCE after including stdio.h will no longer take effect, which causes warnings or even errors during compilation in many selftests. Revert 'commit8092162335
("selftests/harness: remove use of LINE_MAX")' as that came in quite late in the 6.9 cycle. Link: https://lkml.kernel.org/r/20240509053113.43462-1-tao1.su@linux.intel.com Link: https://lore.kernel.org/linux-kselftest/ZjuA3aY_iHkjP7bQ@google.com/ Link: https://lkml.kernel.org/r/20240509053113.43462-2-tao1.su@linux.intel.com Fixes:8092162335
("selftests/harness: remove use of LINE_MAX") Signed-off-by: Tao Su <tao1.su@linux.intel.com> Reviewed-by: Simon Horman <horms@kernel.org> Cc: Alexandre Belloni <alexandre.belloni@bootlin.com> Cc: Bongsu Jeon <bongsu.jeon@samsung.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: David S. Miller <davem@davemloft.net> Cc: Edward Liaw <edliaw@google.com> Cc: Eric Dumazet <edumazet@google.com> Cc: Ivan Orlov <ivan.orlov0322@gmail.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Jarkko Sakkinen <jarkko@kernel.org> Cc: Jaroslav Kysela <perex@perex.cz> Cc: Mark Brown <broonie@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Sean Christopherson <seanjc@google.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Takashi Iwai <tiwai@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
303 lines
6.3 KiB
C
303 lines
6.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#ifdef __aarch64__
|
|
#include <asm/hwcap.h>
|
|
#endif
|
|
|
|
#include <linux/mman.h>
|
|
#include <linux/prctl.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/auxv.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
#include "../kselftest_harness.h"
|
|
|
|
#ifndef __aarch64__
|
|
# define PROT_BTI 0
|
|
#endif
|
|
|
|
TEST(prctl_flags)
|
|
{
|
|
EXPECT_LT(prctl(PR_SET_MDWE, PR_MDWE_NO_INHERIT, 0L, 0L, 7L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
|
|
EXPECT_LT(prctl(PR_SET_MDWE, 7L, 0L, 0L, 0L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
EXPECT_LT(prctl(PR_SET_MDWE, 0L, 7L, 0L, 0L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 7L, 0L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 0L, 7L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
|
|
EXPECT_LT(prctl(PR_GET_MDWE, 7L, 0L, 0L, 0L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
EXPECT_LT(prctl(PR_GET_MDWE, 0L, 7L, 0L, 0L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 7L, 0L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 0L, 7L), 0);
|
|
EXPECT_EQ(errno, EINVAL);
|
|
}
|
|
|
|
FIXTURE(consecutive_prctl_flags) {};
|
|
FIXTURE_SETUP(consecutive_prctl_flags) {}
|
|
FIXTURE_TEARDOWN(consecutive_prctl_flags) {}
|
|
|
|
FIXTURE_VARIANT(consecutive_prctl_flags)
|
|
{
|
|
unsigned long first_flags;
|
|
unsigned long second_flags;
|
|
bool should_work;
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_no_flags)
|
|
{
|
|
.first_flags = 0,
|
|
.second_flags = 0,
|
|
.should_work = true,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_exec_gain)
|
|
{
|
|
.first_flags = PR_MDWE_REFUSE_EXEC_GAIN,
|
|
.second_flags = PR_MDWE_REFUSE_EXEC_GAIN,
|
|
.should_work = true,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_both_flags)
|
|
{
|
|
.first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
|
|
.second_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
|
|
.should_work = true,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_mdwe)
|
|
{
|
|
.first_flags = PR_MDWE_REFUSE_EXEC_GAIN,
|
|
.second_flags = 0,
|
|
.should_work = false,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_mdwe_no_inherit)
|
|
{
|
|
.first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
|
|
.second_flags = 0,
|
|
.should_work = false,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_no_inherit)
|
|
{
|
|
.first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
|
|
.second_flags = PR_MDWE_REFUSE_EXEC_GAIN,
|
|
.should_work = false,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_enable_no_inherit)
|
|
{
|
|
.first_flags = PR_MDWE_REFUSE_EXEC_GAIN,
|
|
.second_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
|
|
.should_work = false,
|
|
};
|
|
|
|
TEST_F(consecutive_prctl_flags, two_prctls)
|
|
{
|
|
int ret;
|
|
|
|
EXPECT_EQ(prctl(PR_SET_MDWE, variant->first_flags, 0L, 0L, 0L), 0);
|
|
|
|
ret = prctl(PR_SET_MDWE, variant->second_flags, 0L, 0L, 0L);
|
|
if (variant->should_work) {
|
|
EXPECT_EQ(ret, 0);
|
|
|
|
ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L);
|
|
ASSERT_EQ(ret, variant->second_flags);
|
|
} else {
|
|
EXPECT_NE(ret, 0);
|
|
ASSERT_EQ(errno, EPERM);
|
|
}
|
|
}
|
|
|
|
FIXTURE(mdwe)
|
|
{
|
|
void *p;
|
|
int flags;
|
|
size_t size;
|
|
pid_t pid;
|
|
};
|
|
|
|
FIXTURE_VARIANT(mdwe)
|
|
{
|
|
bool enabled;
|
|
bool forked;
|
|
bool inherit;
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(mdwe, stock)
|
|
{
|
|
.enabled = false,
|
|
.forked = false,
|
|
.inherit = false,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(mdwe, enabled)
|
|
{
|
|
.enabled = true,
|
|
.forked = false,
|
|
.inherit = true,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(mdwe, inherited)
|
|
{
|
|
.enabled = true,
|
|
.forked = true,
|
|
.inherit = true,
|
|
};
|
|
|
|
FIXTURE_VARIANT_ADD(mdwe, not_inherited)
|
|
{
|
|
.enabled = true,
|
|
.forked = true,
|
|
.inherit = false,
|
|
};
|
|
|
|
static bool executable_map_should_fail(const FIXTURE_VARIANT(mdwe) *variant)
|
|
{
|
|
return variant->enabled && (!variant->forked || variant->inherit);
|
|
}
|
|
|
|
FIXTURE_SETUP(mdwe)
|
|
{
|
|
unsigned long mdwe_flags;
|
|
int ret, status;
|
|
|
|
self->p = NULL;
|
|
self->flags = MAP_SHARED | MAP_ANONYMOUS;
|
|
self->size = getpagesize();
|
|
|
|
if (!variant->enabled)
|
|
return;
|
|
|
|
mdwe_flags = PR_MDWE_REFUSE_EXEC_GAIN;
|
|
if (!variant->inherit)
|
|
mdwe_flags |= PR_MDWE_NO_INHERIT;
|
|
|
|
ret = prctl(PR_SET_MDWE, mdwe_flags, 0L, 0L, 0L);
|
|
ASSERT_EQ(ret, 0) {
|
|
TH_LOG("PR_SET_MDWE failed or unsupported");
|
|
}
|
|
|
|
ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L);
|
|
ASSERT_EQ(ret, mdwe_flags);
|
|
|
|
if (variant->forked) {
|
|
self->pid = fork();
|
|
ASSERT_GE(self->pid, 0) {
|
|
TH_LOG("fork failed\n");
|
|
}
|
|
|
|
if (self->pid > 0) {
|
|
ret = waitpid(self->pid, &status, 0);
|
|
ASSERT_TRUE(WIFEXITED(status));
|
|
exit(WEXITSTATUS(status));
|
|
}
|
|
}
|
|
}
|
|
|
|
FIXTURE_TEARDOWN(mdwe)
|
|
{
|
|
if (self->p && self->p != MAP_FAILED)
|
|
munmap(self->p, self->size);
|
|
}
|
|
|
|
TEST_F(mdwe, mmap_READ_EXEC)
|
|
{
|
|
self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0);
|
|
EXPECT_NE(self->p, MAP_FAILED);
|
|
}
|
|
|
|
TEST_F(mdwe, mmap_WRITE_EXEC)
|
|
{
|
|
self->p = mmap(NULL, self->size, PROT_WRITE | PROT_EXEC, self->flags, 0, 0);
|
|
if (executable_map_should_fail(variant)) {
|
|
EXPECT_EQ(self->p, MAP_FAILED);
|
|
} else {
|
|
EXPECT_NE(self->p, MAP_FAILED);
|
|
}
|
|
}
|
|
|
|
TEST_F(mdwe, mprotect_stay_EXEC)
|
|
{
|
|
int ret;
|
|
|
|
self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0);
|
|
ASSERT_NE(self->p, MAP_FAILED);
|
|
|
|
ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC);
|
|
EXPECT_EQ(ret, 0);
|
|
}
|
|
|
|
TEST_F(mdwe, mprotect_add_EXEC)
|
|
{
|
|
int ret;
|
|
|
|
self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0);
|
|
ASSERT_NE(self->p, MAP_FAILED);
|
|
|
|
ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC);
|
|
if (executable_map_should_fail(variant)) {
|
|
EXPECT_LT(ret, 0);
|
|
} else {
|
|
EXPECT_EQ(ret, 0);
|
|
}
|
|
}
|
|
|
|
TEST_F(mdwe, mprotect_WRITE_EXEC)
|
|
{
|
|
int ret;
|
|
|
|
self->p = mmap(NULL, self->size, PROT_WRITE, self->flags, 0, 0);
|
|
ASSERT_NE(self->p, MAP_FAILED);
|
|
|
|
ret = mprotect(self->p, self->size, PROT_WRITE | PROT_EXEC);
|
|
if (executable_map_should_fail(variant)) {
|
|
EXPECT_LT(ret, 0);
|
|
} else {
|
|
EXPECT_EQ(ret, 0);
|
|
}
|
|
}
|
|
|
|
TEST_F(mdwe, mmap_FIXED)
|
|
{
|
|
void *p;
|
|
|
|
self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0);
|
|
ASSERT_NE(self->p, MAP_FAILED);
|
|
|
|
/* MAP_FIXED unmaps the existing page before mapping which is allowed */
|
|
p = mmap(self->p, self->size, PROT_READ | PROT_EXEC,
|
|
self->flags | MAP_FIXED, 0, 0);
|
|
EXPECT_EQ(p, self->p);
|
|
}
|
|
|
|
TEST_F(mdwe, arm64_BTI)
|
|
{
|
|
int ret;
|
|
|
|
#ifdef __aarch64__
|
|
if (!(getauxval(AT_HWCAP2) & HWCAP2_BTI))
|
|
#endif
|
|
SKIP(return, "HWCAP2_BTI not supported");
|
|
|
|
self->p = mmap(NULL, self->size, PROT_EXEC, self->flags, 0, 0);
|
|
ASSERT_NE(self->p, MAP_FAILED);
|
|
|
|
ret = mprotect(self->p, self->size, PROT_EXEC | PROT_BTI);
|
|
EXPECT_EQ(ret, 0);
|
|
}
|
|
|
|
TEST_HARNESS_MAIN
|