1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
// 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();
}
|