On Fri, Aug 11, 2023 at 05:26:03PM +0100, Catalin Marinas wrote:
On Mon, Aug 07, 2023 at 11:00:24PM +0100, Mark Brown wrote:
- mmap_write_lock(mm);
- mapped_addr = do_mmap(NULL, addr, size, PROT_READ, flags,
VM_SHADOW_STACK | VM_WRITE, 0, &unused, NULL);
Why not PROT_WRITE as well? I guess I need to check the x86 patches since the do_mmap() called here has a different prototype than what's in mainline.
This gets confusing since currently the VM_* flags are derived from the PROT_* flags passed to mmap(). But you skip the PROT_WRITE in favour of adding VM_WRITE directly.
I have to confess that I inherited this from the x86 code and never thought too hard about it. I've got a horrible feeling the reasoning is simply the way in which x86 fits shadow stack into the page tables without having a mechanism like permission indirection, these don't apply for us.
I haven't followed the x86 discussion but did we run out of PROT_* bits for a PROT_SHADOW_STACK?
It's more that there are security concerns with having PROT_, especially in conjunction with needing to provide a token for stack pivot - we not only need to map pages for the GCS, we also need to write a cap token into it so that we can pivot to the new stack. If the GCS can ever be written to by userspace via normal means then that's an issue for the basic protection model that the feature is trying to implement. If we have the PROT_ but try to check for bad uses of it that makes everything messy and complicated which is especially non-ideal for a feature with a security focus. Having a more packaged system call is easier for everyone.
More detail in the x86 patch that's currently in -next:
https://lore.kernel.org/all/20230319001535.23210-34-rick.p.edgecombe@intel.c...
- /* Allocate RLIMIT_STACK with limits of PAGE_SIZE..4G */
- size = PAGE_ALIGN(min_t(unsigned long long,
rlimit(RLIMIT_STACK), SZ_4G));
- return max(PAGE_SIZE, size);
+}
I saw Szabolcs commenting on the default size as well. Maybe we should go for RLIMIT_STACK/2 but let's see how the other sub-thread is going.
I've updated it.
- if ((clone_flags & (CLONE_VFORK | CLONE_VM)) != CLONE_VM)
return 0;
Is it safe for CLONE_VFORK not to get a new shadow stack? A syscall for exec could push something to the stack. I guess the GCS pointer in the parent stays the same, so it wouldn't matter.
Yes, pushing should be fine just as for the regular stack.
That said, I think this check should be somewhere higher up in the caller of gcs_alloc_thread_stack(). The copy_thread_gcs() function already does most of the above checks. Is the GCS allocation called from elsewhere as well?
That's the only place. I've moved the above check into copy_thread_gcs(), you're right that the other checks are redundant as they're done in the caller already.