Shadow stack enabling from dynamic loader v/s kernel on exec

Deepak Gupta
2023-11-23T00:28:05Z

I don't want to divert focus from patch specific comments on shadow
stack patches that're being
discussed in the mailing list. And that's starting this separate
thread about enabling the shadow
stack in the dynamic loader v/s kernel. I've put relevant folks in
"To" and "kernel" and "libc" in CC.

We've beaten this record many times but I think this is the first time
I am getting into weeds.

Per this https://lore.kernel.org/all/20220130211838.8382-1-rick.p.edgecombe@intel.com/,
all
the binaries that were marked with shadow stack are ready to break as
soon as new kernel enables
shadow stack by default based on ELF bit. And thus the reason to let
it be decided up in user
mode and making the kernel oblivious about this decision making during exec.

It looks like it was done because libc changes landed in userspace
binaries from major distros before
the kernel changes could be merged and kernel-user interface changed
as kernel changes matured.

Such an issue doesn't exist for non-x86 (at least risc-v because
that's what I am focussing on). And
have been wondering that if doing below would be a better choice:

- On `exec`, the kernel looks at the ELF bit and sets up a shadow stack
- Dynamic loader (or statically built binary) starts life with shadow stack
- Dynamic loader can disable shadow stack if it wants if it sees some
compat issues
[This last step of figuring out compat issues, anyways dynamic
loader is performing today]

This has many advantages
- dynamic loaders (and static binary) are protected from loader
specific ROP attack in a small window
- stack and shadow stack are always balanced

One disadvantage I can see is that enabling the shadow stack is split
but I really don't see it as a big
disadvantage. Please note that enable/disable/get status prctls can
still exist. And thus user space still
has all the enabling / disabling control with itself depending on
configuration.

Larger question and opinion / input that I am seeking here is that
(from kernel / libc community)

"Was there any other reason other than supporting ELF binaries that
went ahead of kernel changes that
led to decision of delegating of shadow stack enabling in dynamic loader"

If there are other complications that can happen due to kernel
enabling of shadow stack based on ELF bits,
I would like to know about them.

-Deepak