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

arm64: C/R PAC keys

PAC stands for Pointer Authentication Code. Each process has 5 PAC keys
and a mask of enabled keys. All this properties have to be C/R-ed.

As they are per-process protperties, we can save/restore them just for
one thread.

Signed-off-by: Andrei Vagin <avagin@google.com>
This commit is contained in:
AV 2025-03-03 19:14:54 +00:00 committed by Radostin Stoyanov
parent 8d5cef546a
commit 1cf8040173
31 changed files with 244 additions and 26 deletions

View File

@ -81,7 +81,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
goto err;
}
ret = save(arg, regs, fpsimd);
ret = save(pid, arg, regs, fpsimd);
err:
return ret;
}

View File

@ -94,7 +94,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
}
}
ret = save(arg, regs, vfp);
ret = save(pid, arg, regs, vfp);
err:
return ret;
}

View File

@ -91,7 +91,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
goto err;
}
ret = save(arg, regs, fpregs);
ret = save(pid, arg, regs, fpregs);
err:
return 0;
}

View File

@ -149,7 +149,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
regs->regs[0] = 0;
}
ret = save(arg, regs, xs);
ret = save(pid, arg, regs, xs);
return ret;
}

View File

@ -400,7 +400,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
if (ret)
return ret;
return save(arg, regs, fpregs);
return save(pid, arg, regs, fpregs);
}
int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs)

View File

@ -92,7 +92,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
return -1;
}
ret = save(arg, regs, fpsimd);
ret = save(pid, arg, regs, fpsimd);
return ret;
}

View File

@ -348,7 +348,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
}
}
/* Call save_task_regs() */
return save(arg, regs, fpregs);
return save(pid, arg, regs, fpregs);
}
int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs)

View File

@ -453,7 +453,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
goto err;
out:
ret = save(arg, regs, xs);
ret = save(pid, arg, regs, xs);
err:
return ret;
}

View File

@ -97,7 +97,7 @@ extern k_rtsigset_t *compel_thread_sigmask(struct parasite_thread_ctl *tctl);
struct rt_sigframe;
typedef int (*open_proc_fn)(int pid, int mode, const char *fmt, ...) __attribute__((__format__(__printf__, 3, 4)));
typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
typedef int (*save_regs_t)(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
typedef int (*make_sigframe_t)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *);
struct infect_ctx {

View File

@ -1300,7 +1300,7 @@ struct plain_regs_struct {
user_fpregs_struct_t fpregs;
};
static int save_regs_plain(void *to, user_regs_struct_t *r, user_fpregs_struct_t *f)
static int save_regs_plain(pid_t pid, void *to, user_regs_struct_t *r, user_fpregs_struct_t *f)
{
struct plain_regs_struct *prs = to;

View File

@ -1,5 +1,6 @@
#include <string.h>
#include <unistd.h>
#include <linux/auxvec.h>
#include <linux/elf.h>
@ -20,10 +21,86 @@
#include "cpu.h"
#include "restorer.h"
#include "compel/infect.h"
#include "pstree.h"
extern unsigned long getauxval(unsigned long type);
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
static int save_pac_keys(int pid, CoreEntry *core)
{
struct user_pac_address_keys paca;
struct user_pac_generic_keys pacg;
PacKeys *pac_entry;
long pac_enabled_key;
struct iovec iov;
int ret;
unsigned long hwcaps = getauxval(AT_HWCAP);
pac_entry = xmalloc(sizeof(PacKeys));
if (!pac_entry)
return -1;
core->ti_aarch64->pac_keys = pac_entry;
pac_keys__init(pac_entry);
if (hwcaps & HWCAP_PACA) {
PacAddressKeys *pac_address_keys;
pr_debug("%d: Dumping address authentication keys\n", pid);
iov.iov_base = &paca;
iov.iov_len = sizeof(paca);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_ARM_PACA_KEYS, &iov))) {
pr_perror("Failed to get address authentication key for %d", pid);
return -1;
}
pac_address_keys = xmalloc(sizeof(PacAddressKeys));
if (!pac_address_keys)
return -1;
pac_address_keys__init(pac_address_keys);
pac_entry->pac_address_keys = pac_address_keys;
pac_address_keys->apiakey_lo = paca.apiakey;
pac_address_keys->apiakey_hi = paca.apiakey >> 64;
pac_address_keys->apibkey_lo = paca.apibkey;
pac_address_keys->apibkey_hi = paca.apibkey >> 64;
pac_address_keys->apdakey_lo = paca.apdakey;
pac_address_keys->apdakey_hi = paca.apdakey >> 64;
pac_address_keys->apdbkey_lo = paca.apdbkey;
pac_address_keys->apdbkey_hi = paca.apdbkey >> 64;
iov.iov_base = &pac_enabled_key;
iov.iov_len = sizeof(pac_enabled_key);
ret = ptrace(PTRACE_GETREGSET, pid, NT_ARM_PAC_ENABLED_KEYS, &iov);
if (ret) {
pr_perror("Failed to get authentication key mask for %d", pid);
return -1;
}
pac_address_keys->pac_enabled_key = pac_enabled_key;
}
if (hwcaps & HWCAP_PACG) {
PacGenericKeys *pac_generic_keys;
pr_debug("%d: Dumping generic authentication keys\n", pid);
iov.iov_base = &pacg;
iov.iov_len = sizeof(pacg);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_ARM_PACG_KEYS, &iov))) {
pr_perror("Failed to get a generic authantication key for %d", pid);
return -1;
}
pac_generic_keys = xmalloc(sizeof(PacGenericKeys));
if (!pac_generic_keys)
return -1;
pac_generic_keys__init(pac_generic_keys);
pac_entry->pac_generic_keys = pac_generic_keys;
pac_generic_keys->apgakey_lo = pacg.apgakey;
pac_generic_keys->apgakey_hi = pacg.apgakey >> 64;
}
return 0;
}
int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
{
int i;
CoreEntry *core = x;
@ -43,6 +120,8 @@ int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsi
assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpsr);
assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpcr);
if (save_pac_keys(pid, core))
return -1;
return 0;
}
@ -92,6 +171,12 @@ void arch_free_thread_info(CoreEntry *core)
xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd->vregs);
xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd);
}
if (CORE_THREAD_ARCH_INFO(core)->pac_keys) {
PacKeys *pac_entry = CORE_THREAD_ARCH_INFO(core)->pac_keys;
xfree(pac_entry->pac_address_keys);
xfree(pac_entry->pac_generic_keys);
xfree(pac_entry);
}
xfree(CORE_THREAD_ARCH_INFO(core)->gpregs->regs);
xfree(CORE_THREAD_ARCH_INFO(core)->gpregs);
xfree(CORE_THREAD_ARCH_INFO(core));
@ -135,3 +220,83 @@ int restore_gpregs(struct rt_sigframe *f, UserRegsEntry *r)
return 0;
}
int arch_ptrace_restore(int pid, struct pstree_item *item)
{
unsigned long hwcaps = getauxval(AT_HWCAP);
struct user_pac_address_keys upaca;
struct user_pac_generic_keys upacg;
PacAddressKeys *paca;
PacGenericKeys *pacg;
long pac_enabled_keys;
struct iovec iov;
int ret;
pr_debug("%d: Restoring PAC keys\n", pid);
paca = &rsti(item)->arch_info.pac_address_keys;
pacg = &rsti(item)->arch_info.pac_generic_keys;
if (rsti(item)->arch_info.has_paca) {
if (!(hwcaps & HWCAP_PACA)) {
pr_err("PACG support is required from the source system.\n");
return 1;
}
pac_enabled_keys = rsti(item)->arch_info.pac_address_keys.pac_enabled_key;
upaca.apiakey = paca->apiakey_lo + ((__uint128_t)paca->apiakey_hi << 64);
upaca.apibkey = paca->apibkey_lo + ((__uint128_t)paca->apibkey_hi << 64);
upaca.apdakey = paca->apdakey_lo + ((__uint128_t)paca->apdakey_hi << 64);
upaca.apdbkey = paca->apdbkey_lo + ((__uint128_t)paca->apdbkey_hi << 64);
iov.iov_base = &upaca;
iov.iov_len = sizeof(upaca);
if ((ret = ptrace(PTRACE_SETREGSET, pid, NT_ARM_PACA_KEYS, &iov))) {
pr_perror("Failed to set address authentication keys for %d", pid);
return 1;
}
iov.iov_base = &pac_enabled_keys;
iov.iov_len = sizeof(pac_enabled_keys);
if ((ret = ptrace(PTRACE_SETREGSET, pid, NT_ARM_PAC_ENABLED_KEYS, &iov))) {
pr_perror("Failed to set enabled key mask for %d", pid);
return 1;
}
}
if (rsti(item)->arch_info.has_pacg) {
if (!(hwcaps & HWCAP_PACG)) {
pr_err("PACG support is required from the source system.\n");
return 1;
}
upacg.apgakey = pacg->apgakey_lo + ((__uint128_t)pacg->apgakey_hi << 64);
iov.iov_base = &upacg;
iov.iov_len = sizeof(upacg);
if ((ret = ptrace(PTRACE_SETREGSET, pid, NT_ARM_PACG_KEYS, &iov))) {
pr_perror("Failed to set the generic authentication key for %d", pid);
return 1;
}
}
return 0;
}
void arch_rsti_init(struct pstree_item *p)
{
PacKeys *pac_keys = p->core[0]->ti_aarch64->pac_keys;
rsti(p)->arch_info.has_paca = false;
rsti(p)->arch_info.has_pacg = false;
if (!pac_keys)
return;
if (pac_keys->pac_address_keys) {
rsti(p)->arch_info.has_paca = true;
rsti(p)->arch_info.pac_address_keys = *pac_keys->pac_address_keys;
}
if (pac_keys->pac_generic_keys) {
rsti(p)->arch_info.has_pacg = true;
rsti(p)->arch_info.pac_generic_keys = *pac_keys->pac_generic_keys;
}
}

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);

View File

@ -26,4 +26,14 @@ static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls)
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core);
#define ARCH_RST_INFO y
struct rst_arch_info {
bool has_paca, has_pacg;
PacAddressKeys pac_address_keys;
PacGenericKeys pac_generic_keys;
};
int arch_ptrace_restore(int pid, struct pstree_item *item);
void arch_rsti_init(struct pstree_item *current);
#endif

View File

@ -22,7 +22,7 @@
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))((src)->ARM_##e)
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
CoreEntry *core = x;

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);

View File

@ -29,7 +29,7 @@
#define assign_reg(dst, src, e) (dst)->e = (__typeof__(dst->e))(src)->e
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
int i;
CoreEntry *core = x;

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);

View File

@ -27,7 +27,7 @@
#include "images/core.pb-c.h"
#include "images/creds.pb-c.h"
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
CoreEntry *core = x;

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
extern int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info);

View File

@ -404,7 +404,7 @@ static int __copy_task_regs(user_regs_struct_t *regs, user_fpregs_struct_t *fpre
return 0;
}
int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f)
int save_task_regs(pid_t pid, void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f)
{
return __copy_task_regs(u, f, (CoreEntry *)arg);
}

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);

View File

@ -23,7 +23,7 @@
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
{
int i;
CoreEntry *core = x;

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);

View File

@ -282,7 +282,7 @@ static void free_ri_cb(UserS390RiEntry *ri_cb)
/*
* Copy internal structures into Google Protocol Buffers
*/
int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f)
int save_task_regs(pid_t pid, void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f)
{
UserS390VxrsHighEntry *vxrs_high = NULL;
UserS390VxrsLowEntry *vxrs_low = NULL;

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
int save_task_regs(void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f);
int save_task_regs(pid_t pid, void *arg, user_regs_struct_t *u, user_fpregs_struct_t *f);
int arch_alloc_thread_info(CoreEntry *core);
void arch_free_thread_info(CoreEntry *core);

View File

@ -15,7 +15,7 @@
#define XSAVE_PB_NELEMS(__s, __obj, __member) (sizeof(__s) / sizeof(*(__obj)->__member))
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
CoreEntry *core = x;
UserX86RegsEntry *gpregs = core->thread_info->gpregs;

View File

@ -11,6 +11,8 @@
#include <sys/mman.h>
#include "log.h"
static inline void *alloc_compat_syscall_stack(void)
{
void *mem = (void *)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE,

View File

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);
extern int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info);

View File

@ -17,6 +17,7 @@
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sched.h>
#include <linux/elf.h>
#include "types.h"
#include <compel/ptrace.h>
@ -1707,6 +1708,9 @@ static int restore_task_with_children(void *_arg)
arg);
}
int __attribute((weak)) arch_ptrace_restore(int pid, struct pstree_item *item);
int arch_ptrace_restore(int pid, struct pstree_item *item) { return 0; }
static int attach_to_tasks(bool root_seized)
{
struct pstree_item *item;
@ -1747,6 +1751,8 @@ static int attach_to_tasks(bool root_seized)
pr_perror("Unable to set PTRACE_O_TRACESYSGOOD for %d", pid);
return -1;
}
if (arch_ptrace_restore(pid, item))
return -1;
/*
* Suspend seccomp if necessary. We need to do this because
* although seccomp is restored at the very end of the
@ -3104,6 +3110,9 @@ static void *restorer_munmap_addr(CoreEntry *core, void *restorer_blob)
return restorer_sym(restorer_blob, arch_export_unmap);
}
void arch_rsti_init(struct pstree_item *p) __attribute__((weak));
void arch_rsti_init(struct pstree_item *p) {}
static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, unsigned long alen, CoreEntry *core)
{
void *mem = MAP_FAILED;
@ -3323,6 +3332,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
*/
creds_pos_next = creds_pos;
siginfo_n = task_args->siginfo_n;
arch_rsti_init(current);
for (i = 0; i < current->nr_threads; i++) {
CoreEntry *tcore;
struct rt_sigframe *sigframe;

View File

@ -1,6 +1,7 @@
#ifndef __CR_RST_INFO_H__
#define __CR_RST_INFO_H__
#include "asm/restore.h"
#include "common/lock.h"
#include "common/list.h"
#include "vma.h"
@ -33,6 +34,11 @@ struct rst_rseq {
uint64_t rseq_cs_pointer;
};
#ifndef ARCH_RST_INFO
struct rst_arch_info {
};
#endif
struct rst_info {
struct list_head fds;
@ -80,6 +86,8 @@ struct rst_info {
futex_t shstk_unlock;
void *breakpoint;
struct rst_arch_info arch_info;
};
extern struct task_entries *task_entries;

View File

@ -17,9 +17,32 @@ message user_aarch64_fpsimd_context_entry {
required uint32 fpcr = 3;
}
message pac_address_keys {
required uint64 apiakey_lo = 1;
required uint64 apiakey_hi = 2;
required uint64 apibkey_lo = 3;
required uint64 apibkey_hi = 4;
required uint64 apdakey_lo = 5;
required uint64 apdakey_hi = 6;
required uint64 apdbkey_lo = 7;
required uint64 apdbkey_hi = 8;
required uint64 pac_enabled_key = 9;
}
message pac_generic_keys {
required uint64 apgakey_lo = 1;
required uint64 apgakey_hi = 2;
}
message pac_keys {
optional pac_address_keys pac_address_keys = 6;
optional pac_generic_keys pac_generic_keys = 7;
}
message thread_info_aarch64 {
required uint64 clear_tid_addr = 1[(criu).hex = true];
required uint64 tls = 2;
required user_aarch64_regs_entry gpregs = 3[(criu).hex = true];
required user_aarch64_fpsimd_context_entry fpsimd = 4;
optional pac_keys pac_keys = 5;
}