2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-22 01:51:51 +00:00

criu: kerndat: add kdat_has_shstk()

Detect if CRIU runs with shadow stack enabled and store the result in
kerndat.

Unlike most kerndat knobs, kdat_has_shstk() does not check for
availability of the shadow stack in the kernel, but rather checks if
criu runs with shadow stack enabled.

This depends on hardware availabilty, kernel and glibc support, compiler
options and glibc tunables, so kdat_has_shstk() must be called every
time CRIU starts and its result cannot be cached.

The result will be used by the code that controls shadow stack
enablement in the next commit.

Signed-off-by: Mike Rapoport (IBM) <rppt@kernel.org>
This commit is contained in:
Mike Rapoport (IBM) 2023-11-29 18:55:35 +02:00 committed by Andrei Vagin
parent 2ebd1a4f0b
commit f47899c9ef
4 changed files with 57 additions and 0 deletions

View File

@ -4,5 +4,6 @@
extern int kdat_compatible_cr(void);
extern int kdat_can_map_vdso(void);
extern int kdat_x86_has_ptrace_fpu_xsave_bug(void);
extern int kdat_has_shstk(void);
#endif /* __CR_ASM_KERNDAT_H__ */

View File

@ -17,6 +17,7 @@
#include "asm/compat.h"
#include "asm/dump.h"
#include "asm/shstk.h"
int kdat_can_map_vdso(void)
{
@ -251,3 +252,29 @@ out_kill:
return ret;
}
/*
* Unlike most kerndat knobs, this does not check for availability of the
* shadow stack in the kernel, but rather checks if criu runs with shadow
* stack enabled.
*
* This depends on hardware availability, kernel and glibc support, compiler
* options and glibc tunables.
*/
int kdat_has_shstk(void)
{
unsigned long features;
if (!compel_cpu_has_feature(X86_FEATURE_SHSTK))
return 0;
if (syscall(__NR_arch_prctl, ARCH_SHSTK_STATUS, &features)) {
/* kernels that don't support shadow stack return -EINVAL */
if (errno == EINVAL)
return 0;
pr_perror("Cannot get shadow stack status");
return 1;
}
return !!(features & ARCH_SHSTK_SHSTK);
}

View File

@ -87,6 +87,7 @@ struct kerndat_s {
bool has_ipv6_freebind;
bool has_membarrier_get_registrations;
bool has_pagemap_scan;
bool has_shstk;
};
extern struct kerndat_s kdat;

View File

@ -1151,6 +1151,24 @@ static int kerndat_has_openat2(void)
return 0;
}
int __attribute__((weak)) kdat_has_shstk(void)
{
return 0;
}
static int kerndat_has_shstk(void)
{
int ret = kdat_has_shstk();
if (ret < 0) {
pr_err("kdat_has_shstk failed\n");
return ret;
}
kdat.has_shstk = !!ret;
return 0;
}
#define KERNDAT_CACHE_NAME "criu.kdat"
#define KERNDAT_CACHE_FILE KDAT_RUNDIR "/" KERNDAT_CACHE_NAME
@ -1705,6 +1723,12 @@ int kerndat_try_load_new(void)
return ret;
}
ret = kerndat_has_shstk();
if (ret < 0) {
pr_err("kerndat_has_shstk failed when initializing kerndat.\n");
return ret;
}
/* New information is found, we need to save to the cache */
if (ret)
kerndat_save_cache();
@ -1926,6 +1950,10 @@ int kerndat_init(void)
pr_err("kerndat_has_membarrier_get_registrations failed when initializing kerndat.\n");
ret = -1;
}
if (!ret && kerndat_has_shstk()) {
pr_err("kerndat_has_shstk failed when initializing kerndat.\n");
ret = -1;
}
kerndat_lsm();
kerndat_mmap_min_addr();