Skip to content

Commit 7fad2a4

Browse files
rpedgecohansendc
authored andcommitted
x86/shstk: Check that signal frame is shadow stack mem
The shadow stack signal frame is read by the kernel on sigreturn. It relies on shadow stack memory protections to prevent forgeries of this signal frame (which included the pre-signal SSP). This behavior helps userspace protect itself. However, using the INCSSP instruction userspace can adjust the SSP to 8 bytes beyond the end of a shadow stack. INCSSP performs shadow stack reads to make sure it doesn’t increment off of the shadow stack, but on the end position it actually reads 8 bytes below the new SSP. For the shadow stack HW operations, this situation (INCSSP off the end of a shadow stack by 8 bytes) would be fine. If the a RET is executed, the push to the shadow stack would fail to write to the shadow stack. If a CALL is executed, the SSP will be incremented back onto the stack and the return address will be written successfully to the very end. That is expected behavior around shadow stack underflow. However, the kernel doesn’t have a way to read shadow stack memory using shadow stack accesses. WRUSS can write to shadow stack memory with a shadow stack access which ensures the access is to shadow stack memory. But unfortunately for this case, there is no equivalent instruction for shadow stack reads. So when reading the shadow stack signal frames, the kernel currently assumes the SSP is pointing to the shadow stack and uses a normal read. The SSP pointing to shadow stack memory will be true in most cases, but as described above, in can be untrue by 8 bytes. So lookup the VMA of the shadow stack sigframe being read to verify it is shadow stack. Since the SSP can only be beyond the shadow stack by 8 bytes, and shadow stack memory is page aligned, this check only needs to be done when this type of relative position to a page boundary is encountered. So skip the extra work otherwise. Signed-off-by: Rick Edgecombe <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Link: https://lore.kernel.org/all/20230613001108.3040476-34-rick.p.edgecombe%40intel.com
1 parent b93d6c7 commit 7fad2a4

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

arch/x86/kernel/shstk.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,15 +249,38 @@ static int shstk_push_sigframe(unsigned long *ssp)
249249

250250
static int shstk_pop_sigframe(unsigned long *ssp)
251251
{
252+
struct vm_area_struct *vma;
252253
unsigned long token_addr;
253-
int err;
254+
bool need_to_check_vma;
255+
int err = 1;
254256

257+
/*
258+
* It is possible for the SSP to be off the end of a shadow stack by 4
259+
* or 8 bytes. If the shadow stack is at the start of a page or 4 bytes
260+
* before it, it might be this case, so check that the address being
261+
* read is actually shadow stack.
262+
*/
255263
if (!IS_ALIGNED(*ssp, 8))
256264
return -EINVAL;
257265

266+
need_to_check_vma = PAGE_ALIGN(*ssp) == *ssp;
267+
268+
if (need_to_check_vma)
269+
mmap_read_lock_killable(current->mm);
270+
258271
err = get_shstk_data(&token_addr, (unsigned long __user *)*ssp);
259272
if (unlikely(err))
260-
return err;
273+
goto out_err;
274+
275+
if (need_to_check_vma) {
276+
vma = find_vma(current->mm, *ssp);
277+
if (!vma || !(vma->vm_flags & VM_SHADOW_STACK)) {
278+
err = -EFAULT;
279+
goto out_err;
280+
}
281+
282+
mmap_read_unlock(current->mm);
283+
}
261284

262285
/* Restore SSP aligned? */
263286
if (unlikely(!IS_ALIGNED(token_addr, 8)))
@@ -270,6 +293,10 @@ static int shstk_pop_sigframe(unsigned long *ssp)
270293
*ssp = token_addr;
271294

272295
return 0;
296+
out_err:
297+
if (need_to_check_vma)
298+
mmap_read_unlock(current->mm);
299+
return err;
273300
}
274301

275302
int setup_signal_shadow_stack(struct ksignal *ksig)

0 commit comments

Comments
 (0)