x86/criu: shstk: restore SHSTK via premap loops

* call shstk_vma_restore() for VMA_AREA_SHSTK in vma_remap()
* delete map/copy/unmap from shstk_restore() and keep token setup + finalize
* before the loop naturally stopped at cet->ssp-8, so a -8 nudge is required here

Signed-off-by: Igor Svilenkov Bozic <svilenkov@gmail.com>
Co-Authored-By: Andrei Vagin <avagin@gmail.com>
[ alex: small code cleanups ]
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
This commit is contained in:
Igor Svilenkov Bozic 2025-09-06 18:13:37 +02:00 committed by Andrei Vagin
parent abf4a71d99
commit 6fd71b9ee9
2 changed files with 19 additions and 38 deletions

View file

@ -205,28 +205,11 @@ static always_inline int shstk_vma_restore(VmaEntry *vma_entry)
*/
static always_inline int shstk_restore(struct rst_shstk_info *cet)
{
unsigned long *shstk_data = (unsigned long *)cet->premmaped_addr;
unsigned long ssp = cet->vma_start + cet->vma_size - 8;
unsigned long shstk_top = cet->vma_size / 8 - 1;
unsigned long val;
long ret;
unsigned long ssp, val;
if (!(cet->cet & ARCH_SHSTK_SHSTK))
return 0;
if (shstk_map(cet->vma_start, cet->vma_size))
return -1;
/*
* Switch shadow stack from temporary location to the actual task's
* shadow stack VMA
*/
shstk_switch_ssp(ssp);
/* restore shadow stack contents */
for (; ssp >= cet->ssp; ssp -= 8, shstk_top--)
wrssq(ssp, shstk_data[shstk_top]);
/*
* Add tokens for sigreturn frame and for switch of the shadow stack.
* The sigreturn token will be checked by the kernel during
@ -236,6 +219,7 @@ static always_inline int shstk_restore(struct rst_shstk_info *cet)
*/
/* token for sigreturn frame */
ssp = cet->ssp - 8;
val = ALIGN_DOWN(cet->ssp, 8) | SHSTK_DATA_BIT;
wrssq(ssp, val);
@ -247,12 +231,6 @@ static always_inline int shstk_restore(struct rst_shstk_info *cet)
/* reset shadow stack pointer to the proper location */
shstk_switch_ssp(ssp);
ret = sys_munmap(shstk_data, cet->vma_size + PAGE_SIZE);
if (ret < 0) {
pr_err("Failed to unmap premmaped shadow stack\n");
return ret;
}
return shstk_finalize();
}
#define arch_shstk_restore shstk_restore

View file

@ -1112,6 +1112,23 @@ static int vma_remap(VmaEntry *vma_entry, int uffd)
pr_info("Remap %lx->%lx len %lx\n", src, dst, len);
/*
* SHSTK VMAs are a bit special, in fact we create shstk vma right in the
* shstk_vma_restore() and populate it with contents from a premapped VMA
* (which in turns is just a normal anonymous VMA!). Then, we munmap() this
* premapped VMA. After, we need to adjust vma_premmaped_start(vma_entry)
* to point to a created shstk vma and treat it as a premmaped one in vma_remap().
*/
if (vma_entry_is(vma_entry, VMA_AREA_SHSTK)) {
if (shstk_vma_restore(vma_entry)) {
pr_err("Unable to prepare shadow stack vma for remap %lx -> %lx\n", src, dst);
return -1;
}
/* shstk_vma_restore() modifies vma premapped address */
src = vma_premmaped_start(vma_entry);
}
if (src - dst < len)
guard = dst;
else if (dst - src < len)
@ -1811,13 +1828,6 @@ __visible long __export_restore_task(struct task_restore_args *args)
if (vma_entry->start > vma_entry->shmid)
break;
/*
* shadow stack VMAs cannot be remapped, they must be
* recreated with map_shadow_stack system call
*/
if (vma_entry_is(vma_entry, VMA_AREA_SHSTK))
continue;
if (vma_remap(vma_entry, args->uffd))
goto core_restore_end;
}
@ -1835,13 +1845,6 @@ __visible long __export_restore_task(struct task_restore_args *args)
if (vma_entry->start < vma_entry->shmid)
break;
/*
* shadow stack VMAs cannot be remapped, they must be
* recreated with map_shadow_stack system call
*/
if (vma_entry_is(vma_entry, VMA_AREA_SHSTK))
continue;
if (vma_remap(vma_entry, args->uffd))
goto core_restore_end;
}