Message ID | 20180607143807.3611-7-yu-cheng.yu@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > > The following operations are provided. > > ARCH_CET_STATUS: > return the current CET status > > ARCH_CET_DISABLE: > disable CET features > > ARCH_CET_LOCK: > lock out CET features > > ARCH_CET_EXEC: > set CET features for exec() > > ARCH_CET_ALLOC_SHSTK: > allocate a new shadow stack > > ARCH_CET_PUSH_SHSTK: > put a return address on shadow stack > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for > the implementation of GLIBC ucontext related APIs. Please document exactly what these all do and why. I don't understand what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for each ELF program, so I think there should be no need for a magic override.
On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > > > > The following operations are provided. > > > > ARCH_CET_STATUS: > > return the current CET status > > > > ARCH_CET_DISABLE: > > disable CET features > > > > ARCH_CET_LOCK: > > lock out CET features > > > > ARCH_CET_EXEC: > > set CET features for exec() > > > > ARCH_CET_ALLOC_SHSTK: > > allocate a new shadow stack > > > > ARCH_CET_PUSH_SHSTK: > > put a return address on shadow stack > > > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for > > the implementation of GLIBC ucontext related APIs. > > Please document exactly what these all do and why. I don't understand > what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for > each ELF program, so I think there should be no need for a magic > override. CET is initially enabled if the loader has CET capability. Then the loader decides if the application can run with CET. If the application cannot run with CET (e.g. a dependent library does not have CET), then the loader turns off CET before passing to the application. When the loader is done, it locks out CET and the feature cannot be turned off anymore until the next exec() call. When the next exec() is called, CET feature is turned on/off based on the values set by ARCH_CET_EXEC. I will put more details in Documentation/x86/intel_cet.txt.
On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > > On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: > > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > > > > > > The following operations are provided. > > > > > > ARCH_CET_STATUS: > > > return the current CET status > > > > > > ARCH_CET_DISABLE: > > > disable CET features > > > > > > ARCH_CET_LOCK: > > > lock out CET features > > > > > > ARCH_CET_EXEC: > > > set CET features for exec() > > > > > > ARCH_CET_ALLOC_SHSTK: > > > allocate a new shadow stack > > > > > > ARCH_CET_PUSH_SHSTK: > > > put a return address on shadow stack > > > > > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for > > > the implementation of GLIBC ucontext related APIs. > > > > Please document exactly what these all do and why. I don't understand > > what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for > > each ELF program, so I think there should be no need for a magic > > override. > > CET is initially enabled if the loader has CET capability. Then the > loader decides if the application can run with CET. If the application > cannot run with CET (e.g. a dependent library does not have CET), then > the loader turns off CET before passing to the application. When the > loader is done, it locks out CET and the feature cannot be turned off > anymore until the next exec() call. Why is the lockout necessary? If user code enables CET and tries to run code that doesn't support CET, it will crash. I don't see why we need special code in the kernel to prevent a user program from calling arch_prctl() and crashing itself. There are already plenty of ways to do that :) > When the next exec() is called, CET > feature is turned on/off based on the values set by ARCH_CET_EXEC. And why do we need ARCH_CET_EXEC? For background, I really really dislike adding new state that persists across exec(). It's nice to get as close to a clean slate as possible after exec() so that programs can run in a predictable environment. exec() is also a security boundary, and anything a task can do to affect itself after exec() needs to have its security implications considered very carefully. (As a trivial example, you should not be able to use cetcmd ... sudo [malicious options here] to cause sudo to run with CET off and then try to exploit it via the malicious options. If a shutoff is needed for testing, how about teaching ld.so to parse LD_CET=no or similar and protect it the same way as LD_PRELOAD is protected. Or just do LD_PRELOAD=/lib/libdoesntsupportcet.so. --Andy
On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> >> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: >> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> > > >> > > The following operations are provided. >> > > >> > > ARCH_CET_STATUS: >> > > return the current CET status >> > > >> > > ARCH_CET_DISABLE: >> > > disable CET features >> > > >> > > ARCH_CET_LOCK: >> > > lock out CET features >> > > >> > > ARCH_CET_EXEC: >> > > set CET features for exec() >> > > >> > > ARCH_CET_ALLOC_SHSTK: >> > > allocate a new shadow stack >> > > >> > > ARCH_CET_PUSH_SHSTK: >> > > put a return address on shadow stack >> > > >> > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for >> > > the implementation of GLIBC ucontext related APIs. >> > >> > Please document exactly what these all do and why. I don't understand >> > what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for >> > each ELF program, so I think there should be no need for a magic >> > override. >> >> CET is initially enabled if the loader has CET capability. Then the >> loader decides if the application can run with CET. If the application >> cannot run with CET (e.g. a dependent library does not have CET), then >> the loader turns off CET before passing to the application. When the >> loader is done, it locks out CET and the feature cannot be turned off >> anymore until the next exec() call. > > Why is the lockout necessary? If user code enables CET and tries to > run code that doesn't support CET, it will crash. I don't see why we > need special code in the kernel to prevent a user program from calling > arch_prctl() and crashing itself. There are already plenty of ways to > do that :) On CET enabled machine, not all programs nor shared libraries are CET enabled. But since ld.so is CET enabled, all programs start as CET enabled. ld.so will disable CET if a program or any of its shared libraries aren't CET enabled. ld.so will lock up CET once it is done CET checking so that CET can't no longer be disabled afterwards. >> When the next exec() is called, CET >> feature is turned on/off based on the values set by ARCH_CET_EXEC. > > And why do we need ARCH_CET_EXEC? > > For background, I really really dislike adding new state that persists > across exec(). It's nice to get as close to a clean slate as possible > after exec() so that programs can run in a predictable environment. > exec() is also a security boundary, and anything a task can do to > affect itself after exec() needs to have its security implications > considered very carefully. (As a trivial example, you should not be > able to use cetcmd ... sudo [malicious options here] to cause sudo to > run with CET off and then try to exploit it via the malicious options. > > If a shutoff is needed for testing, how about teaching ld.so to parse > LD_CET=no or similar and protect it the same way as LD_PRELOAD is > protected. Or just do LD_PRELOAD=/lib/libdoesntsupportcet.so. > I will take a look.
On Thu, Jun 7, 2018 at 3:02 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > > On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > >> > >> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: > >> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > >> > > > >> > > The following operations are provided. > >> > > > >> > > ARCH_CET_STATUS: > >> > > return the current CET status > >> > > > >> > > ARCH_CET_DISABLE: > >> > > disable CET features > >> > > > >> > > ARCH_CET_LOCK: > >> > > lock out CET features > >> > > > >> > > ARCH_CET_EXEC: > >> > > set CET features for exec() > >> > > > >> > > ARCH_CET_ALLOC_SHSTK: > >> > > allocate a new shadow stack > >> > > > >> > > ARCH_CET_PUSH_SHSTK: > >> > > put a return address on shadow stack > >> > > > >> > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for > >> > > the implementation of GLIBC ucontext related APIs. > >> > > >> > Please document exactly what these all do and why. I don't understand > >> > what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for > >> > each ELF program, so I think there should be no need for a magic > >> > override. > >> > >> CET is initially enabled if the loader has CET capability. Then the > >> loader decides if the application can run with CET. If the application > >> cannot run with CET (e.g. a dependent library does not have CET), then > >> the loader turns off CET before passing to the application. When the > >> loader is done, it locks out CET and the feature cannot be turned off > >> anymore until the next exec() call. > > > > Why is the lockout necessary? If user code enables CET and tries to > > run code that doesn't support CET, it will crash. I don't see why we > > need special code in the kernel to prevent a user program from calling > > arch_prctl() and crashing itself. There are already plenty of ways to > > do that :) > > On CET enabled machine, not all programs nor shared libraries are > CET enabled. But since ld.so is CET enabled, all programs start > as CET enabled. ld.so will disable CET if a program or any of its shared > libraries aren't CET enabled. ld.so will lock up CET once it is done CET > checking so that CET can't no longer be disabled afterwards. Yeah, I got that. No one has explained *why*. (Also, shouldn't the vDSO itself be marked as supporting CET?)
On Thu, Jun 7, 2018 at 4:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > On Thu, Jun 7, 2018 at 3:02 PM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> > On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> >> >> >> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: >> >> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> >> > > >> >> > > The following operations are provided. >> >> > > >> >> > > ARCH_CET_STATUS: >> >> > > return the current CET status >> >> > > >> >> > > ARCH_CET_DISABLE: >> >> > > disable CET features >> >> > > >> >> > > ARCH_CET_LOCK: >> >> > > lock out CET features >> >> > > >> >> > > ARCH_CET_EXEC: >> >> > > set CET features for exec() >> >> > > >> >> > > ARCH_CET_ALLOC_SHSTK: >> >> > > allocate a new shadow stack >> >> > > >> >> > > ARCH_CET_PUSH_SHSTK: >> >> > > put a return address on shadow stack >> >> > > >> >> > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for >> >> > > the implementation of GLIBC ucontext related APIs. >> >> > >> >> > Please document exactly what these all do and why. I don't understand >> >> > what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for >> >> > each ELF program, so I think there should be no need for a magic >> >> > override. >> >> >> >> CET is initially enabled if the loader has CET capability. Then the >> >> loader decides if the application can run with CET. If the application >> >> cannot run with CET (e.g. a dependent library does not have CET), then >> >> the loader turns off CET before passing to the application. When the >> >> loader is done, it locks out CET and the feature cannot be turned off >> >> anymore until the next exec() call. >> > >> > Why is the lockout necessary? If user code enables CET and tries to >> > run code that doesn't support CET, it will crash. I don't see why we >> > need special code in the kernel to prevent a user program from calling >> > arch_prctl() and crashing itself. There are already plenty of ways to >> > do that :) >> >> On CET enabled machine, not all programs nor shared libraries are >> CET enabled. But since ld.so is CET enabled, all programs start >> as CET enabled. ld.so will disable CET if a program or any of its shared >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET >> checking so that CET can't no longer be disabled afterwards. > > Yeah, I got that. No one has explained *why*. It is to prevent malicious code from disabling CET. > (Also, shouldn't the vDSO itself be marked as supporting CET?) No. vDSO is loaded by kernel. vDSO in CET kernel is CET compatible.
On Thu, Jun 7, 2018 at 3:02 PM, H.J. Lu <hjl.tools@gmail.com> wrote: > On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >>> >>> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: >>> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >>> > > >>> > > The following operations are provided. >>> > > >>> > > ARCH_CET_STATUS: >>> > > return the current CET status >>> > > >>> > > ARCH_CET_DISABLE: >>> > > disable CET features >>> > > >>> > > ARCH_CET_LOCK: >>> > > lock out CET features >>> > > >>> > > ARCH_CET_EXEC: >>> > > set CET features for exec() >>> > > >>> > > ARCH_CET_ALLOC_SHSTK: >>> > > allocate a new shadow stack >>> > > >>> > > ARCH_CET_PUSH_SHSTK: >>> > > put a return address on shadow stack >>> > > >> And why do we need ARCH_CET_EXEC? >> >> For background, I really really dislike adding new state that persists >> across exec(). It's nice to get as close to a clean slate as possible >> after exec() so that programs can run in a predictable environment. >> exec() is also a security boundary, and anything a task can do to >> affect itself after exec() needs to have its security implications >> considered very carefully. (As a trivial example, you should not be >> able to use cetcmd ... sudo [malicious options here] to cause sudo to >> run with CET off and then try to exploit it via the malicious options. >> >> If a shutoff is needed for testing, how about teaching ld.so to parse >> LD_CET=no or similar and protect it the same way as LD_PRELOAD is >> protected. Or just do LD_PRELOAD=/lib/libdoesntsupportcet.so. >> > > I will take a look. We can use LD_CET to turn off CET. Since most of legacy binaries are compatible with shadow stack, ARCH_CET_EXEC can be used to turn on shadow stack on legacy binaries: [hjl@gnu-cet-1 glibc]$ readelf -n /bin/ls| head -10 Displaying notes found in: .note.ABI-tag Owner Data size Description GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag) OS: Linux, ABI: 3.2.0 Displaying notes found in: .note.gnu.property Owner Data size Description GNU 0x00000020 NT_GNU_PROPERTY_TYPE_0 Properties: x86 ISA used: [hjl@gnu-cet-1 glibc]$ cetcmd --on -- /bin/ls / Segmentation fault [hjl@gnu-cet-1 glibc]$ cetcmd --on -f shstk -- /bin/ls / bin dev export lib libx32 media mnt opt root sbin sys usr boot etc home lib64 lost+found misc net proc run srv tmp var [hjl@gnu-cet-1 glibc]$ cetcmd --on -f ibt -- /bin/ls / Segmentation fault [hjl@gnu-cet-1 glibc]$
On Thu, Jun 7, 2018 at 9:22 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Thu, Jun 7, 2018 at 3:02 PM, H.J. Lu <hjl.tools@gmail.com> wrote: > > On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > >> On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > >>> > >>> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: > >>> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > >>> > > > >>> > > The following operations are provided. > >>> > > > >>> > > ARCH_CET_STATUS: > >>> > > return the current CET status > >>> > > > >>> > > ARCH_CET_DISABLE: > >>> > > disable CET features > >>> > > > >>> > > ARCH_CET_LOCK: > >>> > > lock out CET features > >>> > > > >>> > > ARCH_CET_EXEC: > >>> > > set CET features for exec() > >>> > > > >>> > > ARCH_CET_ALLOC_SHSTK: > >>> > > allocate a new shadow stack > >>> > > > >>> > > ARCH_CET_PUSH_SHSTK: > >>> > > put a return address on shadow stack > >>> > > > > >> And why do we need ARCH_CET_EXEC? > >> > >> For background, I really really dislike adding new state that persists > >> across exec(). It's nice to get as close to a clean slate as possible > >> after exec() so that programs can run in a predictable environment. > >> exec() is also a security boundary, and anything a task can do to > >> affect itself after exec() needs to have its security implications > >> considered very carefully. (As a trivial example, you should not be > >> able to use cetcmd ... sudo [malicious options here] to cause sudo to > >> run with CET off and then try to exploit it via the malicious options. > >> > >> If a shutoff is needed for testing, how about teaching ld.so to parse > >> LD_CET=no or similar and protect it the same way as LD_PRELOAD is > >> protected. Or just do LD_PRELOAD=/lib/libdoesntsupportcet.so. > >> > > > > I will take a look. > > We can use LD_CET to turn off CET. Since most of legacy binaries > are compatible with shadow stack, ARCH_CET_EXEC can be used > to turn on shadow stack on legacy binaries: Is there any reason you can't use LD_CET=force to do it for dynamically linked binaries? I find it quite hard to believe that forcibly CET-ifying a legacy statically linked binary is a good idea.
On Thu, Jun 7, 2018 at 9:10 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Thu, Jun 7, 2018 at 4:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > > On Thu, Jun 7, 2018 at 3:02 PM H.J. Lu <hjl.tools@gmail.com> wrote: > >> > >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > >> > On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > >> >> > >> >> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: > >> >> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > >> >> > > > >> >> > > The following operations are provided. > >> >> > > > >> >> > > ARCH_CET_STATUS: > >> >> > > return the current CET status > >> >> > > > >> >> > > ARCH_CET_DISABLE: > >> >> > > disable CET features > >> >> > > > >> >> > > ARCH_CET_LOCK: > >> >> > > lock out CET features > >> >> > > > >> >> > > ARCH_CET_EXEC: > >> >> > > set CET features for exec() > >> >> > > > >> >> > > ARCH_CET_ALLOC_SHSTK: > >> >> > > allocate a new shadow stack > >> >> > > > >> >> > > ARCH_CET_PUSH_SHSTK: > >> >> > > put a return address on shadow stack > >> >> > > > >> >> > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for > >> >> > > the implementation of GLIBC ucontext related APIs. > >> >> > > >> >> > Please document exactly what these all do and why. I don't understand > >> >> > what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for > >> >> > each ELF program, so I think there should be no need for a magic > >> >> > override. > >> >> > >> >> CET is initially enabled if the loader has CET capability. Then the > >> >> loader decides if the application can run with CET. If the application > >> >> cannot run with CET (e.g. a dependent library does not have CET), then > >> >> the loader turns off CET before passing to the application. When the > >> >> loader is done, it locks out CET and the feature cannot be turned off > >> >> anymore until the next exec() call. > >> > > >> > Why is the lockout necessary? If user code enables CET and tries to > >> > run code that doesn't support CET, it will crash. I don't see why we > >> > need special code in the kernel to prevent a user program from calling > >> > arch_prctl() and crashing itself. There are already plenty of ways to > >> > do that :) > >> > >> On CET enabled machine, not all programs nor shared libraries are > >> CET enabled. But since ld.so is CET enabled, all programs start > >> as CET enabled. ld.so will disable CET if a program or any of its shared > >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET > >> checking so that CET can't no longer be disabled afterwards. > > > > Yeah, I got that. No one has explained *why*. > > It is to prevent malicious code from disabling CET. > By the time malicious code issue its own syscalls, you've already lost the battle. I could probably be convinced that a lock-CET-on feature that applies *only* to the calling thread and is not inherited by clone() is a decent idea, but I'd want to see someone who understands the state of the art in exploit design justify it. You're also going to need to figure out how to make CRIU work if you allow locking CET on. A priori, I think we should just not provide a lock mechanism. > > (Also, shouldn't the vDSO itself be marked as supporting CET?) > > No. vDSO is loaded by kernel. vDSO in CET kernel is CET > compatible. > I think the vDSO should do its best to act like a real DSO. That means that, if the vDSO supports CET, it should advertise support for CET using the Linux ABI. Since you're going to require GCC 8 anyway, this should be a single line of code in the Makefile.
On Thu, Jun 7, 2018 at 9:35 PM, Andy Lutomirski <luto@kernel.org> wrote: > On Thu, Jun 7, 2018 at 9:22 PM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> On Thu, Jun 7, 2018 at 3:02 PM, H.J. Lu <hjl.tools@gmail.com> wrote: >> > On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> >> On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> >>> >> >>> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: >> >>> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> >>> > > >> >>> > > The following operations are provided. >> >>> > > >> >>> > > ARCH_CET_STATUS: >> >>> > > return the current CET status >> >>> > > >> >>> > > ARCH_CET_DISABLE: >> >>> > > disable CET features >> >>> > > >> >>> > > ARCH_CET_LOCK: >> >>> > > lock out CET features >> >>> > > >> >>> > > ARCH_CET_EXEC: >> >>> > > set CET features for exec() >> >>> > > >> >>> > > ARCH_CET_ALLOC_SHSTK: >> >>> > > allocate a new shadow stack >> >>> > > >> >>> > > ARCH_CET_PUSH_SHSTK: >> >>> > > put a return address on shadow stack >> >>> > > >> >> >> And why do we need ARCH_CET_EXEC? >> >> >> >> For background, I really really dislike adding new state that persists >> >> across exec(). It's nice to get as close to a clean slate as possible >> >> after exec() so that programs can run in a predictable environment. >> >> exec() is also a security boundary, and anything a task can do to >> >> affect itself after exec() needs to have its security implications >> >> considered very carefully. (As a trivial example, you should not be >> >> able to use cetcmd ... sudo [malicious options here] to cause sudo to >> >> run with CET off and then try to exploit it via the malicious options. >> >> >> >> If a shutoff is needed for testing, how about teaching ld.so to parse >> >> LD_CET=no or similar and protect it the same way as LD_PRELOAD is >> >> protected. Or just do LD_PRELOAD=/lib/libdoesntsupportcet.so. >> >> >> > >> > I will take a look. >> >> We can use LD_CET to turn off CET. Since most of legacy binaries >> are compatible with shadow stack, ARCH_CET_EXEC can be used >> to turn on shadow stack on legacy binaries: > > Is there any reason you can't use LD_CET=force to do it for > dynamically linked binaries? We need to enable shadow stack from the start. Otherwise function return will fail when returning from callee with shadow stack to caller without shadow stack. > I find it quite hard to believe that forcibly CET-ifying a legacy > statically linked binary is a good idea. We'd like to provide protection as much as we can.
On Thu, Jun 7, 2018 at 9:38 PM, Andy Lutomirski <luto@kernel.org> wrote: > On Thu, Jun 7, 2018 at 9:10 PM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> On Thu, Jun 7, 2018 at 4:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> > On Thu, Jun 7, 2018 at 3:02 PM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> >> >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> >> > On Thu, Jun 7, 2018 at 1:33 PM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> >> >> >> >> >> On Thu, 2018-06-07 at 11:48 -0700, Andy Lutomirski wrote: >> >> >> > On Thu, Jun 7, 2018 at 7:41 AM Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >> >> >> > > >> >> >> > > The following operations are provided. >> >> >> > > >> >> >> > > ARCH_CET_STATUS: >> >> >> > > return the current CET status >> >> >> > > >> >> >> > > ARCH_CET_DISABLE: >> >> >> > > disable CET features >> >> >> > > >> >> >> > > ARCH_CET_LOCK: >> >> >> > > lock out CET features >> >> >> > > >> >> >> > > ARCH_CET_EXEC: >> >> >> > > set CET features for exec() >> >> >> > > >> >> >> > > ARCH_CET_ALLOC_SHSTK: >> >> >> > > allocate a new shadow stack >> >> >> > > >> >> >> > > ARCH_CET_PUSH_SHSTK: >> >> >> > > put a return address on shadow stack >> >> >> > > >> >> >> > > ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for >> >> >> > > the implementation of GLIBC ucontext related APIs. >> >> >> > >> >> >> > Please document exactly what these all do and why. I don't understand >> >> >> > what purpose ARCH_CET_LOCK and ARCH_CET_EXEC serve. CET is opt in for >> >> >> > each ELF program, so I think there should be no need for a magic >> >> >> > override. >> >> >> >> >> >> CET is initially enabled if the loader has CET capability. Then the >> >> >> loader decides if the application can run with CET. If the application >> >> >> cannot run with CET (e.g. a dependent library does not have CET), then >> >> >> the loader turns off CET before passing to the application. When the >> >> >> loader is done, it locks out CET and the feature cannot be turned off >> >> >> anymore until the next exec() call. >> >> > >> >> > Why is the lockout necessary? If user code enables CET and tries to >> >> > run code that doesn't support CET, it will crash. I don't see why we >> >> > need special code in the kernel to prevent a user program from calling >> >> > arch_prctl() and crashing itself. There are already plenty of ways to >> >> > do that :) >> >> >> >> On CET enabled machine, not all programs nor shared libraries are >> >> CET enabled. But since ld.so is CET enabled, all programs start >> >> as CET enabled. ld.so will disable CET if a program or any of its shared >> >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET >> >> checking so that CET can't no longer be disabled afterwards. >> > >> > Yeah, I got that. No one has explained *why*. >> >> It is to prevent malicious code from disabling CET. >> > > By the time malicious code issue its own syscalls, you've already lost > the battle. I could probably be convinced that a lock-CET-on feature > that applies *only* to the calling thread and is not inherited by > clone() is a decent idea, but I'd want to see someone who understands > the state of the art in exploit design justify it. You're also going > to need to figure out how to make CRIU work if you allow locking CET > on. > > A priori, I think we should just not provide a lock mechanism. We need a door for CET. But it is a very bad idea to leave it open all the time. I don't know much about CRIU, If it is Checkpoint/Restore In Userspace. Can you free any application with AVX512 on AVX512 machine and restore it on non-AVX512 machine? >> > (Also, shouldn't the vDSO itself be marked as supporting CET?) >> >> No. vDSO is loaded by kernel. vDSO in CET kernel is CET >> compatible. >> > > I think the vDSO should do its best to act like a real DSO. That > means that, if the vDSO supports CET, it should advertise support for > CET using the Linux ABI. Since you're going to require GCC 8 anyway, > this should be a single line of code in the Makefile. Sure. A couple lines.
On Fri, Jun 8, 2018 at 5:24 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Thu, Jun 7, 2018 at 9:38 PM, Andy Lutomirski <luto@kernel.org> wrote: > > On Thu, Jun 7, 2018 at 9:10 PM H.J. Lu <hjl.tools@gmail.com> wrote: > >> > >> On Thu, Jun 7, 2018 at 4:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > >> > > > > By the time malicious code issue its own syscalls, you've already lost > > the battle. I could probably be convinced that a lock-CET-on feature > > that applies *only* to the calling thread and is not inherited by > > clone() is a decent idea, but I'd want to see someone who understands > > the state of the art in exploit design justify it. You're also going > > to need to figure out how to make CRIU work if you allow locking CET > > on. > > > > A priori, I think we should just not provide a lock mechanism. > > We need a door for CET. But it is a very bad idea to leave it open > all the time. I don't know much about CRIU, If it is Checkpoint/Restore > In Userspace. Can you free any application with AVX512 on AVX512 > machine and restore it on non-AVX512 machine? Presumably not -- if the program uses AVX512 and AVX512 goes away, then the program won't be happy. Anyway, having thought about this, here's a straw man proposal. We add a lock flag like in these patches. The lock flag is set by arch_prctl(), inherited on clone, and cleared on exec(). ptrace() gains a new API to clear the lock flag and can modify the CET configuration regardless of the lock flag. (So ptrace() needs APIs to read and write SSP, to read and write the shadow stack itself, and to change the mode.) By the time an attacker has gotten enough control of a victim process to get it to use ptrace(), I don't think that trying to protect CET serves any purpose. As an aside, where are the latest CET docs? I've found the "CET technology preview 2.0", but it doesn't seem to be very clear or entirely complete. On Fri, Jun 8, 2018 at 5:17 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Thu, Jun 7, 2018 at 9:35 PM, Andy Lutomirski <luto@kernel.org> wrote: > > Is there any reason you can't use LD_CET=force to do it for > > dynamically linked binaries? > > We need to enable shadow stack from the start. Otherwise function > return will fail when returning from callee with shadow stack to caller > without shadow stack. I don't see the problem. A CET-supporting ld.so will be started with CET on regardless of what the final binary says. If ld.so sees LD_CET=force, it can keep CET on regardless of the flags in the loaded binary. > > > I find it quite hard to believe that forcibly CET-ifying a legacy > > statically linked binary is a good idea. > > We'd like to provide protection as much as we can. > I agree that this is a nice sentiment, but I don't think that a simple "force CET on next exec()" flag is a good way to accomplish this. I've had the pleasure of using legacy binaries, and there are all kinds of gotchas. First, a bunch of them aren't binaries at all -- they're shell scripts. There's big_expensive_program that starts with #!/bin/bash and eventually execs /opt/blahblahblah/big_expensive_program_bin, and that involves two execs. (Heck, even Firefox is set up more or less like this.) Some programs can re-exec themselves. All of this is not to mention that it would be really annoying when your program crashes after you've been using it for hours because you finally triggered the code path that did longjmp() and CET kills it. And you don't really need kernel support for this anyway. It should be relatively straightforward to write a loader that opens and loads a static binary. I think that this entire CET-on-exec concept should be dropped from this patch series. If someone really wants it, make it a separate patch on top after everything has been merged, and we can poke holes in it them.
On Fri, Jun 08, 2018 at 07:57:22AM -0700, Andy Lutomirski wrote: > On Fri, Jun 8, 2018 at 5:24 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > On Thu, Jun 7, 2018 at 9:38 PM, Andy Lutomirski <luto@kernel.org> wrote: > > > On Thu, Jun 7, 2018 at 9:10 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > >> > > >> On Thu, Jun 7, 2018 at 4:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > > >> > > > > > > By the time malicious code issue its own syscalls, you've already lost > > > the battle. I could probably be convinced that a lock-CET-on feature > > > that applies *only* to the calling thread and is not inherited by > > > clone() is a decent idea, but I'd want to see someone who understands > > > the state of the art in exploit design justify it. You're also going > > > to need to figure out how to make CRIU work if you allow locking CET > > > on. > > > > > > A priori, I think we should just not provide a lock mechanism. > > > > We need a door for CET. But it is a very bad idea to leave it open > > all the time. I don't know much about CRIU, If it is Checkpoint/Restore > > In Userspace. Can you free any application with AVX512 on AVX512 > > machine and restore it on non-AVX512 machine? > > Presumably not -- if the program uses AVX512 and AVX512 goes away, > then the program won't be happy. Yes. In most scenarios we require the fpu capability to be the same on both machines (in case of migration) or/and not being changed between c/r cycles. ... > As an aside, where are the latest CET docs? I've found the "CET > technology preview 2.0", but it doesn't seem to be very clear or > entirely complete. +1
On Thu, 7 Jun 2018, H.J. Lu wrote: > On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > > Why is the lockout necessary? If user code enables CET and tries to > > run code that doesn't support CET, it will crash. I don't see why we > > need special code in the kernel to prevent a user program from calling > > arch_prctl() and crashing itself. There are already plenty of ways to > > do that :) > > On CET enabled machine, not all programs nor shared libraries are > CET enabled. But since ld.so is CET enabled, all programs start > as CET enabled. ld.so will disable CET if a program or any of its shared > libraries aren't CET enabled. ld.so will lock up CET once it is done CET > checking so that CET can't no longer be disabled afterwards. That works for stuff which loads all libraries at start time, but what happens if the program uses dlopen() later on? If CET is force locked and the library is not CET enabled, it will fail. I don't see the point of trying to support CET by magic. It adds complexity and you'll never be able to handle all corner cases correctly. dlopen() is not even a corner case. Occasionally stuff needs to be recompiled to utilize new mechanisms, see retpoline ... Thanks, tglx
On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: > On Thu, 7 Jun 2018, H.J. Lu wrote: >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> > Why is the lockout necessary? If user code enables CET and tries to >> > run code that doesn't support CET, it will crash. I don't see why we >> > need special code in the kernel to prevent a user program from calling >> > arch_prctl() and crashing itself. There are already plenty of ways to >> > do that :) >> >> On CET enabled machine, not all programs nor shared libraries are >> CET enabled. But since ld.so is CET enabled, all programs start >> as CET enabled. ld.so will disable CET if a program or any of its shared >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET >> checking so that CET can't no longer be disabled afterwards. > > That works for stuff which loads all libraries at start time, but what > happens if the program uses dlopen() later on? If CET is force locked and > the library is not CET enabled, it will fail. That is to prevent disabling CET by dlopening a legacy shared library. > I don't see the point of trying to support CET by magic. It adds complexity > and you'll never be able to handle all corner cases correctly. dlopen() is > not even a corner case. That is a price we pay for security. To enable CET, especially shadow shack, the program and all of shared libraries it uses should be CET enabled. Most of programs can be enabled with CET by compiling them with -fcf-protection. > Occasionally stuff needs to be recompiled to utilize new mechanisms, see > retpoline ... > > Thanks, > > tglx >
On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: > > On Thu, 7 Jun 2018, H.J. Lu wrote: > >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > >> > Why is the lockout necessary? If user code enables CET and tries to > >> > run code that doesn't support CET, it will crash. I don't see why we > >> > need special code in the kernel to prevent a user program from calling > >> > arch_prctl() and crashing itself. There are already plenty of ways to > >> > do that :) > >> > >> On CET enabled machine, not all programs nor shared libraries are > >> CET enabled. But since ld.so is CET enabled, all programs start > >> as CET enabled. ld.so will disable CET if a program or any of its shared > >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET > >> checking so that CET can't no longer be disabled afterwards. > > > > That works for stuff which loads all libraries at start time, but what > > happens if the program uses dlopen() later on? If CET is force locked and > > the library is not CET enabled, it will fail. > > That is to prevent disabling CET by dlopening a legacy shared library. > > > I don't see the point of trying to support CET by magic. It adds complexity > > and you'll never be able to handle all corner cases correctly. dlopen() is > > not even a corner case. > > That is a price we pay for security. To enable CET, especially shadow > shack, the program and all of shared libraries it uses should be CET > enabled. Most of programs can be enabled with CET by compiling them > with -fcf-protection. If you charge too high a price for security, people may turn it off. I think we're going to need a mode where a program says "I want to use the CET, but turn it off if I dlopen an unsupported library". There are programs that load binary-only plugins.
On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: > On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: >> > On Thu, 7 Jun 2018, H.J. Lu wrote: >> >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> >> > Why is the lockout necessary? If user code enables CET and tries to >> >> > run code that doesn't support CET, it will crash. I don't see why we >> >> > need special code in the kernel to prevent a user program from calling >> >> > arch_prctl() and crashing itself. There are already plenty of ways to >> >> > do that :) >> >> >> >> On CET enabled machine, not all programs nor shared libraries are >> >> CET enabled. But since ld.so is CET enabled, all programs start >> >> as CET enabled. ld.so will disable CET if a program or any of its shared >> >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET >> >> checking so that CET can't no longer be disabled afterwards. >> > >> > That works for stuff which loads all libraries at start time, but what >> > happens if the program uses dlopen() later on? If CET is force locked and >> > the library is not CET enabled, it will fail. >> >> That is to prevent disabling CET by dlopening a legacy shared library. >> >> > I don't see the point of trying to support CET by magic. It adds complexity >> > and you'll never be able to handle all corner cases correctly. dlopen() is >> > not even a corner case. >> >> That is a price we pay for security. To enable CET, especially shadow >> shack, the program and all of shared libraries it uses should be CET >> enabled. Most of programs can be enabled with CET by compiling them >> with -fcf-protection. > > If you charge too high a price for security, people may turn it off. > I think we're going to need a mode where a program says "I want to use > the CET, but turn it off if I dlopen an unsupported library". There > are programs that load binary-only plugins. You can do # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK which turns off shadow stack.
On Tue, Jun 12, 2018 at 9:05 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: > > On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: > >> > >> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: > >> > On Thu, 7 Jun 2018, H.J. Lu wrote: > >> >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: > >> >> > Why is the lockout necessary? If user code enables CET and tries to > >> >> > run code that doesn't support CET, it will crash. I don't see why we > >> >> > need special code in the kernel to prevent a user program from calling > >> >> > arch_prctl() and crashing itself. There are already plenty of ways to > >> >> > do that :) > >> >> > >> >> On CET enabled machine, not all programs nor shared libraries are > >> >> CET enabled. But since ld.so is CET enabled, all programs start > >> >> as CET enabled. ld.so will disable CET if a program or any of its shared > >> >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET > >> >> checking so that CET can't no longer be disabled afterwards. > >> > > >> > That works for stuff which loads all libraries at start time, but what > >> > happens if the program uses dlopen() later on? If CET is force locked and > >> > the library is not CET enabled, it will fail. > >> > >> That is to prevent disabling CET by dlopening a legacy shared library. > >> > >> > I don't see the point of trying to support CET by magic. It adds complexity > >> > and you'll never be able to handle all corner cases correctly. dlopen() is > >> > not even a corner case. > >> > >> That is a price we pay for security. To enable CET, especially shadow > >> shack, the program and all of shared libraries it uses should be CET > >> enabled. Most of programs can be enabled with CET by compiling them > >> with -fcf-protection. > > > > If you charge too high a price for security, people may turn it off. > > I think we're going to need a mode where a program says "I want to use > > the CET, but turn it off if I dlopen an unsupported library". There > > are programs that load binary-only plugins. > > You can do > > # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK > > which turns off shadow stack. > Which exactly illustrates my point. By making your security story too absolute, you'll force people to turn it off when they don't need to. If I'm using a fully CET-ified distro and I'm using a CET-aware program that loads binary plugins, and I may or may not have an old (binary-only, perhaps) plugin that doesn't support CET, then the behavior I want is for CET to be on until I dlopen() a program that doesn't support it. Unless there's some ABI reason why that can't be done, but I don't think there is. I'm concerned that the entire concept of locking CET is there to solve a security problem that doesn't actually exist.
On Tue, Jun 12, 2018 at 9:34 AM, Andy Lutomirski <luto@kernel.org> wrote: > On Tue, Jun 12, 2018 at 9:05 AM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: >> > On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> >> >> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: >> >> > On Thu, 7 Jun 2018, H.J. Lu wrote: >> >> >> On Thu, Jun 7, 2018 at 2:01 PM, Andy Lutomirski <luto@kernel.org> wrote: >> >> >> > Why is the lockout necessary? If user code enables CET and tries to >> >> >> > run code that doesn't support CET, it will crash. I don't see why we >> >> >> > need special code in the kernel to prevent a user program from calling >> >> >> > arch_prctl() and crashing itself. There are already plenty of ways to >> >> >> > do that :) >> >> >> >> >> >> On CET enabled machine, not all programs nor shared libraries are >> >> >> CET enabled. But since ld.so is CET enabled, all programs start >> >> >> as CET enabled. ld.so will disable CET if a program or any of its shared >> >> >> libraries aren't CET enabled. ld.so will lock up CET once it is done CET >> >> >> checking so that CET can't no longer be disabled afterwards. >> >> > >> >> > That works for stuff which loads all libraries at start time, but what >> >> > happens if the program uses dlopen() later on? If CET is force locked and >> >> > the library is not CET enabled, it will fail. >> >> >> >> That is to prevent disabling CET by dlopening a legacy shared library. >> >> >> >> > I don't see the point of trying to support CET by magic. It adds complexity >> >> > and you'll never be able to handle all corner cases correctly. dlopen() is >> >> > not even a corner case. >> >> >> >> That is a price we pay for security. To enable CET, especially shadow >> >> shack, the program and all of shared libraries it uses should be CET >> >> enabled. Most of programs can be enabled with CET by compiling them >> >> with -fcf-protection. >> > >> > If you charge too high a price for security, people may turn it off. >> > I think we're going to need a mode where a program says "I want to use >> > the CET, but turn it off if I dlopen an unsupported library". There >> > are programs that load binary-only plugins. >> >> You can do >> >> # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK >> >> which turns off shadow stack. >> > > Which exactly illustrates my point. By making your security story too > absolute, you'll force people to turn it off when they don't need to. > If I'm using a fully CET-ified distro and I'm using a CET-aware > program that loads binary plugins, and I may or may not have an old > (binary-only, perhaps) plugin that doesn't support CET, then the > behavior I want is for CET to be on until I dlopen() a program that > doesn't support it. Unless there's some ABI reason why that can't be > done, but I don't think there is. We can make it opt-in via GLIBC_TUNABLES. But by default, the legacy shared object is disallowed when CET is enabled. > I'm concerned that the entire concept of locking CET is there to solve > a security problem that doesn't actually exist. We don't know that.
On Tue, 12 Jun 2018, H.J. Lu wrote: > On Tue, Jun 12, 2018 at 9:34 AM, Andy Lutomirski <luto@kernel.org> wrote: > > On Tue, Jun 12, 2018 at 9:05 AM H.J. Lu <hjl.tools@gmail.com> wrote: > >> On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: > >> > On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: > >> >> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: > >> >> > That works for stuff which loads all libraries at start time, but what > >> >> > happens if the program uses dlopen() later on? If CET is force locked and > >> >> > the library is not CET enabled, it will fail. > >> >> > >> >> That is to prevent disabling CET by dlopening a legacy shared library. > >> >> > >> >> > I don't see the point of trying to support CET by magic. It adds complexity > >> >> > and you'll never be able to handle all corner cases correctly. dlopen() is > >> >> > not even a corner case. > >> >> > >> >> That is a price we pay for security. To enable CET, especially shadow > >> >> shack, the program and all of shared libraries it uses should be CET > >> >> enabled. Most of programs can be enabled with CET by compiling them > >> >> with -fcf-protection. > >> > > >> > If you charge too high a price for security, people may turn it off. > >> > I think we're going to need a mode where a program says "I want to use > >> > the CET, but turn it off if I dlopen an unsupported library". There > >> > are programs that load binary-only plugins. > >> > >> You can do > >> > >> # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK > >> > >> which turns off shadow stack. > >> > > > > Which exactly illustrates my point. By making your security story too > > absolute, you'll force people to turn it off when they don't need to. > > If I'm using a fully CET-ified distro and I'm using a CET-aware > > program that loads binary plugins, and I may or may not have an old > > (binary-only, perhaps) plugin that doesn't support CET, then the > > behavior I want is for CET to be on until I dlopen() a program that > > doesn't support it. Unless there's some ABI reason why that can't be > > done, but I don't think there is. > > We can make it opt-in via GLIBC_TUNABLES. But by default, the legacy > shared object is disallowed when CET is enabled. That's a bad idea. Stuff has launchers which people might not be able to change. So they will simply turn of CET completely or it makes them hack horrible crap into init, e.g. the above export. Give them sane kernel options: cet = off, relaxed, forced where relaxed allows to run binary plugins. Then let dlopen() call into the kernel with the filepath of the library to check for CET and that will tell you whether its ok or or not and do the necessary magic in the kernel when CET has to be disabled due to a !CET library/application. That's also making the whole thing independent of magic glibc environment options and allows it to be used all over the place in the same way. Thanks, tglx
On Tue, Jun 12, 2018 at 11:59 AM, Thomas Gleixner <tglx@linutronix.de> wrote: > On Tue, 12 Jun 2018, H.J. Lu wrote: >> On Tue, Jun 12, 2018 at 9:34 AM, Andy Lutomirski <luto@kernel.org> wrote: >> > On Tue, Jun 12, 2018 at 9:05 AM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: >> >> > On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> >> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: >> >> >> > That works for stuff which loads all libraries at start time, but what >> >> >> > happens if the program uses dlopen() later on? If CET is force locked and >> >> >> > the library is not CET enabled, it will fail. >> >> >> >> >> >> That is to prevent disabling CET by dlopening a legacy shared library. >> >> >> >> >> >> > I don't see the point of trying to support CET by magic. It adds complexity >> >> >> > and you'll never be able to handle all corner cases correctly. dlopen() is >> >> >> > not even a corner case. >> >> >> >> >> >> That is a price we pay for security. To enable CET, especially shadow >> >> >> shack, the program and all of shared libraries it uses should be CET >> >> >> enabled. Most of programs can be enabled with CET by compiling them >> >> >> with -fcf-protection. >> >> > >> >> > If you charge too high a price for security, people may turn it off. >> >> > I think we're going to need a mode where a program says "I want to use >> >> > the CET, but turn it off if I dlopen an unsupported library". There >> >> > are programs that load binary-only plugins. >> >> >> >> You can do >> >> >> >> # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK >> >> >> >> which turns off shadow stack. >> >> >> > >> > Which exactly illustrates my point. By making your security story too >> > absolute, you'll force people to turn it off when they don't need to. >> > If I'm using a fully CET-ified distro and I'm using a CET-aware >> > program that loads binary plugins, and I may or may not have an old >> > (binary-only, perhaps) plugin that doesn't support CET, then the >> > behavior I want is for CET to be on until I dlopen() a program that >> > doesn't support it. Unless there's some ABI reason why that can't be >> > done, but I don't think there is. >> >> We can make it opt-in via GLIBC_TUNABLES. But by default, the legacy >> shared object is disallowed when CET is enabled. > > That's a bad idea. Stuff has launchers which people might not be able to > change. So they will simply turn of CET completely or it makes them hack > horrible crap into init, e.g. the above export. > > Give them sane kernel options: > > cet = off, relaxed, forced > > where relaxed allows to run binary plugins. Then let dlopen() call into the > kernel with the filepath of the library to check for CET and that will tell > you whether its ok or or not and do the necessary magic in the kernel when > CET has to be disabled due to a !CET library/application. > > That's also making the whole thing independent of magic glibc environment > options and allows it to be used all over the place in the same way. This is very similar to our ARCH_CET_EXEC proposal which controls how CET should be enforced. But Andy thinks it is a bad idea.
On Tue, Jun 12, 2018 at 12:34 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Tue, Jun 12, 2018 at 11:59 AM, Thomas Gleixner <tglx@linutronix.de> wrote: > > On Tue, 12 Jun 2018, H.J. Lu wrote: > >> On Tue, Jun 12, 2018 at 9:34 AM, Andy Lutomirski <luto@kernel.org> wrote: > >> > On Tue, Jun 12, 2018 at 9:05 AM H.J. Lu <hjl.tools@gmail.com> wrote: > >> >> On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: > >> >> > On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: > >> >> >> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: > >> >> >> > That works for stuff which loads all libraries at start time, but what > >> >> >> > happens if the program uses dlopen() later on? If CET is force locked and > >> >> >> > the library is not CET enabled, it will fail. > >> >> >> > >> >> >> That is to prevent disabling CET by dlopening a legacy shared library. > >> >> >> > >> >> >> > I don't see the point of trying to support CET by magic. It adds complexity > >> >> >> > and you'll never be able to handle all corner cases correctly. dlopen() is > >> >> >> > not even a corner case. > >> >> >> > >> >> >> That is a price we pay for security. To enable CET, especially shadow > >> >> >> shack, the program and all of shared libraries it uses should be CET > >> >> >> enabled. Most of programs can be enabled with CET by compiling them > >> >> >> with -fcf-protection. > >> >> > > >> >> > If you charge too high a price for security, people may turn it off. > >> >> > I think we're going to need a mode where a program says "I want to use > >> >> > the CET, but turn it off if I dlopen an unsupported library". There > >> >> > are programs that load binary-only plugins. > >> >> > >> >> You can do > >> >> > >> >> # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK > >> >> > >> >> which turns off shadow stack. > >> >> > >> > > >> > Which exactly illustrates my point. By making your security story too > >> > absolute, you'll force people to turn it off when they don't need to. > >> > If I'm using a fully CET-ified distro and I'm using a CET-aware > >> > program that loads binary plugins, and I may or may not have an old > >> > (binary-only, perhaps) plugin that doesn't support CET, then the > >> > behavior I want is for CET to be on until I dlopen() a program that > >> > doesn't support it. Unless there's some ABI reason why that can't be > >> > done, but I don't think there is. > >> > >> We can make it opt-in via GLIBC_TUNABLES. But by default, the legacy > >> shared object is disallowed when CET is enabled. > > > > That's a bad idea. Stuff has launchers which people might not be able to > > change. So they will simply turn of CET completely or it makes them hack > > horrible crap into init, e.g. the above export. > > > > Give them sane kernel options: > > > > cet = off, relaxed, forced > > > > where relaxed allows to run binary plugins. Then let dlopen() call into the > > kernel with the filepath of the library to check for CET and that will tell > > you whether its ok or or not and do the necessary magic in the kernel when > > CET has to be disabled due to a !CET library/application. > > > > That's also making the whole thing independent of magic glibc environment > > options and allows it to be used all over the place in the same way. > > This is very similar to our ARCH_CET_EXEC proposal which controls how > CET should be enforced. But Andy thinks it is a bad idea. > I do think it's a bad idea to have a new piece of state that survives across exec(). It's going to have nasty usability problems and nasty security problems. We may need a mode by which glibc can turn CET *back off* even after a program had it on if it dlopens() an old binary. Or maybe there won't be demand. I can certainly understand why the CET_LOCK feature is there, although I think we need a way to override it using something like ptrace(). I'm not convinced that CET_LOCK is really needed, but someone who understand the thread model should chime in. Kees, do you know anyone who has a good enough understanding of usermode exploits and how they'll interact with CET? --Andy
On Mon, Jun 18, 2018 at 3:03 PM, Andy Lutomirski <luto@kernel.org> wrote: > On Tue, Jun 12, 2018 at 12:34 PM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> On Tue, Jun 12, 2018 at 11:59 AM, Thomas Gleixner <tglx@linutronix.de> wrote: >> > On Tue, 12 Jun 2018, H.J. Lu wrote: >> >> On Tue, Jun 12, 2018 at 9:34 AM, Andy Lutomirski <luto@kernel.org> wrote: >> >> > On Tue, Jun 12, 2018 at 9:05 AM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> >> On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: >> >> >> > On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: >> >> >> >> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: >> >> >> >> > That works for stuff which loads all libraries at start time, but what >> >> >> >> > happens if the program uses dlopen() later on? If CET is force locked and >> >> >> >> > the library is not CET enabled, it will fail. >> >> >> >> >> >> >> >> That is to prevent disabling CET by dlopening a legacy shared library. >> >> >> >> >> >> >> >> > I don't see the point of trying to support CET by magic. It adds complexity >> >> >> >> > and you'll never be able to handle all corner cases correctly. dlopen() is >> >> >> >> > not even a corner case. >> >> >> >> >> >> >> >> That is a price we pay for security. To enable CET, especially shadow >> >> >> >> shack, the program and all of shared libraries it uses should be CET >> >> >> >> enabled. Most of programs can be enabled with CET by compiling them >> >> >> >> with -fcf-protection. >> >> >> > >> >> >> > If you charge too high a price for security, people may turn it off. >> >> >> > I think we're going to need a mode where a program says "I want to use >> >> >> > the CET, but turn it off if I dlopen an unsupported library". There >> >> >> > are programs that load binary-only plugins. >> >> >> >> >> >> You can do >> >> >> >> >> >> # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK >> >> >> >> >> >> which turns off shadow stack. >> >> >> >> >> > >> >> > Which exactly illustrates my point. By making your security story too >> >> > absolute, you'll force people to turn it off when they don't need to. >> >> > If I'm using a fully CET-ified distro and I'm using a CET-aware >> >> > program that loads binary plugins, and I may or may not have an old >> >> > (binary-only, perhaps) plugin that doesn't support CET, then the >> >> > behavior I want is for CET to be on until I dlopen() a program that >> >> > doesn't support it. Unless there's some ABI reason why that can't be >> >> > done, but I don't think there is. >> >> >> >> We can make it opt-in via GLIBC_TUNABLES. But by default, the legacy >> >> shared object is disallowed when CET is enabled. >> > >> > That's a bad idea. Stuff has launchers which people might not be able to >> > change. So they will simply turn of CET completely or it makes them hack >> > horrible crap into init, e.g. the above export. >> > >> > Give them sane kernel options: >> > >> > cet = off, relaxed, forced >> > >> > where relaxed allows to run binary plugins. Then let dlopen() call into the >> > kernel with the filepath of the library to check for CET and that will tell >> > you whether its ok or or not and do the necessary magic in the kernel when >> > CET has to be disabled due to a !CET library/application. >> > >> > That's also making the whole thing independent of magic glibc environment >> > options and allows it to be used all over the place in the same way. >> >> This is very similar to our ARCH_CET_EXEC proposal which controls how >> CET should be enforced. But Andy thinks it is a bad idea. > > I do think it's a bad idea to have a new piece of state that survives > across exec(). It's going to have nasty usability problems and nasty > security problems. > > We may need a mode by which glibc can turn CET *back off* even after a > program had it on if it dlopens() an old binary. Or maybe there won't > be demand. I can certainly understand why the CET_LOCK feature is > there, although I think we need a way to override it using something > like ptrace(). I'm not convinced that CET_LOCK is really needed, but > someone who understand the thread model should chime in. > > Kees, do you know anyone who has a good enough understanding of > usermode exploits and how they'll interact with CET? Adding Florian to CC, but if something gets CET enabled, it really shouldn't have a way to turn it off. If there's a way to turn it off, all the ROP research will suddenly turn to exactly one gadget before doing the rest of the ROP: turning off CET. Right now ROP is: use stack-pivot gadget, do everything else. Allowed CET to turn off will just add one step: use CET-off gadget, use stack-pivot gadget, do everything else. :P Following Linus's request for "slow introduction" of new security features, likely the best approach is to default to "relaxed" (with a warning about down-grades), and allow distros/end-users to pick "forced" if they know their libraries are all CET-enabled. -Kees
On 06/19/2018 02:52 AM, Kees Cook wrote: > Adding Florian to CC, but if something gets CET enabled, it really > shouldn't have a way to turn it off. If there's a way to turn it off, > all the ROP research will suddenly turn to exactly one gadget before > doing the rest of the ROP: turning off CET. Right now ROP is: use > stack-pivot gadget, do everything else. Allowed CET to turn off will > just add one step: use CET-off gadget, use stack-pivot gadget, do > everything else. :P > > Following Linus's request for "slow introduction" of new security > features, likely the best approach is to default to "relaxed" (with a > warning about down-grades), and allow distros/end-users to pick > "forced" if they know their libraries are all CET-enabled. The dynamic linker can tell beforehand (before executing any user code) whether a process image supports CET. So there doesn't have to be anything gradual about it per se to preserve backwards compatibility. The idea to turn off CET probably comes from the desire to support dlopen. I'm not sure if this is really necessary because the complexity is rather nasty. (We currently do something similar for executable stacks.) I'd rather have a switch to turn off the feature upon process start. Things like NSS and PAM modules need to be recompiled early. (I hope that everything that goes directly to the network via custom protocols or hardware such as smartcards is proxied via daemons these days.) Thanks, Florian
> On Jun 18, 2018, at 5:52 PM, Kees Cook <keescook@chromium.org> wrote: > >> On Mon, Jun 18, 2018 at 3:03 PM, Andy Lutomirski <luto@kernel.org> wrote: >>> On Tue, Jun 12, 2018 at 12:34 PM H.J. Lu <hjl.tools@gmail.com> wrote: >>> >>>> On Tue, Jun 12, 2018 at 11:59 AM, Thomas Gleixner <tglx@linutronix.de> wrote: >>>>> On Tue, 12 Jun 2018, H.J. Lu wrote: >>>>>> On Tue, Jun 12, 2018 at 9:34 AM, Andy Lutomirski <luto@kernel.org> wrote: >>>>>>> On Tue, Jun 12, 2018 at 9:05 AM H.J. Lu <hjl.tools@gmail.com> wrote: >>>>>>>> On Tue, Jun 12, 2018 at 9:01 AM, Andy Lutomirski <luto@kernel.org> wrote: >>>>>>>>> On Tue, Jun 12, 2018 at 4:43 AM H.J. Lu <hjl.tools@gmail.com> wrote: >>>>>>>>>> On Tue, Jun 12, 2018 at 3:03 AM, Thomas Gleixner <tglx@linutronix.de> wrote: >>>>>>>>>> That works for stuff which loads all libraries at start time, but what >>>>>>>>>> happens if the program uses dlopen() later on? If CET is force locked and >>>>>>>>>> the library is not CET enabled, it will fail. >>>>>>>>> >>>>>>>>> That is to prevent disabling CET by dlopening a legacy shared library. >>>>>>>>> >>>>>>>>>> I don't see the point of trying to support CET by magic. It adds complexity >>>>>>>>>> and you'll never be able to handle all corner cases correctly. dlopen() is >>>>>>>>>> not even a corner case. >>>>>>>>> >>>>>>>>> That is a price we pay for security. To enable CET, especially shadow >>>>>>>>> shack, the program and all of shared libraries it uses should be CET >>>>>>>>> enabled. Most of programs can be enabled with CET by compiling them >>>>>>>>> with -fcf-protection. >>>>>>>> >>>>>>>> If you charge too high a price for security, people may turn it off. >>>>>>>> I think we're going to need a mode where a program says "I want to use >>>>>>>> the CET, but turn it off if I dlopen an unsupported library". There >>>>>>>> are programs that load binary-only plugins. >>>>>>> >>>>>>> You can do >>>>>>> >>>>>>> # export GLIBC_TUNABLES=glibc.tune.hwcaps=-SHSTK >>>>>>> >>>>>>> which turns off shadow stack. >>>>>>> >>>>>> >>>>>> Which exactly illustrates my point. By making your security story too >>>>>> absolute, you'll force people to turn it off when they don't need to. >>>>>> If I'm using a fully CET-ified distro and I'm using a CET-aware >>>>>> program that loads binary plugins, and I may or may not have an old >>>>>> (binary-only, perhaps) plugin that doesn't support CET, then the >>>>>> behavior I want is for CET to be on until I dlopen() a program that >>>>>> doesn't support it. Unless there's some ABI reason why that can't be >>>>>> done, but I don't think there is. >>>>> >>>>> We can make it opt-in via GLIBC_TUNABLES. But by default, the legacy >>>>> shared object is disallowed when CET is enabled. >>>> >>>> That's a bad idea. Stuff has launchers which people might not be able to >>>> change. So they will simply turn of CET completely or it makes them hack >>>> horrible crap into init, e.g. the above export. >>>> >>>> Give them sane kernel options: >>>> >>>> cet = off, relaxed, forced >>>> >>>> where relaxed allows to run binary plugins. Then let dlopen() call into the >>>> kernel with the filepath of the library to check for CET and that will tell >>>> you whether its ok or or not and do the necessary magic in the kernel when >>>> CET has to be disabled due to a !CET library/application. >>>> >>>> That's also making the whole thing independent of magic glibc environment >>>> options and allows it to be used all over the place in the same way. >>> >>> This is very similar to our ARCH_CET_EXEC proposal which controls how >>> CET should be enforced. But Andy thinks it is a bad idea. >> >> I do think it's a bad idea to have a new piece of state that survives >> across exec(). It's going to have nasty usability problems and nasty >> security problems. >> >> We may need a mode by which glibc can turn CET *back off* even after a >> program had it on if it dlopens() an old binary. Or maybe there won't >> be demand. I can certainly understand why the CET_LOCK feature is >> there, although I think we need a way to override it using something >> like ptrace(). I'm not convinced that CET_LOCK is really needed, but >> someone who understand the thread model should chime in. >> >> Kees, do you know anyone who has a good enough understanding of >> usermode exploits and how they'll interact with CET? > > Adding Florian to CC, but if something gets CET enabled, it really > shouldn't have a way to turn it off. If there's a way to turn it off, > all the ROP research will suddenly turn to exactly one gadget before > doing the rest of the ROP: turning off CET. Right now ROP is: use > stack-pivot gadget, do everything else. Allowed CET to turn off will > just add one step: use CET-off gadget, use stack-pivot gadget, do > everything else. :P Fair enough > > Following Linus's request for "slow introduction" of new security > features, likely the best approach is to default to "relaxed" (with a > warning about down-grades), and allow distros/end-users to pick > "forced" if they know their libraries are all CET-enabled. I still don’t get what “relaxed” is for. I think the right design is: Processes start with CET on or off depending on the ELF note, but they start with CET unlocked no matter what. They can freely switch CET on and off (subject to being clever enough not to crash if they turn it on and then return right off the end of the shadow stack) until they call ARCH_CET_LOCK. Ptrace gets new APIs to turn CET on and off and to lock and unlock it. If an attacker finds a “ptrace me and turn off CET” gadget, then they might as well just do “ptrace me and write shell code” instead. It’s basically the same gadget. Keep in mind that the actual sequence of syscalls to do this is incredibly complicated. It’s unclear to me that forcing CET on belongs in the kernel at all. By the time an attacker can find a non-CET ELF binary and can exec it in a context where it does their bidding, the attacker is far beyond what CET can even try to help. At this point we’re talking about an attacker who can effectively invoke system(3) with arbitrary parameters, and attackers with *that* power don’t need ROP and the like. There is a new feature I’d like to see, though: add an ELF note to bless a binary as being an ELF interpreter. And add an LSM callback to validate an ELF interpreter. Let’s minimize the shenanigans that people who control containers can get up to. (Obviously the ELF note part would need to be opt-in.)
On Tue, Jun 19, 2018 at 7:50 AM, Andy Lutomirski <luto@amacapital.net> wrote: >> On Jun 18, 2018, at 5:52 PM, Kees Cook <keescook@chromium.org> wrote: >> Following Linus's request for "slow introduction" of new security >> features, likely the best approach is to default to "relaxed" (with a >> warning about down-grades), and allow distros/end-users to pick >> "forced" if they know their libraries are all CET-enabled. > > I still don’t get what “relaxed” is for. I think the right design is: > > Processes start with CET on or off depending on the ELF note, but they start with CET unlocked no matter what. They can freely switch CET on and off (subject to being clever enough not to crash if they turn it on and then return right off the end of the shadow stack) until they call ARCH_CET_LOCK. I'm fine with this. I'd expect modern loaders to just turn on CET and ARCH_CET_LOCK immediately and be done with it. :P > Ptrace gets new APIs to turn CET on and off and to lock and unlock it. If an attacker finds a “ptrace me and turn off CET” gadget, then they might as well just do “ptrace me and write shell code” instead. It’s basically the same gadget. Keep in mind that the actual sequence of syscalls to do this is incredibly complicated. Right -- if an attacker can control ptrace of the target, we're way past CET. The only concern I have, though, is taking advantage of expected ptracing. For example: browsers tend to have crash handlers that launch a ptracer. If ptracing disabled CET for all threads, this won't by safe: an attacker just gains control in two threads, crashes one to get the ptracer to attach, which disables CET in the other thread and the attacker continues ROP as normal. As long as the ptrace disabling is thread-specific, I think this will be okay. -Kees
On Tue, 2018-06-19 at 09:44 -0700, Kees Cook wrote: > On Tue, Jun 19, 2018 at 7:50 AM, Andy Lutomirski <luto@amacapital.net > > wrote: > > > > > > > > On Jun 18, 2018, at 5:52 PM, Kees Cook <keescook@chromium.org> > > > wrote: > > > Following Linus's request for "slow introduction" of new security > > > features, likely the best approach is to default to "relaxed" > > > (with a > > > warning about down-grades), and allow distros/end-users to pick > > > "forced" if they know their libraries are all CET-enabled. > > I still don’t get what “relaxed” is for. I think the right design > > is: > > > > Processes start with CET on or off depending on the ELF note, but > > they start with CET unlocked no matter what. They can freely switch > > CET on and off (subject to being clever enough not to crash if they > > turn it on and then return right off the end of the shadow stack) > > until they call ARCH_CET_LOCK. > I'm fine with this. I'd expect modern loaders to just turn on CET and > ARCH_CET_LOCK immediately and be done with it. :P This is the current implementation. If the loader has CET in its ELF header, it is executed with CET on. The loader will turn off CET if the application being loaded does not support it (in the ELF header). The loader calls ARCH_CET_LOCK before passing to the application. But how do we handle dlopen? > > > > Ptrace gets new APIs to turn CET on and off and to lock and unlock > > it. If an attacker finds a “ptrace me and turn off CET” gadget, > > then they might as well just do “ptrace me and write shell code” > > instead. It’s basically the same gadget. Keep in mind that the > > actual sequence of syscalls to do this is incredibly complicated. > Right -- if an attacker can control ptrace of the target, we're way > past CET. The only concern I have, though, is taking advantage of > expected ptracing. For example: browsers tend to have crash handlers > that launch a ptracer. If ptracing disabled CET for all threads, this > won't by safe: an attacker just gains control in two threads, crashes > one to get the ptracer to attach, which disables CET in the other > thread and the attacker continues ROP as normal. As long as the > ptrace > disabling is thread-specific, I think this will be okay. If ptrace can turn CET on/off and it is thread-specific, do we still need ptrace lock/unlock? Yu-cheng
On Tue, Jun 19, 2018 at 9:59 AM, Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > On Tue, 2018-06-19 at 09:44 -0700, Kees Cook wrote: >> On Tue, Jun 19, 2018 at 7:50 AM, Andy Lutomirski <luto@amacapital.net >> > wrote: >> > >> > > >> > > On Jun 18, 2018, at 5:52 PM, Kees Cook <keescook@chromium.org> >> > > wrote: >> > > Following Linus's request for "slow introduction" of new security >> > > features, likely the best approach is to default to "relaxed" >> > > (with a >> > > warning about down-grades), and allow distros/end-users to pick >> > > "forced" if they know their libraries are all CET-enabled. >> > I still don’t get what “relaxed” is for. I think the right design >> > is: >> > >> > Processes start with CET on or off depending on the ELF note, but >> > they start with CET unlocked no matter what. They can freely switch >> > CET on and off (subject to being clever enough not to crash if they >> > turn it on and then return right off the end of the shadow stack) >> > until they call ARCH_CET_LOCK. >> I'm fine with this. I'd expect modern loaders to just turn on CET and >> ARCH_CET_LOCK immediately and be done with it. :P > > This is the current implementation. If the loader has CET in its ELF > header, it is executed with CET on. The loader will turn off CET if > the application being loaded does not support it (in the ELF header). > The loader calls ARCH_CET_LOCK before passing to the application. But > how do we handle dlopen? I thought CET_LOCK would not get set in "relaxed" mode, due to dlopen usage, and that would be the WARN case. People without dlopen concerns can boot with "enforced" mode? If a system builder knows there are no legacy dlopens they build with enforced enabled, etc. >> > Ptrace gets new APIs to turn CET on and off and to lock and unlock >> > it. If an attacker finds a “ptrace me and turn off CET” gadget, >> > then they might as well just do “ptrace me and write shell code” >> > instead. It’s basically the same gadget. Keep in mind that the >> > actual sequence of syscalls to do this is incredibly complicated. >> Right -- if an attacker can control ptrace of the target, we're way >> past CET. The only concern I have, though, is taking advantage of >> expected ptracing. For example: browsers tend to have crash handlers >> that launch a ptracer. If ptracing disabled CET for all threads, this >> won't by safe: an attacker just gains control in two threads, crashes >> one to get the ptracer to attach, which disables CET in the other >> thread and the attacker continues ROP as normal. As long as the >> ptrace >> disabling is thread-specific, I think this will be okay. > > If ptrace can turn CET on/off and it is thread-specific, do we still > need ptrace lock/unlock? Does it provide anything beyond what PR_DUMPABLE does? -Kees
> On Jun 19, 2018, at 10:07 AM, Kees Cook <keescook@chromium.org> wrote: > >> On Tue, Jun 19, 2018 at 9:59 AM, Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: >>> On Tue, 2018-06-19 at 09:44 -0700, Kees Cook wrote: >>> On Tue, Jun 19, 2018 at 7:50 AM, Andy Lutomirski <luto@amacapital.net >>>> wrote: >>>> >>>>> >>>>> On Jun 18, 2018, at 5:52 PM, Kees Cook <keescook@chromium.org> >>>>> wrote: >>>>> Following Linus's request for "slow introduction" of new security >>>>> features, likely the best approach is to default to "relaxed" >>>>> (with a >>>>> warning about down-grades), and allow distros/end-users to pick >>>>> "forced" if they know their libraries are all CET-enabled. >>>> I still don’t get what “relaxed” is for. I think the right design >>>> is: >>>> >>>> Processes start with CET on or off depending on the ELF note, but >>>> they start with CET unlocked no matter what. They can freely switch >>>> CET on and off (subject to being clever enough not to crash if they >>>> turn it on and then return right off the end of the shadow stack) >>>> until they call ARCH_CET_LOCK. >>> I'm fine with this. I'd expect modern loaders to just turn on CET and >>> ARCH_CET_LOCK immediately and be done with it. :P >> >> This is the current implementation. If the loader has CET in its ELF >> header, it is executed with CET on. The loader will turn off CET if >> the application being loaded does not support it (in the ELF header). >> The loader calls ARCH_CET_LOCK before passing to the application. But >> how do we handle dlopen? > > I thought CET_LOCK would not get set in "relaxed" mode, due to dlopen > usage, and that would be the WARN case. People without dlopen concerns > can boot with "enforced" mode? If a system builder knows there are no > legacy dlopens they build with enforced enabled, etc. I think we’re getting ahead of ourselves. dlopen() of a non-CET-aware library in a CET process is distinctly non-trivial, especially in a multithreaded process. I think getting it right will require *userspace* support. It certainly needs ld.so to issue to arch_prctl at a bare minimum. So I see no point to a kernel-supplied “relaxed” mode. I think there may be demand for a ld.so relaxed mode, but it will have nothing to do with boot options. It’s potentially helpful to add an arch_prctl that turns CET off for all threads, but only if unlocked. It would obviously be one hell of a gadget. > >>>> Ptrace gets new APIs to turn CET on and off and to lock and unlock >>>> it. If an attacker finds a “ptrace me and turn off CET” gadget, >>>> then they might as well just do “ptrace me and write shell code” >>>> instead. It’s basically the same gadget. Keep in mind that the >>>> actual sequence of syscalls to do this is incredibly complicated. >>> Right -- if an attacker can control ptrace of the target, we're way >>> past CET. The only concern I have, though, is taking advantage of >>> expected ptracing. For example: browsers tend to have crash handlers >>> that launch a ptracer. If ptracing disabled CET for all threads, this >>> won't by safe: an attacker just gains control in two threads, crashes >>> one to get the ptracer to attach, which disables CET in the other >>> thread and the attacker continues ROP as normal. As long as the >>> ptrace >>> disabling is thread-specific, I think this will be okay. >> >> If ptrace can turn CET on/off and it is thread-specific, do we still >> need ptrace lock/unlock? Let me clarify. I don’t think ptrace() should have any automatic effect on CET. I think there should be an explicit way to ask ptrace to twiddle CET, and it should probably apply per thread. > > Does it provide anything beyond what PR_DUMPABLE does? What do you mean? > > -Kees > > -- > Kees Cook > Pixel Security
On Tue, Jun 19, 2018 at 10:20 AM, Andy Lutomirski <luto@amacapital.net> wrote: > >> On Jun 19, 2018, at 10:07 AM, Kees Cook <keescook@chromium.org> wrote: >> >> Does it provide anything beyond what PR_DUMPABLE does? > > What do you mean? I was just going by the name of it. I wasn't sure what "ptrace CET lock" meant, so I was trying to understand if it was another "you can't ptrace me" toggle, and if so, wouldn't it be redundant with PR_SET_DUMPABLE = 0, etc. -Kees
> On Jun 19, 2018, at 1:12 PM, Kees Cook <keescook@chromium.org> wrote: > >> On Tue, Jun 19, 2018 at 10:20 AM, Andy Lutomirski <luto@amacapital.net> wrote: >> >>> On Jun 19, 2018, at 10:07 AM, Kees Cook <keescook@chromium.org> wrote: >>> >>> Does it provide anything beyond what PR_DUMPABLE does? >> >> What do you mean? > > I was just going by the name of it. I wasn't sure what "ptrace CET > lock" meant, so I was trying to understand if it was another "you > can't ptrace me" toggle, and if so, wouldn't it be redundant with > PR_SET_DUMPABLE = 0, etc. > No, other way around. The valid CET states are on/unlocked, off/unlocked, on/locked, off/locked. arch_prctl can freely the state unless locked. ptrace can change it no matter what. The lock is to prevent the existence of a gadget to disable CET (unless the gadget involves ptrace, but I don’t think that’s a real concern).
On Tue, 2018-06-19 at 13:47 -0700, Andy Lutomirski wrote: > > > > On Jun 19, 2018, at 1:12 PM, Kees Cook <keescook@chromium.org> > > wrote: > > > > > > > > On Tue, Jun 19, 2018 at 10:20 AM, Andy Lutomirski <luto@amacapita > > > l.net> wrote: > > > > > > > > > > > On Jun 19, 2018, at 10:07 AM, Kees Cook <keescook@chromium.org> > > > > wrote: > > > > > > > > Does it provide anything beyond what PR_DUMPABLE does? > > > What do you mean? > > I was just going by the name of it. I wasn't sure what "ptrace CET > > lock" meant, so I was trying to understand if it was another "you > > can't ptrace me" toggle, and if so, wouldn't it be redundant with > > PR_SET_DUMPABLE = 0, etc. > > > No, other way around. The valid CET states are on/unlocked, > off/unlocked, on/locked, off/locked. arch_prctl can freely the state > unless locked. ptrace can change it no matter what. The lock is to > prevent the existence of a gadget to disable CET (unless the gadget > involves ptrace, but I don’t think that’s a real concern). We have the arch_prctl now and only need to add ptrace lock/unlock. Back to the dlopen() "relaxed" mode. Would the following work? If the lib being loaded does not use setjmp/getcontext families (the loader knows?), then the loader leaves shstk on. Otherwise, if the system-wide setting is "relaxed", the loader turns off shstk and issues a warning. In addition, if (dlopen == relaxed), then cet is not locked in any time. The system-wide setting (somewhere in /etc?) can be: dlopen=force|relaxed /* controls dlopen of non-cet libs */ exec=force|relaxed /* controls exec of non-cet apps */ -- Yu-cheng
> On Jun 19, 2018, at 3:38 PM, Yu-cheng Yu <yu-cheng.yu@intel.com> wrote: > > On Tue, 2018-06-19 at 13:47 -0700, Andy Lutomirski wrote: >>> >>> On Jun 19, 2018, at 1:12 PM, Kees Cook <keescook@chromium.org> >>> wrote: >>> >>>> >>>> On Tue, Jun 19, 2018 at 10:20 AM, Andy Lutomirski <luto@amacapita >>>> l.net> wrote: >>>> >>>>> >>>>> On Jun 19, 2018, at 10:07 AM, Kees Cook <keescook@chromium.org> >>>>> wrote: >>>>> >>>>> Does it provide anything beyond what PR_DUMPABLE does? >>>> What do you mean? >>> I was just going by the name of it. I wasn't sure what "ptrace CET >>> lock" meant, so I was trying to understand if it was another "you >>> can't ptrace me" toggle, and if so, wouldn't it be redundant with >>> PR_SET_DUMPABLE = 0, etc. >>> >> No, other way around. The valid CET states are on/unlocked, >> off/unlocked, on/locked, off/locked. arch_prctl can freely the state >> unless locked. ptrace can change it no matter what. The lock is to >> prevent the existence of a gadget to disable CET (unless the gadget >> involves ptrace, but I don’t think that’s a real concern). > > We have the arch_prctl now and only need to add ptrace lock/unlock. > > Back to the dlopen() "relaxed" mode. Would the following work? > > If the lib being loaded does not use setjmp/getcontext families (the > loader knows?), then the loader leaves shstk on. Will that actually work? Are there libs that do something like longjmp without actually using the glibc longjmp routine? What about compilers that statically match a throw to a catch and try to return through several frames at once? > Otherwise, if the > system-wide setting is "relaxed", the loader turns off shstk and issues > a warning. In addition, if (dlopen == relaxed), then cet is not locked > in any time. > > The system-wide setting (somewhere in /etc?) can be: > > dlopen=force|relaxed /* controls dlopen of non-cet libs */ > exec=force|relaxed /* controls exec of non-cet apps */ > > Why do we need a whole new mechanism here? Can’t all this use regular glibc tunables?
On Tue, 2018-06-19 at 17:50 -0700, Andy Lutomirski wrote: > > > > > On Jun 19, 2018, at 3:38 PM, Yu-cheng Yu <yu-cheng.yu@intel.com> > > wrote: > > > > On Tue, 2018-06-19 at 13:47 -0700, Andy Lutomirski wrote: > > > > > > > > > > > > > > > On Jun 19, 2018, at 1:12 PM, Kees Cook <keescook@chromium.org> > > > > wrote: > > > > > > > > > > > > > > > > > > > On Tue, Jun 19, 2018 at 10:20 AM, Andy Lutomirski <luto@amaca > > > > > pita > > > > > l.net> wrote: > > > > > > > > > > > > > > > > > > > > > > > On Jun 19, 2018, at 10:07 AM, Kees Cook <keescook@chromium. > > > > > > org> > > > > > > wrote: > > > > > > > > > > > > Does it provide anything beyond what PR_DUMPABLE does? > > > > > What do you mean? > > > > I was just going by the name of it. I wasn't sure what "ptrace > > > > CET > > > > lock" meant, so I was trying to understand if it was another > > > > "you > > > > can't ptrace me" toggle, and if so, wouldn't it be redundant > > > > with > > > > PR_SET_DUMPABLE = 0, etc. > > > > > > > No, other way around. The valid CET states are on/unlocked, > > > off/unlocked, on/locked, off/locked. arch_prctl can freely the > > > state > > > unless locked. ptrace can change it no matter what. The lock is > > > to > > > prevent the existence of a gadget to disable CET (unless the > > > gadget > > > involves ptrace, but I don’t think that’s a real concern). > > We have the arch_prctl now and only need to add ptrace lock/unlock. > > > > Back to the dlopen() "relaxed" mode. Would the following work? > > > > If the lib being loaded does not use setjmp/getcontext families > > (the > > loader knows?), then the loader leaves shstk on. > Will that actually work? Are there libs that do something like > longjmp without actually using the glibc longjmp routine? What about > compilers that statically match a throw to a catch and try to return > through several frames at once? > The compiler throw/catch is already handled similarly to how longjmp is handled. To summarize the dlopen() situation, ---- (1) We don't want to fall back like the following. One reason is turning off SHSTK for threads is tricky. if ((dlopen() a legacy library) && (cet_policy==relaxed)) { /* * We don't care if the library will actually fault; * just turn off CET protection now. */ Turn off CET; } (2) We cannot predict what version of a library will be dlopen'ed, and cannot turn off CET reliably from the beginning of an application. ---- Can we mandate a signal handler (to turn off CET) when ((dlopen is used ) && (cet_policy==relaxed))? > > > > Otherwise, if the > > system-wide setting is "relaxed", the loader turns off shstk and > > issues > > a warning. In addition, if (dlopen == relaxed), then cet is not > > locked > > in any time. > > > > The system-wide setting (somewhere in /etc?) can be: > > > > dlopen=force|relaxed /* controls dlopen of non-cet libs */ > > exec=force|relaxed /* controls exec of non-cet apps */ > > > > > Why do we need a whole new mechanism here? Can’t all this use > regular glibc tunables? Ok, got it. Yu-cheng
diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h index c8fd87e13859..a2a53fe4d5e6 100644 --- a/arch/x86/include/asm/cet.h +++ b/arch/x86/include/asm/cet.h @@ -12,24 +12,31 @@ struct task_struct; struct cet_stat { unsigned long shstk_base; unsigned long shstk_size; + unsigned long exec_shstk_size; unsigned int shstk_enabled:1; + unsigned int locked:1; + unsigned int exec_shstk:2; }; #ifdef CONFIG_X86_INTEL_CET +int prctl_cet(int option, unsigned long arg2); unsigned long cet_get_shstk_ptr(void); int cet_push_shstk(int ia32, unsigned long ssp, unsigned long val); int cet_setup_shstk(void); int cet_setup_thread_shstk(struct task_struct *p); +int cet_alloc_shstk(unsigned long *arg); void cet_disable_shstk(void); void cet_disable_free_shstk(struct task_struct *p); int cet_restore_signal(unsigned long ssp); int cet_setup_signal(int ia32, unsigned long addr); #else +static inline int prctl_cet(int option, unsigned long arg2) { return 0; } static inline unsigned long cet_get_shstk_ptr(void) { return 0; } static inline int cet_push_shstk(int ia32, unsigned long ssp, unsigned long val) { return 0; } static inline int cet_setup_shstk(void) { return 0; } static inline int cet_setup_thread_shstk(struct task_struct *p) { return 0; } +static inline int cet_alloc_shstk(unsigned long *arg) { return -EINVAL; } static inline void cet_disable_shstk(void) {} static inline void cet_disable_free_shstk(struct task_struct *p) {} static inline int cet_restore_signal(unsigned long ssp) { return 0; } diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h index 5a6aac9fa41f..f9965403b655 100644 --- a/arch/x86/include/uapi/asm/prctl.h +++ b/arch/x86/include/uapi/asm/prctl.h @@ -14,4 +14,19 @@ #define ARCH_MAP_VDSO_32 0x2002 #define ARCH_MAP_VDSO_64 0x2003 +#define ARCH_CET_STATUS 0x3001 +#define ARCH_CET_DISABLE 0x3002 +#define ARCH_CET_LOCK 0x3003 +#define ARCH_CET_EXEC 0x3004 +#define ARCH_CET_ALLOC_SHSTK 0x3005 +#define ARCH_CET_PUSH_SHSTK 0x3006 + +/* + * Settings for ARCH_CET_EXEC + */ +#define CET_EXEC_ELF_PROPERTY 0 +#define CET_EXEC_ALWAYS_OFF 1 +#define CET_EXEC_ALWAYS_ON 2 +#define CET_EXEC_MAX CET_EXEC_ALWAYS_ON + #endif /* _ASM_X86_PRCTL_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index cbf983f44b61..80464f925a6a 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -138,7 +138,7 @@ obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o -obj-$(CONFIG_X86_INTEL_CET) += cet.o +obj-$(CONFIG_X86_INTEL_CET) += cet.o cet_prctl.o obj-$(CONFIG_ARCH_HAS_PROGRAM_PROPERTIES) += elf.o diff --git a/arch/x86/kernel/cet.c b/arch/x86/kernel/cet.c index 156f5d88ffd5..1b7089dcf1ea 100644 --- a/arch/x86/kernel/cet.c +++ b/arch/x86/kernel/cet.c @@ -83,6 +83,19 @@ static unsigned long shstk_mmap(unsigned long addr, unsigned long len) return addr; } +int cet_alloc_shstk(unsigned long *arg) +{ + unsigned long size = *arg; + unsigned long addr; + + addr = shstk_mmap(0, size); + if (addr >= TASK_SIZE) + return -ENOMEM; + + *arg = addr; + return 0; +} + int cet_setup_shstk(void) { unsigned long addr, size; @@ -90,7 +103,10 @@ int cet_setup_shstk(void) if (!cpu_feature_enabled(X86_FEATURE_SHSTK)) return -EOPNOTSUPP; - size = SHSTK_SIZE; + size = current->thread.cet.exec_shstk_size; + if ((size > TASK_SIZE) || (size == 0)) + size = SHSTK_SIZE; + addr = shstk_mmap(0, size); if (addr >= TASK_SIZE) diff --git a/arch/x86/kernel/cet_prctl.c b/arch/x86/kernel/cet_prctl.c new file mode 100644 index 000000000000..326996e2ea80 --- /dev/null +++ b/arch/x86/kernel/cet_prctl.c @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <linux/errno.h> +#include <linux/uaccess.h> +#include <linux/prctl.h> +#include <linux/compat.h> +#include <asm/processor.h> +#include <asm/prctl.h> +#include <asm/elf.h> +#include <asm/elf_property.h> +#include <asm/cet.h> + +/* + * Handler of prctl for CET: + * + * ARCH_CET_STATUS: return the current status + * ARCH_CET_DISABLE: disable features + * ARCH_CET_LOCK: lock out cet features until exec() + * ARCH_CET_EXEC: set default features for exec() + * ARCH_CET_ALLOC_SHSTK: allocate shadow stack + * ARCH_CET_PUSH_SHSTK: put a return address on shadow stack + */ + +static int handle_get_status(unsigned long arg2) +{ + unsigned int features = 0, cet_exec = 0; + unsigned long shstk_size = 0; + + if (current->thread.cet.shstk_enabled) + features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + if (current->thread.cet.exec_shstk == CET_EXEC_ALWAYS_ON) + cet_exec |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + shstk_size = current->thread.cet.exec_shstk_size; + + if (in_compat_syscall()) { + unsigned int buf[3]; + + buf[0] = features; + buf[1] = cet_exec; + buf[2] = (unsigned int)shstk_size; + return copy_to_user((unsigned int __user *)arg2, buf, + sizeof(buf)); + } else { + unsigned long buf[3]; + + buf[0] = (unsigned long)features; + buf[1] = (unsigned long)cet_exec; + buf[2] = shstk_size; + return copy_to_user((unsigned long __user *)arg2, buf, + sizeof(buf)); + } +} + +static int handle_set_exec(unsigned long arg2) +{ + unsigned int features = 0, cet_exec = 0; + unsigned long shstk_size = 0; + int err = 0; + + if (in_compat_syscall()) { + unsigned int buf[3]; + + err = copy_from_user(buf, (unsigned int __user *)arg2, + sizeof(buf)); + if (!err) { + features = buf[0]; + cet_exec = buf[1]; + shstk_size = (unsigned long)buf[2]; + } + } else { + unsigned long buf[3]; + + err = copy_from_user(buf, (unsigned long __user *)arg2, + sizeof(buf)); + if (!err) { + features = (unsigned int)buf[0]; + cet_exec = (unsigned int)buf[1]; + shstk_size = buf[2]; + } + } + + if (err) + return -EFAULT; + if (cet_exec > CET_EXEC_MAX) + return -EINVAL; + if (shstk_size >= TASK_SIZE) + return -EINVAL; + + if (features & GNU_PROPERTY_X86_FEATURE_1_SHSTK) { + if (!cpu_feature_enabled(X86_FEATURE_SHSTK)) + return -EINVAL; + if ((current->thread.cet.exec_shstk == CET_EXEC_ALWAYS_ON) && + (cet_exec != CET_EXEC_ALWAYS_ON)) + return -EPERM; + } + + if (features & GNU_PROPERTY_X86_FEATURE_1_SHSTK) + current->thread.cet.exec_shstk = cet_exec; + + current->thread.cet.exec_shstk_size = shstk_size; + return 0; +} + +static int handle_push_shstk(unsigned long arg2) +{ + unsigned long ssp = 0, ret_addr = 0; + int ia32, err; + + ia32 = in_ia32_syscall(); + + if (ia32) { + unsigned int buf[2]; + + err = copy_from_user(buf, (unsigned int __user *)arg2, + sizeof(buf)); + if (!err) { + ssp = (unsigned long)buf[0]; + ret_addr = (unsigned long)buf[1]; + } + } else { + unsigned long buf[2]; + + err = copy_from_user(buf, (unsigned long __user *)arg2, + sizeof(buf)); + if (!err) { + ssp = buf[0]; + ret_addr = buf[1]; + } + } + if (err) + return -EFAULT; + err = cet_push_shstk(ia32, ssp, ret_addr); + if (err) + return -err; + return 0; +} + +static int handle_alloc_shstk(unsigned long arg2) +{ + int err = 0; + unsigned long shstk_size = 0; + + if (in_ia32_syscall()) { + unsigned int size; + + err = get_user(size, (unsigned int __user *)arg2); + if (!err) + shstk_size = size; + } else { + err = get_user(shstk_size, (unsigned long __user *)arg2); + } + + if (err) + return -EFAULT; + + err = cet_alloc_shstk(&shstk_size); + if (err) + return -err; + + if (in_ia32_syscall()) { + if (put_user(shstk_size, (unsigned int __user *)arg2)) + return -EFAULT; + } else { + if (put_user(shstk_size, (unsigned long __user *)arg2)) + return -EFAULT; + } + return 0; +} + +int prctl_cet(int option, unsigned long arg2) +{ + if (!cpu_feature_enabled(X86_FEATURE_SHSTK)) + return -EINVAL; + + switch (option) { + case ARCH_CET_STATUS: + return handle_get_status(arg2); + + case ARCH_CET_DISABLE: + if (current->thread.cet.locked) + return -EPERM; + if (arg2 & GNU_PROPERTY_X86_FEATURE_1_SHSTK) + cet_disable_free_shstk(current); + + return 0; + + case ARCH_CET_LOCK: + current->thread.cet.locked = 1; + return 0; + + case ARCH_CET_EXEC: + return handle_set_exec(arg2); + + case ARCH_CET_ALLOC_SHSTK: + return handle_alloc_shstk(arg2); + + case ARCH_CET_PUSH_SHSTK: + return handle_push_shstk(arg2); + + default: + return -EINVAL; + } +} diff --git a/arch/x86/kernel/elf.c b/arch/x86/kernel/elf.c index 8e2719d8dc86..de08d41971f6 100644 --- a/arch/x86/kernel/elf.c +++ b/arch/x86/kernel/elf.c @@ -8,7 +8,10 @@ #include <asm/cet.h> #include <asm/elf_property.h> +#include <asm/prctl.h> +#include <asm/processor.h> #include <uapi/linux/elf-em.h> +#include <uapi/linux/prctl.h> #include <linux/binfmts.h> #include <linux/elf.h> #include <linux/slab.h> @@ -208,13 +211,26 @@ int arch_setup_features(void *ehdr_p, void *phdr_p, current->thread.cet.shstk_enabled = 0; current->thread.cet.shstk_base = 0; current->thread.cet.shstk_size = 0; + current->thread.cet.locked = 0; if (cpu_feature_enabled(X86_FEATURE_SHSTK)) { - if (shstk) { - err = cet_setup_shstk(); - if (err < 0) - goto out; + int exec = current->thread.cet.exec_shstk; + + if (exec != CET_EXEC_ALWAYS_OFF) { + if (shstk || (exec == CET_EXEC_ALWAYS_ON)) { + err = cet_setup_shstk(); + if (err < 0) + goto out; + } } } + + /* + * Lockout CET features if no interpreter + */ + if (!interp) + current->thread.cet.locked = 1; + + err = 0; out: return err; } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index ae56caee41f9..54ad1863c6d2 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -794,6 +794,13 @@ long do_arch_prctl_common(struct task_struct *task, int option, return get_cpuid_mode(); case ARCH_SET_CPUID: return set_cpuid_mode(task, cpuid_enabled); + case ARCH_CET_STATUS: + case ARCH_CET_DISABLE: + case ARCH_CET_LOCK: + case ARCH_CET_EXEC: + case ARCH_CET_ALLOC_SHSTK: + case ARCH_CET_PUSH_SHSTK: + return prctl_cet(option, cpuid_enabled); } return -EINVAL;