The __NR_mmap isn't found on armhf. The mmap() is commonly available
system call and its wrapper is present on all architectures. So it should
be used directly. It solves problem for armhf and doesn't create problem
for other architectures.
Remove sys_mmap() functions as they aren't doing anything else other than
calling mmap(). There is no need to set errno = 0 manually as glibc
always resets it.
For reference errors are as following:
CC seal_elf
seal_elf.c: In function 'sys_mmap':
seal_elf.c:39:33: error: '__NR_mmap' undeclared (first use in this function)
39 | sret = (void *) syscall(__NR_mmap, addr, len, prot,
| ^~~~~~~~~
mseal_test.c: In function 'sys_mmap':
mseal_test.c:90:33: error: '__NR_mmap' undeclared (first use in this function)
90 | sret = (void *) syscall(__NR_mmap, addr, len, prot,
| ^~~~~~~~~
Link: https://lkml.kernel.org/r/20240809082511.497266-1-usama.anjum@collabora.com
Fixes: 4926c7a52d
("selftest mm/mseal memory sealing")
Signed-off-by: Muhammad Usama Anjum <usama.anjum@collabora.com>
Cc: Jeff Xu <jeffxu@chromium.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
137 lines
3 KiB
C
137 lines
3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#define _GNU_SOURCE
|
|
#include <sys/mman.h>
|
|
#include <stdint.h>
|
|
#include <asm-generic/unistd.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#include <stdbool.h>
|
|
#include "../kselftest.h"
|
|
#include <syscall.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/vfs.h>
|
|
#include <sys/stat.h>
|
|
#include "mseal_helpers.h"
|
|
|
|
/*
|
|
* define sys_xyx to call syscall directly.
|
|
*/
|
|
static int sys_mseal(void *start, size_t len)
|
|
{
|
|
int sret;
|
|
|
|
errno = 0;
|
|
sret = syscall(__NR_mseal, start, len, 0);
|
|
return sret;
|
|
}
|
|
|
|
static inline int sys_mprotect(void *ptr, size_t size, unsigned long prot)
|
|
{
|
|
int sret;
|
|
|
|
errno = 0;
|
|
sret = syscall(__NR_mprotect, ptr, size, prot);
|
|
return sret;
|
|
}
|
|
|
|
static bool seal_support(void)
|
|
{
|
|
int ret;
|
|
void *ptr;
|
|
unsigned long page_size = getpagesize();
|
|
|
|
ptr = mmap(NULL, page_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
if (ptr == (void *) -1)
|
|
return false;
|
|
|
|
ret = sys_mseal(ptr, page_size);
|
|
if (ret < 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
const char somestr[4096] = {"READONLY"};
|
|
|
|
static void test_seal_elf(void)
|
|
{
|
|
int ret;
|
|
FILE *maps;
|
|
char line[512];
|
|
uintptr_t addr_start, addr_end;
|
|
char prot[5];
|
|
char filename[256];
|
|
unsigned long page_size = getpagesize();
|
|
unsigned long long ptr = (unsigned long long) somestr;
|
|
char *somestr2 = (char *)somestr;
|
|
|
|
/*
|
|
* Modify the protection of readonly somestr
|
|
*/
|
|
if (((unsigned long long)ptr % page_size) != 0)
|
|
ptr = (unsigned long long)ptr & ~(page_size - 1);
|
|
|
|
ksft_print_msg("somestr = %s\n", somestr);
|
|
ksft_print_msg("change protection to rw\n");
|
|
ret = sys_mprotect((void *)ptr, page_size, PROT_READ|PROT_WRITE);
|
|
FAIL_TEST_IF_FALSE(!ret);
|
|
*somestr2 = 'A';
|
|
ksft_print_msg("somestr is modified to: %s\n", somestr);
|
|
ret = sys_mprotect((void *)ptr, page_size, PROT_READ);
|
|
FAIL_TEST_IF_FALSE(!ret);
|
|
|
|
maps = fopen("/proc/self/maps", "r");
|
|
FAIL_TEST_IF_FALSE(maps);
|
|
|
|
/*
|
|
* apply sealing to elf binary
|
|
*/
|
|
while (fgets(line, sizeof(line), maps)) {
|
|
if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*u %255[^\n]",
|
|
&addr_start, &addr_end, prot, filename) == 4) {
|
|
if (strlen(filename)) {
|
|
/*
|
|
* seal the mapping if read only.
|
|
*/
|
|
if (strstr(prot, "r-")) {
|
|
ret = sys_mseal((void *)addr_start, addr_end - addr_start);
|
|
FAIL_TEST_IF_FALSE(!ret);
|
|
ksft_print_msg("sealed: %lx-%lx %s %s\n",
|
|
addr_start, addr_end, prot, filename);
|
|
if ((uintptr_t) somestr >= addr_start &&
|
|
(uintptr_t) somestr <= addr_end)
|
|
ksft_print_msg("mapping for somestr found\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose(maps);
|
|
|
|
ret = sys_mprotect((void *)ptr, page_size, PROT_READ | PROT_WRITE);
|
|
FAIL_TEST_IF_FALSE(ret < 0);
|
|
ksft_print_msg("somestr is sealed, mprotect is rejected\n");
|
|
|
|
REPORT_TEST_PASS();
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
bool test_seal = seal_support();
|
|
|
|
ksft_print_header();
|
|
ksft_print_msg("pid=%d\n", getpid());
|
|
|
|
if (!test_seal)
|
|
ksft_exit_skip("sealing not supported, check CONFIG_64BIT\n");
|
|
|
|
ksft_set_plan(1);
|
|
|
|
test_seal_elf();
|
|
|
|
ksft_finished();
|
|
}
|