mbox series

[0/3] Mips support for PT_GNU_STACK

Message ID 1561672142-5907-1-git-send-email-dmladjenovic@wavecomp.com
Headers show
Series Mips support for PT_GNU_STACK | expand

Message

Dragan Mladjenovic June 27, 2019, 9:49 p.m. UTC
Hello everyone,

Patches in this series are slight variation of work done previously by Faraz Shahbazker [1]
in 2016. A brief summary of the issue this is trying to address:

Up until the Linux kernel version 4.8 [2] MIPS FPU emulator used a small trampoline created on
user stack to handle delay slots when emulating FPU branches. Because of this non-executable stack
could not be enabled by default on MIPS. The compatibility issue is that these old kernels respect
PT_GNU_STACK, making the stack non-executable if requested, and could crash the user process if there
would be need to emulate a instruction in the delay slot of a FPU branch.

In order to allow for the tool-chain to safely use PT_GNU_STACK by default and to provide the
compatibility with pre-4.8 kernels, original patch would revert stack protection back to executable
stack if it could not detect that kernel supports non-executable stack.

The form of detection the patch proposes is not yet provided by the kernel. Instead, this version of
the patch does kernel version check at runtime and provides compatible behavior if it cannot detect
the 4.8 kernel or newer.
 
The last patch increments the ABI Version number in order to disallow new binaries to run with older glibc.
The number is not set in stone. I'm assuming it will probably land after GNU_HASH [3] support which consumes
ABI version 5 for MIPS. I will send proposal for Binutils and GCC after this part gets finalized.

Even if this part doesn't get in the next release due to issue [4] with ABI version handling.
It would be still nice if the back-compat support gets in. I would like to hear your thoughts on this.

Best regards,

Dragan

[1] https://sourceware.org/ml/libc-alpha/2016-02/msg00076.html
[2] https://github.com/torvalds/linux/commit/432c6bacbd0c16ec210c43da411ccc3855c4c010
[3] https://sourceware.org/ml/libc-alpha/2019-06/msg00456.html
[4] https://sourceware.org/ml/libc-alpha/2019-06/msg00730.html


Dragan Mladjenovic (3):
  [ELF] Allow the machine to override stack permissions via
    USE_DL_EXEC_STACK_OVERRIDE.
  [MIPS] Define USE_DL_EXEC_STACK_OVERRIDE on Mips
  [RFC][MIPS] Define GNU_STACK ABI

 elf/dl-load.c                                      | 10 +++++
 elf/dl-support.c                                   |  8 +++-
 sysdeps/generic/ldsodefs.h                         |  4 ++
 sysdeps/unix/sysv/linux/mips/Makefile              | 28 +++++++++++--
 sysdeps/unix/sysv/linux/mips/configure.ac          |  2 +
 sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c   | 48 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/mips/dl-sysdep.h           | 28 +++++++++++++
 sysdeps/unix/sysv/linux/mips/ldsodefs.h            |  2 +-
 sysdeps/unix/sysv/linux/mips/libc-abis             |  2 +
 .../sysv/linux/mips/tst-execstack-ovrd-static.c    |  1 +
 sysdeps/unix/sysv/linux/mips/tst-execstack-ovrd.c  |  2 +
 .../sysv/linux/mips/tst-execstack-ovrd1-static.c   |  1 +
 sysdeps/unix/sysv/linux/mips/tst-execstack-ovrd1.c | 11 +++++
 13 files changed, 141 insertions(+), 6 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/dl-sysdep.h
 create mode 100644 sysdeps/unix/sysv/linux/mips/tst-execstack-ovrd-static.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/tst-execstack-ovrd.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/tst-execstack-ovrd1-static.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/tst-execstack-ovrd1.c

Comments

Florian Weimer June 28, 2019, 8:34 a.m. UTC | #1
* Dragan Mladjenovic:

> The form of detection the patch proposes is not yet provided by the
> kernel. Instead, this version of the patch does kernel version check
> at runtime and provides compatible behavior if it cannot detect the
> 4.8 kernel or newer.

People patch their kernels to lie about the version, so I don't think
this is correct.

Kernel developers also think it's acceptable to change compatibility
mechanisms that have already been deployed in binutils or glibc, so I
really think this needs to wait until some signal has been added to the
the auxiliary vector in a mainline kernel.  Sorry.

Thanks,
Florian
Dragan Mladjenovic June 28, 2019, 12:21 p.m. UTC | #2
Thanks for the comment.

>> The form of detection the patch proposes is not yet provided by the
>> kernel. Instead, this version of the patch does kernel version check
>> at runtime and provides compatible behavior if it cannot detect the
>> 4.8 kernel or newer.
>
> People patch their kernels to lie about the version, so I don't think
> this is correct.

I'm not particularly fond of doing version checks, but this something
that is already done to enforce minimum kernel version supported 
by the glibc. Not sure this would be more broken that that. 

> Kernel developers also think it's acceptable to change compatibility
> mechanisms that have already been deployed in binutils or glibc, so I
> really think this needs to wait until some signal has been added to the
> the auxiliary vector in a mainline kernel.

I don't think that any new change on kernel side will make this change
obsolete or broken. At best if some kind of the signal gets provided by 
the kernel in the future that would allow us the have a real non-executable stack
on pre-4.8 kernel + 4.8 patch + future patch that provides the signal.

Best regards,

Dragan
Faraz Shahbazker June 28, 2019, 4:19 p.m. UTC | #3
On 6/28/19 1:34 AM, Florian Weimer wrote:
>> The form of detection the patch proposes is not yet provided by the
>> kernel. Instead, this version of the patch does kernel version check
>> at runtime and provides compatible behavior if it cannot detect the
>> 4.8 kernel or newer.
> 
> People patch their kernels to lie about the version, so I don't think
> this is correct.

Could a possible compromise be to forego the run-time check and instead make
the non-exec stack override trigger statically for MIPs when building glibc
with 4.8 or later kernel headers? In that case, the potential gap between glibc's
expectation and an old kernel masquerading as a newer version is exactly what it
would be for the usual minimum kernel version check.

We'd lose the ability to build against older kernel headers and work seamlessly
with newer kernels. This is not ideal, but it is more important to get a 
working non-executable stack solution out in user space.
> Kernel developers also think it's acceptable to change compatibility
> mechanisms that have already been deployed in binutils or glibc, so I
> really think this needs to wait until some signal has been added to the
> the auxiliary vector in a mainline kernel.

Note that as it stands, this is not an interface between the kernel and glibc.
Non-executable stack support is looked upon as a security fix in the kernel and
hence is not liable to flip back and forth, to the extent that there isn't a
KConfig setting which allows one to build the kernel without it. The auxiliary
vector OTOH would be a compatibility mechanism between the kernel and glibc and
hence would be vulnerable to the malicious manipulations of those devious kernel
developers :D

Regards,
Faraz
Dragan Mladjenovic July 5, 2019, 12:52 p.m. UTC | #4
Faraz Shahbazker *

> On 6/28/19 1:34 AM, Florian Weimer wrote:
>>> The form of detection the patch proposes is not yet provided by the
>>> kernel. Instead, this version of the patch does kernel version check
>>> at runtime and provides compatible behavior if it cannot detect the
>>> 4.8 kernel or newer.
>>
>> People patch their kernels to lie about the version, so I don't think
>> this is correct.
>
> Could a possible compromise be to forego the run-time check and instead make
> the non-exec stack override trigger statically for MIPs when building glibc
> with 4.8 or later kernel headers? In that case, the potential gap between glibc's
> expectation and an old kernel masquerading as a newer version is exactly what it
> would be for the usual minimum kernel version check.
>
> We'd lose the ability to build against older kernel headers and work seamlessly
> with newer kernels. This is not ideal, but it is more important to get a
> working non-executable stack solution out in user space.

I'm interested if proposed compromise is acceptable for the community to be done in this release cycle?
If not what else can we do to move this issue forward?

Best regards,

Dragan
Maciej W. Rozycki July 5, 2019, 4:16 p.m. UTC | #5
On Fri, 5 Jul 2019, Dragan Mladjenovic wrote:

> >>> The form of detection the patch proposes is not yet provided by the
> >>> kernel. Instead, this version of the patch does kernel version check
> >>> at runtime and provides compatible behavior if it cannot detect the
> >>> 4.8 kernel or newer.
> >>
> >> People patch their kernels to lie about the version, so I don't think
> >> this is correct.

 It is their problem then, I don't think it's a valid excuse.  We have 
previous art in this area; cf. commit d5f2798a0ac9 ("MIPS: Set the 
required Linux kernel version to 4.5.0 for 2008 NaN") and I reckon there 
have been more cases like this.

> > Could a possible compromise be to forego the run-time check and instead make
> > the non-exec stack override trigger statically for MIPs when building glibc
> > with 4.8 or later kernel headers? In that case, the potential gap between glibc's
> > expectation and an old kernel masquerading as a newer version is exactly what it
> > would be for the usual minimum kernel version check.
> >
> > We'd lose the ability to build against older kernel headers and work seamlessly
> > with newer kernels. This is not ideal, but it is more important to get a
> > working non-executable stack solution out in user space.
> 
> I'm interested if proposed compromise is acceptable for the community to be done in this release cycle?
> If not what else can we do to move this issue forward?

 Submitting stuff late in the cycle never helps, so I think the best 
compromise might be to target 2.31 instead.  And I think a kernel version 
check is the right approach.

  Maciej
Florian Weimer July 8, 2019, 12:01 p.m. UTC | #6
* Faraz Shahbazker:

> On 6/28/19 1:34 AM, Florian Weimer wrote:
>>> The form of detection the patch proposes is not yet provided by the
>>> kernel. Instead, this version of the patch does kernel version check
>>> at runtime and provides compatible behavior if it cannot detect the
>>> 4.8 kernel or newer.
>> 
>> People patch their kernels to lie about the version, so I don't think
>> this is correct.
>
> Could a possible compromise be to forego the run-time check and
> instead make the non-exec stack override trigger statically for MIPs
> when building glibc with 4.8 or later kernel headers? In that case,
> the potential gap between glibc's expectation and an old kernel
> masquerading as a newer version is exactly what it would be for the
> usual minimum kernel version check.

The minimum kernel version check is the reason why kernels are patched
to lie about their version. 8-/

>> Kernel developers also think it's acceptable to change compatibility
>> mechanisms that have already been deployed in binutils or glibc, so I
>> really think this needs to wait until some signal has been added to the
>> the auxiliary vector in a mainline kernel.
>
> Note that as it stands, this is not an interface between the kernel
> and glibc.  Non-executable stack support is looked upon as a security
> fix in the kernel and hence is not liable to flip back and forth, to
> the extent that there isn't a KConfig setting which allows one to
> build the kernel without it. The auxiliary vector OTOH would be a
> compatibility mechanism between the kernel and glibc and hence would
> be vulnerable to the malicious manipulations of those devious kernel
> developers :D

Not sure I understand.  We have the same problem with vsyscall.  Its
absence is also advertised as a security feature, and yet there is no
easy way to detect that the kernel is missing what was once a key piece
of the x86-64 userspace ABI.

Based on the vsyscall experience, lack of a reliable detection mechanism
means that it can be impossible to get old userspace ready for new
kernels (because you can't just conventionalize code and limit the
impact on legacy products which share the same binaries).

Thanks,
Florian
Dragan Mladjenovic July 9, 2019, 10:39 p.m. UTC | #7
On 08.07.2019. 14:01, Florian Weimer  wrote:

>> Could a possible compromise be to forego the run-time check and
>> instead make the non-exec stack override trigger statically for MIPs
>> when building glibc with 4.8 or later kernel headers? In that case,
>> the potential gap between glibc's expectation and an old kernel
>> masquerading as a newer version is exactly what it would be for the
>> usual minimum kernel version check.
>
> The minimum kernel version check is the reason why kernels are patched
> to lie about their version. 8-/

The user can lie via LD_ASSUME_KERNEL env or by hacking the kernel,
but that implies that they know what they are doing.  

There is an use-case of someone wanting to back-port the 4.8 kernel patch to their older
kernel and have glibc chose to honor the RW GNU_STACK.
Version check doesn't help here, and while it sounds a bit far-fetched I guess one could
be tempted to hack the kernel version along the way. 

Having something else than version check would be better in above case, but until that hits
the mainline we could as well move to 4.8 as minimum kernel version.

>>> Kernel developers also think it's acceptable to change compatibility
>>> mechanisms that have already been deployed in binutils or glibc, so I
>>> really think this needs to wait until some signal has been added to the
>>> the auxiliary vector in a mainline kernel.
>>
>> Note that as it stands, this is not an interface between the kernel
>> and glibc.  Non-executable stack support is looked upon as a security
>> fix in the kernel and hence is not liable to flip back and forth, to
>> the extent that there isn't a KConfig setting which allows one to
>> build the kernel without it. The auxiliary vector OTOH would be a
>> compatibility mechanism between the kernel and glibc and hence would
>> be vulnerable to the malicious manipulations of those devious kernel
>> developers :D
>
> Not sure I understand.  We have the same problem with vsyscall.  Its
> absence is also advertised as a security feature, and yet there is no
> easy way to detect that the kernel is missing what was once a key piece
> of the x86-64 userspace ABI.
>
> Based on the vsyscall experience, lack of a reliable detection mechanism
> means that it can be impossible to get old userspace ready for new
> kernels (because you can't just conventionalize code and limit the
> impact on legacy products which share the same binaries).

If someone in the future would decide do go back to the 
old kernel behavior of "randomly"* crashing user-space application that use
RW GNU_STACK we would be in the problem ether way.

* Not really random, but might as well be.

Best regards,

Dragan