restore/pie: check return value of sys_rseq on unregister

The return value of sys_rseq was previously ignored during
unregistration, under the assumption that it would not fail if the rseq
structure was properly registered.

However, if sys_rseq fails, the kernel retains the registration. If the
memory containing the rseq structure is subsequently unmapped or reused,
kernel updates to the rseq area can cause the process to crash (e.g.,
via SIGSEGV).

Check the return value of sys_rseq. If it fails, log the error code and
abort the restoration process. This makes rseq unregistration failures
fatal and explicit, aiding in debugging and preventing later obscure
crashes.

Signed-off-by: liqiang2020 <liqiang64@huawei.com>
This commit is contained in:
liqiang2020 2025-12-16 18:14:13 +08:00 committed by Andrei Vagin
parent fb59ae504e
commit 07af3304fd

View file

@ -1363,13 +1363,19 @@ __visible void __export_unmap(void)
sys_munmap(bootstrap_start, bootstrap_len - vdso_rt_size);
}
static void unregister_libc_rseq(struct rst_rseq_param *rseq)
static int unregister_libc_rseq(struct rst_rseq_param *rseq)
{
if (!rseq->rseq_abi_pointer)
return;
long ret;
/* can't fail if rseq is registered */
sys_rseq(decode_pointer(rseq->rseq_abi_pointer), rseq->rseq_abi_size, 1, rseq->signature);
if (!rseq->rseq_abi_pointer)
return 0;
ret = sys_rseq(decode_pointer(rseq->rseq_abi_pointer), rseq->rseq_abi_size, 1, rseq->signature);
if (ret) {
pr_err("Failed to unregister libc rseq %ld\n", ret);
return -1;
}
return 0;
}
/*
@ -1803,7 +1809,8 @@ __visible long __export_restore_task(struct task_restore_args *args)
* for instance once the kernel will want to update (struct rseq).cpu_id field:
* https://github.com/torvalds/linux/blob/ce522ba9ef7e/kernel/rseq.c#L89
*/
unregister_libc_rseq(&args->libc_rseq);
if (unregister_libc_rseq(&args->libc_rseq))
goto core_restore_end;
if (unmap_old_vmas((void *)args->premmapped_addr, args->premmapped_len, bootstrap_start, bootstrap_len,
args->task_size))