Message ID | 20190906152455.22757-2-mic@digikod.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add support for O_MAYEXEC | expand |
Let's assume I want to add support for this to the glibc dynamic loader, while still being able to run on older kernels. Is it safe to try the open call first, with O_MAYEXEC, and if that fails with EINVAL, try again without O_MAYEXEC? Or do I risk disabling this security feature if I do that? Do we need a different way for recognizing kernel support. (Note that we cannot probe paths in /proc for various reasons.) Thanks, Florian
On 06/09/2019 17:56, Florian Weimer wrote: > Let's assume I want to add support for this to the glibc dynamic loader, > while still being able to run on older kernels. > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > with EINVAL, try again without O_MAYEXEC? The kernel ignore unknown open(2) flags, so yes, it is safe even for older kernel to use O_MAYEXEC. > > Or do I risk disabling this security feature if I do that? It is only a security feature if the kernel support it, otherwise it is a no-op. > > Do we need a different way for recognizing kernel support. (Note that > we cannot probe paths in /proc for various reasons.) There is no need to probe for kernel support. > > Thanks, > Florian > -- Mickaël Salaün Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > On 06/09/2019 17:56, Florian Weimer wrote: > > Let's assume I want to add support for this to the glibc dynamic loader, > > while still being able to run on older kernels. > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > with EINVAL, try again without O_MAYEXEC? > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > older kernel to use O_MAYEXEC. > Well...maybe. What about existing programs that are sending down bogus open flags? Once you turn this on, they may break...or provide a way to circumvent the protections this gives. Maybe this should be a new flag that is only usable in the new openat2() syscall that's still under discussion? That syscall will enforce that all flags are recognized. You presumably wouldn't need the sysctl if you went that route too. Anyone that wants to use this will have to recompile anyway. If the kernel doesn't support openat2 or if the flag is rejected then you know that you have no O_MAYEXEC support and can decide what to do. > > Or do I risk disabling this security feature if I do that? > > It is only a security feature if the kernel support it, otherwise it is > a no-op. > With a security feature, I think we really want userland to aware of whether it works. > > Do we need a different way for recognizing kernel support. (Note that > > we cannot probe paths in /proc for various reasons.) > > There is no need to probe for kernel support. > > > Thanks, > > Florian > > > > -- > Mickaël Salaün > > Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On 2019-09-06, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: > > On 06/09/2019 17:56, Florian Weimer wrote: > > Let's assume I want to add support for this to the glibc dynamic loader, > > while still being able to run on older kernels. > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > with EINVAL, try again without O_MAYEXEC? > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > older kernel to use O_MAYEXEC. Depends on your definition of "safe" -- a security feature that you will silently not enable on older kernels doesn't sound super safe to me. Unfortunately this is a limitation of open(2) that we cannot change -- which is why the openat2(2) proposal I've been posting gives -EINVAL for unknown O_* flags. There is a way to probe for support (though unpleasant), by creating a test O_MAYEXEC fd and then checking if the flag is present in /proc/self/fdinfo/$n.
On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > > On 06/09/2019 17:56, Florian Weimer wrote: > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > while still being able to run on older kernels. > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > with EINVAL, try again without O_MAYEXEC? > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > older kernel to use O_MAYEXEC. > > > > Well...maybe. What about existing programs that are sending down bogus > open flags? Once you turn this on, they may break...or provide a way to > circumvent the protections this gives. It should be noted that this has been a valid concern for every new O_* flag introduced (and yet we still introduced new flags, despite the concern) -- though to be fair, O_TMPFILE actually does have a work-around with the O_DIRECTORY mask setup. The openat2() set adds O_EMPTYPATH -- though in fairness it's also backwards compatible because empty path strings have always given ENOENT (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. > Maybe this should be a new flag that is only usable in the new openat2() > syscall that's still under discussion? That syscall will enforce that > all flags are recognized. You presumably wouldn't need the sysctl if you > went that route too. I'm also interested in whether we could add an UPGRADE_NOEXEC flag to how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for it, since I'd heard about this work through the grape-vine).
On 06/09/2019 18:48, Jeff Layton wrote: > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: >> On 06/09/2019 17:56, Florian Weimer wrote: >>> Let's assume I want to add support for this to the glibc dynamic loader, >>> while still being able to run on older kernels. >>> >>> Is it safe to try the open call first, with O_MAYEXEC, and if that fails >>> with EINVAL, try again without O_MAYEXEC? >> >> The kernel ignore unknown open(2) flags, so yes, it is safe even for >> older kernel to use O_MAYEXEC. >> > > Well...maybe. What about existing programs that are sending down bogus > open flags? Once you turn this on, they may break...or provide a way to > circumvent the protections this gives. Well, I don't think we should nor could care about bogus programs that do not conform to the Linux ABI. > > Maybe this should be a new flag that is only usable in the new openat2() > syscall that's still under discussion? That syscall will enforce that > all flags are recognized. You presumably wouldn't need the sysctl if you > went that route too. Here is a thread about a new syscall: https://lore.kernel.org/lkml/1544699060.6703.11.camel@linux.ibm.com/ I don't think it fit well with auditing nor integrity. Moreover using the current open(2) behavior of ignoring unknown flags fit well with the usage of O_MAYEXEC (because it is only a hint to the kernel about the use of the *opened* file). > > Anyone that wants to use this will have to recompile anyway. If the > kernel doesn't support openat2 or if the flag is rejected then you know > that you have no O_MAYEXEC support and can decide what to do. If we want to enforce a security policy, we need to either be the system administrator or the distro developer. If a distro ship interpreters using this flag, we don't need to recompile anything, but we need to be able to control the enforcement according to the mount point configuration (or an advanced MAC, or an IMA config). I don't see why an userspace process should check if this flag is supported or not, it should simply use it, and the sysadmin will enable an enforcement if it makes sense for the whole system. > >>> Or do I risk disabling this security feature if I do that? >> >> It is only a security feature if the kernel support it, otherwise it is >> a no-op. >> > > With a security feature, I think we really want userland to aware of > whether it works. If userland would like to enforce something, it can already do it without any kernel modification. The goal of the O_MAYEXEC flag is to enable the kernel, hence sysadmins or system designers, to enforce a global security policy that makes sense. > >>> Do we need a different way for recognizing kernel support. (Note that >>> we cannot probe paths in /proc for various reasons.) >> >> There is no need to probe for kernel support. >> >>> Thanks, >>> Florian >>> Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On Sat, Sep 07, 2019 at 03:07:39AM +1000, Aleksa Sarai wrote: > On 2019-09-06, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: > > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > while still being able to run on older kernels. > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > with EINVAL, try again without O_MAYEXEC? > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > older kernel to use O_MAYEXEC. > > Depends on your definition of "safe" -- a security feature that you will > silently not enable on older kernels doesn't sound super safe to me. > Unfortunately this is a limitation of open(2) that we cannot change -- > which is why the openat2(2) proposal I've been posting gives -EINVAL for > unknown O_* flags. > > There is a way to probe for support (though unpleasant), by creating a > test O_MAYEXEC fd and then checking if the flag is present in > /proc/self/fdinfo/$n. Which Florian said they can't do for various reasons. It is a major painpoint if there's no easy way for userspace to probe for support. Especially if it's security related which usually means that you want to know whether this feature works or not. Christian
On 06/09/2019 19:20, Christian Brauner wrote: > On Sat, Sep 07, 2019 at 03:07:39AM +1000, Aleksa Sarai wrote: >> On 2019-09-06, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: >>> >>> On 06/09/2019 17:56, Florian Weimer wrote: >>>> Let's assume I want to add support for this to the glibc dynamic loader, >>>> while still being able to run on older kernels. >>>> >>>> Is it safe to try the open call first, with O_MAYEXEC, and if that fails >>>> with EINVAL, try again without O_MAYEXEC? >>> >>> The kernel ignore unknown open(2) flags, so yes, it is safe even for >>> older kernel to use O_MAYEXEC. >> >> Depends on your definition of "safe" -- a security feature that you will >> silently not enable on older kernels doesn't sound super safe to me. >> Unfortunately this is a limitation of open(2) that we cannot change -- >> which is why the openat2(2) proposal I've been posting gives -EINVAL for >> unknown O_* flags. >> >> There is a way to probe for support (though unpleasant), by creating a >> test O_MAYEXEC fd and then checking if the flag is present in >> /proc/self/fdinfo/$n. > > Which Florian said they can't do for various reasons. > > It is a major painpoint if there's no easy way for userspace to probe > for support. Especially if it's security related which usually means > that you want to know whether this feature works or not. I used "safe" deliberately (not "secure" which didn't make sense in this sentence). According to the threat model, if the kernel doesn't support the feature, it should be ignored by userland. In this case, it fit well with the current behavior of open(2). I agree that the openat2(2) behavior handling flags is the good way to do it (whitelisting), but the O_MAYEXEC flag should not change the userland behavior on its own, because it depend on a global policy. Even being able to probe for O_MAYEXEC support does not make sense because it would not be enough to know the system policy (either this flag is enforced or not…). Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On Fri, Sep 06, 2019 at 07:20:51PM +0200, Christian Brauner wrote: > On Sat, Sep 07, 2019 at 03:07:39AM +1000, Aleksa Sarai wrote: > > On 2019-09-06, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: > > > > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > > while still being able to run on older kernels. > > > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > > with EINVAL, try again without O_MAYEXEC? > > > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > > older kernel to use O_MAYEXEC. > > > > Depends on your definition of "safe" -- a security feature that you will > > silently not enable on older kernels doesn't sound super safe to me. > > Unfortunately this is a limitation of open(2) that we cannot change -- > > which is why the openat2(2) proposal I've been posting gives -EINVAL for > > unknown O_* flags. > > > > There is a way to probe for support (though unpleasant), by creating a > > test O_MAYEXEC fd and then checking if the flag is present in > > /proc/self/fdinfo/$n. > > Which Florian said they can't do for various reasons. > > It is a major painpoint if there's no easy way for userspace to probe > for support. Especially if it's security related which usually means > that you want to know whether this feature works or not. What about just trying to violate the policy via fexecve() instead of looking around in /proc? Still ugly, though. Tycho
* Tycho Andersen: > On Fri, Sep 06, 2019 at 07:20:51PM +0200, Christian Brauner wrote: >> On Sat, Sep 07, 2019 at 03:07:39AM +1000, Aleksa Sarai wrote: >> > On 2019-09-06, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: >> > > >> > > On 06/09/2019 17:56, Florian Weimer wrote: >> > > > Let's assume I want to add support for this to the glibc dynamic loader, >> > > > while still being able to run on older kernels. >> > > > >> > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails >> > > > with EINVAL, try again without O_MAYEXEC? >> > > >> > > The kernel ignore unknown open(2) flags, so yes, it is safe even for >> > > older kernel to use O_MAYEXEC. >> > >> > Depends on your definition of "safe" -- a security feature that you will >> > silently not enable on older kernels doesn't sound super safe to me. >> > Unfortunately this is a limitation of open(2) that we cannot change -- >> > which is why the openat2(2) proposal I've been posting gives -EINVAL for >> > unknown O_* flags. >> > >> > There is a way to probe for support (though unpleasant), by creating a >> > test O_MAYEXEC fd and then checking if the flag is present in >> > /proc/self/fdinfo/$n. >> >> Which Florian said they can't do for various reasons. >> >> It is a major painpoint if there's no easy way for userspace to probe >> for support. Especially if it's security related which usually means >> that you want to know whether this feature works or not. > > What about just trying to violate the policy via fexecve() instead of > looking around in /proc? Still ugly, though. How would we do this? This is about opening the main executable as part of an explicit loader invocation. Typically, an fexecve will succeed and try to run the program, but with the wrong dynamic loader. Thanks, Florian
On Fri, 2019-09-06 at 19:14 +0200, Mickaël Salaün wrote: > On 06/09/2019 18:48, Jeff Layton wrote: > > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > > while still being able to run on older kernels. > > > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > > with EINVAL, try again without O_MAYEXEC? > > > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > > older kernel to use O_MAYEXEC. > > > > > > > Well...maybe. What about existing programs that are sending down bogus > > open flags? Once you turn this on, they may break...or provide a way to > > circumvent the protections this gives. > > Well, I don't think we should nor could care about bogus programs that > do not conform to the Linux ABI. > But they do conform. The ABI is just undefined here. Unknown flags are ignored so we never really know if $random_program may be setting them. > > Maybe this should be a new flag that is only usable in the new openat2() > > syscall that's still under discussion? That syscall will enforce that > > all flags are recognized. You presumably wouldn't need the sysctl if you > > went that route too. > > Here is a thread about a new syscall: > https://lore.kernel.org/lkml/1544699060.6703.11.camel@linux.ibm.com/ > > I don't think it fit well with auditing nor integrity. Moreover using > the current open(2) behavior of ignoring unknown flags fit well with the > usage of O_MAYEXEC (because it is only a hint to the kernel about the > use of the *opened* file). > The fact that open and openat didn't vet unknown flags is really a bug. Too late to fix it now, of course, and as Aleksa points out, we've worked around that in the past. Now though, we have a new openat2 syscall on the horizon. There's little need to continue these sorts of hacks. New open flags really have no place in the old syscalls, IMO. > > Anyone that wants to use this will have to recompile anyway. If the > > kernel doesn't support openat2 or if the flag is rejected then you know > > that you have no O_MAYEXEC support and can decide what to do. > > If we want to enforce a security policy, we need to either be the system > administrator or the distro developer. If a distro ship interpreters > using this flag, we don't need to recompile anything, but we need to be > able to control the enforcement according to the mount point > configuration (or an advanced MAC, or an IMA config). I don't see why an > userspace process should check if this flag is supported or not, it > should simply use it, and the sysadmin will enable an enforcement if it > makes sense for the whole system. > A userland program may need to do other risk mitigation if it sets O_MAYEXEC and the kernel doesn't recognize it. Personally, here's what I'd suggest: - Base this on top of the openat2 set - Change it that so that openat2() files are non-executable by default. Anyone wanting to do that needs to set O_MAYEXEC or upgrade the fd somehow. - Only have the openat2 syscall pay attention to O_MAYEXEC. Let open and openat continue ignoring the new flag. That works around a whole pile of potential ABI headaches. Note that we'd need to make that decision before the openat2 patches are merged. Even better would be to declare the new flag in some openat2-only flag space, so there's no confusion about it being supported by legacy open calls. If glibc wants to implement an open -> openat2 wrapper in userland later, it can set that flag in the wrapper implicitly to emulate the old behavior. Given that you're going to have to recompile software to take advantage of this anyway, what's the benefit to changing legacy syscalls? > > > > Or do I risk disabling this security feature if I do that? > > > > > > It is only a security feature if the kernel support it, otherwise it is > > > a no-op. > > > > > > > With a security feature, I think we really want userland to aware of > > whether it works. > > If userland would like to enforce something, it can already do it > without any kernel modification. The goal of the O_MAYEXEC flag is to > enable the kernel, hence sysadmins or system designers, to enforce a > global security policy that makes sense. > I don't see how this helps anything if you can't tell whether the kernel recognizes the damned thing. Also, our track record with global sysctl switches like this is pretty poor. They're an administrative headache as well as a potential attack vector. I think your idea is a good one, but it could stand to have fewer moving parts.
> On Sep 6, 2019, at 11:38 AM, Jeff Layton <jlayton@kernel.org> wrote: > >> On Fri, 2019-09-06 at 19:14 +0200, Mickaël Salaün wrote: >>> On 06/09/2019 18:48, Jeff Layton wrote: >>>> On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: >>>>> On 06/09/2019 17:56, Florian Weimer wrote: >>>>> Let's assume I want to add support for this to the glibc dynamic loader, >>>>> while still being able to run on older kernels. >>>>> >>>>> Is it safe to try the open call first, with O_MAYEXEC, and if that fails >>>>> with EINVAL, try again without O_MAYEXEC? >>>> >>>> The kernel ignore unknown open(2) flags, so yes, it is safe even for >>>> older kernel to use O_MAYEXEC. >>>> >>> >>> Well...maybe. What about existing programs that are sending down bogus >>> open flags? Once you turn this on, they may break...or provide a way to >>> circumvent the protections this gives. >> >> Well, I don't think we should nor could care about bogus programs that >> do not conform to the Linux ABI. >> > > But they do conform. The ABI is just undefined here. Unknown flags are > ignored so we never really know if $random_program may be setting them. > >>> Maybe this should be a new flag that is only usable in the new openat2() >>> syscall that's still under discussion? That syscall will enforce that >>> all flags are recognized. You presumably wouldn't need the sysctl if you >>> went that route too. >> >> Here is a thread about a new syscall: >> https://lore.kernel.org/lkml/1544699060.6703.11.camel@linux.ibm.com/ >> >> I don't think it fit well with auditing nor integrity. Moreover using >> the current open(2) behavior of ignoring unknown flags fit well with the >> usage of O_MAYEXEC (because it is only a hint to the kernel about the >> use of the *opened* file). >> > > The fact that open and openat didn't vet unknown flags is really a bug. > > Too late to fix it now, of course, and as Aleksa points out, we've > worked around that in the past. Now though, we have a new openat2 > syscall on the horizon. There's little need to continue these sorts of > hacks. > > New open flags really have no place in the old syscalls, IMO. > >>> Anyone that wants to use this will have to recompile anyway. If the >>> kernel doesn't support openat2 or if the flag is rejected then you know >>> that you have no O_MAYEXEC support and can decide what to do. >> >> If we want to enforce a security policy, we need to either be the system >> administrator or the distro developer. If a distro ship interpreters >> using this flag, we don't need to recompile anything, but we need to be >> able to control the enforcement according to the mount point >> configuration (or an advanced MAC, or an IMA config). I don't see why an >> userspace process should check if this flag is supported or not, it >> should simply use it, and the sysadmin will enable an enforcement if it >> makes sense for the whole system. >> > > A userland program may need to do other risk mitigation if it sets > O_MAYEXEC and the kernel doesn't recognize it. > > Personally, here's what I'd suggest: > > - Base this on top of the openat2 set > - Change it that so that openat2() files are non-executable by default. Anyone wanting to do that needs to set O_MAYEXEC or upgrade the fd somehow. > - Only have the openat2 syscall pay attention to O_MAYEXEC. Let open and openat continue ignoring the new flag. > > That works around a whole pile of potential ABI headaches. Note that > we'd need to make that decision before the openat2 patches are merged. > > Even better would be to declare the new flag in some openat2-only flag > space, so there's no confusion about it being supported by legacy open > calls. > > If glibc wants to implement an open -> openat2 wrapper in userland > later, it can set that flag in the wrapper implicitly to emulate the old > behavior. > > Given that you're going to have to recompile software to take advantage > of this anyway, what's the benefit to changing legacy syscalls? > >>>>> Or do I risk disabling this security feature if I do that? >>>> >>>> It is only a security feature if the kernel support it, otherwise it is >>>> a no-op. >>>> >>> >>> With a security feature, I think we really want userland to aware of >>> whether it works. >> >> If userland would like to enforce something, it can already do it >> without any kernel modification. The goal of the O_MAYEXEC flag is to >> enable the kernel, hence sysadmins or system designers, to enforce a >> global security policy that makes sense. >> > > I don't see how this helps anything if you can't tell whether the kernel > recognizes the damned thing. Also, our track record with global sysctl > switches like this is pretty poor. They're an administrative headache as > well as a potential attack vector. I tend to agree. The sysctl seems like it’s asking for trouble. I can see an ld.so.conf option to turn this thing off making sense.
* Jeff Layton: > Even better would be to declare the new flag in some openat2-only flag > space, so there's no confusion about it being supported by legacy open > calls. Isn't that desirable anyway because otherwise fcntl with F_GETFL will give really confusing results? > If glibc wants to implement an open -> openat2 wrapper in userland > later, it can set that flag in the wrapper implicitly to emulate the old > behavior. I see us rather doing the opposite, i.e. implement openat2 with non-exotic flags using openat. But we've bitten by this in the past, so maybe that's not such a great idea. It's tempting to make the same mistake again for every new system call. Thanks, Florian
On Fri, Sep 06, 2019 at 08:27:31PM +0200, Florian Weimer wrote: > * Tycho Andersen: > > > On Fri, Sep 06, 2019 at 07:20:51PM +0200, Christian Brauner wrote: > >> On Sat, Sep 07, 2019 at 03:07:39AM +1000, Aleksa Sarai wrote: > >> > On 2019-09-06, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: > >> > > > >> > > On 06/09/2019 17:56, Florian Weimer wrote: > >> > > > Let's assume I want to add support for this to the glibc dynamic loader, > >> > > > while still being able to run on older kernels. > >> > > > > >> > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > >> > > > with EINVAL, try again without O_MAYEXEC? > >> > > > >> > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > >> > > older kernel to use O_MAYEXEC. > >> > > >> > Depends on your definition of "safe" -- a security feature that you will > >> > silently not enable on older kernels doesn't sound super safe to me. > >> > Unfortunately this is a limitation of open(2) that we cannot change -- > >> > which is why the openat2(2) proposal I've been posting gives -EINVAL for > >> > unknown O_* flags. > >> > > >> > There is a way to probe for support (though unpleasant), by creating a > >> > test O_MAYEXEC fd and then checking if the flag is present in > >> > /proc/self/fdinfo/$n. > >> > >> Which Florian said they can't do for various reasons. > >> > >> It is a major painpoint if there's no easy way for userspace to probe > >> for support. Especially if it's security related which usually means > >> that you want to know whether this feature works or not. > > > > What about just trying to violate the policy via fexecve() instead of > > looking around in /proc? Still ugly, though. > > How would we do this? This is about opening the main executable as part > of an explicit loader invocation. Typically, an fexecve will succeed > and try to run the program, but with the wrong dynamic loader. Yeah, fexecve() was a think-o, sorry, you don't need to go that far. I was thinking do what the tests in this series do: create a tmpfs with MS_NOEXEC, put an executable file in it, and try and open it with O_MAYEXEC. If that works, the kernel doesn't support the flag, and it should give you -EACCES if the kernel does support the flag. Still a lot of work, though. Seems better to just use openat2. Tycho
On Fri, 6 Sep 2019, Jeff Layton wrote: > The fact that open and openat didn't vet unknown flags is really a bug. > > Too late to fix it now, of course, and as Aleksa points out, we've > worked around that in the past. Now though, we have a new openat2 > syscall on the horizon. There's little need to continue these sorts of > hacks. > > New open flags really have no place in the old syscalls, IMO. Agree here. It's unfortunate but a reality and Linus will reject any such changes which break existing userspace.
On Sat, 2019-09-07 at 03:13 +1000, Aleksa Sarai wrote: > On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > > while still being able to run on older kernels. > > > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > > with EINVAL, try again without O_MAYEXEC? > > > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > > older kernel to use O_MAYEXEC. > > > > > > > Well...maybe. What about existing programs that are sending down bogus > > open flags? Once you turn this on, they may break...or provide a way to > > circumvent the protections this gives. > > It should be noted that this has been a valid concern for every new O_* > flag introduced (and yet we still introduced new flags, despite the > concern) -- though to be fair, O_TMPFILE actually does have a > work-around with the O_DIRECTORY mask setup. > > The openat2() set adds O_EMPTYPATH -- though in fairness it's also > backwards compatible because empty path strings have always given ENOENT > (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. > > > Maybe this should be a new flag that is only usable in the new openat2() > > syscall that's still under discussion? That syscall will enforce that > > all flags are recognized. You presumably wouldn't need the sysctl if you > > went that route too. > > I'm also interested in whether we could add an UPGRADE_NOEXEC flag to > how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for > it, since I'd heard about this work through the grape-vine). > I rather like the idea of having openat2 fds be non-executable by default, and having userland request it specifically via O_MAYEXEC (or some similar openat2 flag) if it's needed. Then you could add an UPGRADE_EXEC flag instead? That seems like something reasonable to do with a brand new API, and might be very helpful for preventing certain classes of attacks.
> On Sep 6, 2019, at 12:43 PM, Jeff Layton <jlayton@kernel.org> wrote: > >> On Sat, 2019-09-07 at 03:13 +1000, Aleksa Sarai wrote: >>> On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: >>>> On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: >>>>> On 06/09/2019 17:56, Florian Weimer wrote: >>>>> Let's assume I want to add support for this to the glibc dynamic loader, >>>>> while still being able to run on older kernels. >>>>> >>>>> Is it safe to try the open call first, with O_MAYEXEC, and if that fails >>>>> with EINVAL, try again without O_MAYEXEC? >>>> >>>> The kernel ignore unknown open(2) flags, so yes, it is safe even for >>>> older kernel to use O_MAYEXEC. >>>> >>> >>> Well...maybe. What about existing programs that are sending down bogus >>> open flags? Once you turn this on, they may break...or provide a way to >>> circumvent the protections this gives. >> >> It should be noted that this has been a valid concern for every new O_* >> flag introduced (and yet we still introduced new flags, despite the >> concern) -- though to be fair, O_TMPFILE actually does have a >> work-around with the O_DIRECTORY mask setup. >> >> The openat2() set adds O_EMPTYPATH -- though in fairness it's also >> backwards compatible because empty path strings have always given ENOENT >> (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. >> >>> Maybe this should be a new flag that is only usable in the new openat2() >>> syscall that's still under discussion? That syscall will enforce that >>> all flags are recognized. You presumably wouldn't need the sysctl if you >>> went that route too. >> >> I'm also interested in whether we could add an UPGRADE_NOEXEC flag to >> how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for >> it, since I'd heard about this work through the grape-vine). >> > > I rather like the idea of having openat2 fds be non-executable by > default, and having userland request it specifically via O_MAYEXEC (or > some similar openat2 flag) if it's needed. Then you could add an > UPGRADE_EXEC flag instead? > > That seems like something reasonable to do with a brand new API, and > might be very helpful for preventing certain classes of attacks. > > There are at least four concepts of executability here: - Just check the file mode and any other relevant permissions. Return a normal fd. Makes sense for script interpreters, perhaps. - Make the fd fexecve-able. - Make the resulting fd mappable PROT_EXEC. - Make the resulting fd upgradable. I’m not at all convinced that the kernel needs to distinguish all these, but at least upgradability should be its own thing IMO.
On Fri, 2019-09-06 at 13:06 -0700, Andy Lutomirski wrote: > > On Sep 6, 2019, at 12:43 PM, Jeff Layton <jlayton@kernel.org> wrote: > > > > > On Sat, 2019-09-07 at 03:13 +1000, Aleksa Sarai wrote: > > > > On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > > > > > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > > > > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > > > > while still being able to run on older kernels. > > > > > > > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > > > > with EINVAL, try again without O_MAYEXEC? > > > > > > > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > > > > older kernel to use O_MAYEXEC. > > > > > > > > > > > > > Well...maybe. What about existing programs that are sending down bogus > > > > open flags? Once you turn this on, they may break...or provide a way to > > > > circumvent the protections this gives. > > > > > > It should be noted that this has been a valid concern for every new O_* > > > flag introduced (and yet we still introduced new flags, despite the > > > concern) -- though to be fair, O_TMPFILE actually does have a > > > work-around with the O_DIRECTORY mask setup. > > > > > > The openat2() set adds O_EMPTYPATH -- though in fairness it's also > > > backwards compatible because empty path strings have always given ENOENT > > > (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. > > > > > > > Maybe this should be a new flag that is only usable in the new openat2() > > > > syscall that's still under discussion? That syscall will enforce that > > > > all flags are recognized. You presumably wouldn't need the sysctl if you > > > > went that route too. > > > > > > I'm also interested in whether we could add an UPGRADE_NOEXEC flag to > > > how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for > > > it, since I'd heard about this work through the grape-vine). > > > > > > > I rather like the idea of having openat2 fds be non-executable by > > default, and having userland request it specifically via O_MAYEXEC (or > > some similar openat2 flag) if it's needed. Then you could add an > > UPGRADE_EXEC flag instead? > > > > That seems like something reasonable to do with a brand new API, and > > might be very helpful for preventing certain classes of attacks. > > > > > > There are at least four concepts of executability here: > > - Just check the file mode and any other relevant permissions. Return a normal fd. Makes sense for script interpreters, perhaps. > > - Make the fd fexecve-able. > > - Make the resulting fd mappable PROT_EXEC. > > - Make the resulting fd upgradable. > > I’m not at all convinced that the kernel needs to distinguish all these, but at least upgradability should be its own thing IMO. Good point. Upgradability is definitely orthogonal, though the idea there is to alter the default behavior. If the default is NOEXEC then UPGRADE_EXEC would make sense. In any case, I was mostly thinking about the middle two in your list above. After more careful reading of the patches, I now get get that Mickaël is more interested in the first, and that's really a different sort of use-case. Most opens never result in the fd being fed to fexecve or mmapped with PROT_EXEC, so having userland explicitly opt-in to allowing that during the open sounds like a reasonable thing to do. But I get that preventing execution via script interpreters of files that are not executable might be something nice to have. Perhaps we need two flags for openat2? OA2_MAYEXEC : test that permissions allow execution and that the file doesn't reside on a noexec mount before allowing the open OA2_EXECABLE : only allow fexecve or mmapping with PROT_EXEC if the fd was opened with this
> On Sep 6, 2019, at 1:51 PM, Jeff Layton <jlayton@kernel.org> wrote: > > On Fri, 2019-09-06 at 13:06 -0700, Andy Lutomirski wrote: > >> I’m not at all convinced that the kernel needs to distinguish all these, but at least upgradability should be its own thing IMO. > > Good point. Upgradability is definitely orthogonal, though the idea > there is to alter the default behavior. If the default is NOEXEC then > UPGRADE_EXEC would make sense. > > In any case, I was mostly thinking about the middle two in your list > above. After more careful reading of the patches, I now get get that > Mickaël is more interested in the first, and that's really a different > sort of use-case. > > Most opens never result in the fd being fed to fexecve or mmapped with > PROT_EXEC, so having userland explicitly opt-in to allowing that during > the open sounds like a reasonable thing to do. > > But I get that preventing execution via script interpreters of files > that are not executable might be something nice to have. > > Perhaps we need two flags for openat2? > > OA2_MAYEXEC : test that permissions allow execution and that the file > doesn't reside on a noexec mount before allowing the open > > OA2_EXECABLE : only allow fexecve or mmapping with PROT_EXEC if the fd > was opened with this > > > We could go one step farther and have three masks: check_perms, fd_perms, and upgrade_perms. check_perms says “fail if I don’t have these perms”. fd_perms is the permissions on the returned fd, and upgrade_perms is the upgrade mask. (fd_perms & ~check_perms) != 0 is an error. This makes it possible to say "I want to make sure the file is writable, but I don't actually want to write to it", which could plausibly be useful. I would argue that these things should have new, sane bits, e.g. FILE_READ, FILE_WRITE, and FILE_EXECUTE (or maybe FILE_MAP_EXEC and FILE_EXECVE). And maybe there should be at least 16 bits for each mask reserved. Windows has a lot more mode bits than Linux, and it's not entirely nuts. We do *not* need any direct equivalent of O_RDWR for openat2(). --Andy
On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > On Sat, 2019-09-07 at 03:13 +1000, Aleksa Sarai wrote: > > On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > > > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > > > while still being able to run on older kernels. > > > > > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > > > with EINVAL, try again without O_MAYEXEC? > > > > > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > > > older kernel to use O_MAYEXEC. > > > > > > > > > > Well...maybe. What about existing programs that are sending down bogus > > > open flags? Once you turn this on, they may break...or provide a way to > > > circumvent the protections this gives. > > > > It should be noted that this has been a valid concern for every new O_* > > flag introduced (and yet we still introduced new flags, despite the > > concern) -- though to be fair, O_TMPFILE actually does have a > > work-around with the O_DIRECTORY mask setup. > > > > The openat2() set adds O_EMPTYPATH -- though in fairness it's also > > backwards compatible because empty path strings have always given ENOENT > > (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. > > > > > Maybe this should be a new flag that is only usable in the new openat2() > > > syscall that's still under discussion? That syscall will enforce that > > > all flags are recognized. You presumably wouldn't need the sysctl if you > > > went that route too. > > > > I'm also interested in whether we could add an UPGRADE_NOEXEC flag to > > how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for > > it, since I'd heard about this work through the grape-vine). > > > > I rather like the idea of having openat2 fds be non-executable by > default, and having userland request it specifically via O_MAYEXEC (or > some similar openat2 flag) if it's needed. Then you could add an > UPGRADE_EXEC flag instead? > > That seems like something reasonable to do with a brand new API, and > might be very helpful for preventing certain classes of attacks. In that case, maybe openat2(2) should default to not allowing any upgrades by default? The reason I pitched UPGRADE_NOEXEC is because UPGRADE_NO{READ,WRITE} are the existing @how->upgrade_mask flags. However, I just noticed something else about this series -- if you do O_PATH|O_MAYEXEC the new flag gets ignored. Given that you can do fexecve(2) on an O_PATH (and O_PATHs have some other benefits), is this something that we'd want to have?
On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > On Fri, 2019-09-06 at 13:06 -0700, Andy Lutomirski wrote: > > > On Sep 6, 2019, at 12:43 PM, Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > On Sat, 2019-09-07 at 03:13 +1000, Aleksa Sarai wrote: > > > > > On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > > > > > > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > > > > > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > > > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > > > > > while still being able to run on older kernels. > > > > > > > > > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > > > > > with EINVAL, try again without O_MAYEXEC? > > > > > > > > > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > > > > > older kernel to use O_MAYEXEC. > > > > > > > > > > > > > > > > Well...maybe. What about existing programs that are sending down bogus > > > > > open flags? Once you turn this on, they may break...or provide a way to > > > > > circumvent the protections this gives. > > > > > > > > It should be noted that this has been a valid concern for every new O_* > > > > flag introduced (and yet we still introduced new flags, despite the > > > > concern) -- though to be fair, O_TMPFILE actually does have a > > > > work-around with the O_DIRECTORY mask setup. > > > > > > > > The openat2() set adds O_EMPTYPATH -- though in fairness it's also > > > > backwards compatible because empty path strings have always given ENOENT > > > > (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. > > > > > > > > > Maybe this should be a new flag that is only usable in the new openat2() > > > > > syscall that's still under discussion? That syscall will enforce that > > > > > all flags are recognized. You presumably wouldn't need the sysctl if you > > > > > went that route too. > > > > > > > > I'm also interested in whether we could add an UPGRADE_NOEXEC flag to > > > > how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for > > > > it, since I'd heard about this work through the grape-vine). > > > > > > > > > > I rather like the idea of having openat2 fds be non-executable by > > > default, and having userland request it specifically via O_MAYEXEC (or > > > some similar openat2 flag) if it's needed. Then you could add an > > > UPGRADE_EXEC flag instead? > > > > > > That seems like something reasonable to do with a brand new API, and > > > might be very helpful for preventing certain classes of attacks. > > > > > > > > > > There are at least four concepts of executability here: > > > > - Just check the file mode and any other relevant permissions. Return a normal fd. Makes sense for script interpreters, perhaps. > > > > - Make the fd fexecve-able. > > > > - Make the resulting fd mappable PROT_EXEC. > > > > - Make the resulting fd upgradable. > > > > I’m not at all convinced that the kernel needs to distinguish all these, but at least upgradability should be its own thing IMO. > > Good point. Upgradability is definitely orthogonal, though the idea > there is to alter the default behavior. If the default is NOEXEC then > UPGRADE_EXEC would make sense. > > In any case, I was mostly thinking about the middle two in your list > above. After more careful reading of the patches, I now get get that > Mickaël is more interested in the first, and that's really a different > sort of use-case. > > Most opens never result in the fd being fed to fexecve or mmapped with > PROT_EXEC, so having userland explicitly opt-in to allowing that during > the open sounds like a reasonable thing to do. > > But I get that preventing execution via script interpreters of files > that are not executable might be something nice to have. My first glance at the patch lead me to believe that this was about blocking at fexecve()-time (which was what my first attempt at this problem looked like) -- hence why I mentioned the upgrade_mask stuff (because of the dances you can do with O_PATH, if blocking at fexecve()-time was the goal then you seriously do need the upgrade_mask and "O_PATH mask" in order for it to be even slightly secure). But I also agree this is useful, and we can always add FMODE_EXEC, FMODE_MAP_EXEC, and FMODE_UPGRADE_EXEC (and the related bits) at a later date. > Perhaps we need two flags for openat2? > > OA2_MAYEXEC : test that permissions allow execution and that the file > doesn't reside on a noexec mount before allowing the open > > OA2_EXECABLE : only allow fexecve or mmapping with PROT_EXEC if the fd > was opened with this That seems reasonable to me. The only thing is that there currently isn't any code to restrict fexecve() or PROT_EXEC in that fashion (doubly so when you consider binfmt_script). So if we want to make certain things default behaviour (such as disallowing exec by default) we'd need to get the PROT_EXEC restriction work done first.
On 2019-09-07, Aleksa Sarai <cyphar@cyphar.com> wrote: > On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > > On Sat, 2019-09-07 at 03:13 +1000, Aleksa Sarai wrote: > > > On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: > > > > On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: > > > > > On 06/09/2019 17:56, Florian Weimer wrote: > > > > > > Let's assume I want to add support for this to the glibc dynamic loader, > > > > > > while still being able to run on older kernels. > > > > > > > > > > > > Is it safe to try the open call first, with O_MAYEXEC, and if that fails > > > > > > with EINVAL, try again without O_MAYEXEC? > > > > > > > > > > The kernel ignore unknown open(2) flags, so yes, it is safe even for > > > > > older kernel to use O_MAYEXEC. > > > > > > > > > > > > > Well...maybe. What about existing programs that are sending down bogus > > > > open flags? Once you turn this on, they may break...or provide a way to > > > > circumvent the protections this gives. > > > > > > It should be noted that this has been a valid concern for every new O_* > > > flag introduced (and yet we still introduced new flags, despite the > > > concern) -- though to be fair, O_TMPFILE actually does have a > > > work-around with the O_DIRECTORY mask setup. > > > > > > The openat2() set adds O_EMPTYPATH -- though in fairness it's also > > > backwards compatible because empty path strings have always given ENOENT > > > (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. > > > > > > > Maybe this should be a new flag that is only usable in the new openat2() > > > > syscall that's still under discussion? That syscall will enforce that > > > > all flags are recognized. You presumably wouldn't need the sysctl if you > > > > went that route too. > > > > > > I'm also interested in whether we could add an UPGRADE_NOEXEC flag to > > > how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for > > > it, since I'd heard about this work through the grape-vine). > > > > > > > I rather like the idea of having openat2 fds be non-executable by > > default, and having userland request it specifically via O_MAYEXEC (or > > some similar openat2 flag) if it's needed. Then you could add an > > UPGRADE_EXEC flag instead? > > > > That seems like something reasonable to do with a brand new API, and > > might be very helpful for preventing certain classes of attacks. > > In that case, maybe openat2(2) should default to not allowing any > upgrades by default? The reason I pitched UPGRADE_NOEXEC is because > UPGRADE_NO{READ,WRITE} are the existing @how->upgrade_mask flags. Sorry, another issue is that there isn't a current way to really restrict fexecve() permissions (from my [limited] understanding, __FMODE_EXEC isn't the right thing to use) -- so we can't blanket block exec through openat2() O_PATH descriptors and add UPGRADE_EXEC later. We would have to implement FMODE_EXEC (and FMODE_MAP_EXEC as you suggested) in order to implement FMODE_UPGRADE_EXEC before we could even get a first version of openat2(2) in. Though, I do (a little begrudgingly) agree that we should have a safe default if possible (magical O_PATH reopening trickery is something that most people don't know about and probably wouldn't want to happen if they did).
On 06/09/2019 20:41, Andy Lutomirski wrote: > > >> On Sep 6, 2019, at 11:38 AM, Jeff Layton <jlayton@kernel.org> wrote: >> >>> On Fri, 2019-09-06 at 19:14 +0200, Mickaël Salaün wrote: >>>> On 06/09/2019 18:48, Jeff Layton wrote: >>>>> On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: >>>>>> On 06/09/2019 17:56, Florian Weimer wrote: >>>>>> Let's assume I want to add support for this to the glibc dynamic loader, >>>>>> while still being able to run on older kernels. >>>>>> >>>>>> Is it safe to try the open call first, with O_MAYEXEC, and if that fails >>>>>> with EINVAL, try again without O_MAYEXEC? >>>>> >>>>> The kernel ignore unknown open(2) flags, so yes, it is safe even for >>>>> older kernel to use O_MAYEXEC. >>>>> >>>> >>>> Well...maybe. What about existing programs that are sending down bogus >>>> open flags? Once you turn this on, they may break...or provide a way to >>>> circumvent the protections this gives. >>> >>> Well, I don't think we should nor could care about bogus programs that >>> do not conform to the Linux ABI. >>> >> >> But they do conform. The ABI is just undefined here. Unknown flags are >> ignored so we never really know if $random_program may be setting them. >> >>>> Maybe this should be a new flag that is only usable in the new openat2() >>>> syscall that's still under discussion? That syscall will enforce that >>>> all flags are recognized. You presumably wouldn't need the sysctl if you >>>> went that route too. >>> >>> Here is a thread about a new syscall: >>> https://lore.kernel.org/lkml/1544699060.6703.11.camel@linux.ibm.com/ >>> >>> I don't think it fit well with auditing nor integrity. Moreover using >>> the current open(2) behavior of ignoring unknown flags fit well with the >>> usage of O_MAYEXEC (because it is only a hint to the kernel about the >>> use of the *opened* file). >>> >> >> The fact that open and openat didn't vet unknown flags is really a bug. >> >> Too late to fix it now, of course, and as Aleksa points out, we've >> worked around that in the past. Now though, we have a new openat2 >> syscall on the horizon. There's little need to continue these sorts of >> hacks. >> >> New open flags really have no place in the old syscalls, IMO. >> >>>> Anyone that wants to use this will have to recompile anyway. If the >>>> kernel doesn't support openat2 or if the flag is rejected then you know >>>> that you have no O_MAYEXEC support and can decide what to do. >>> >>> If we want to enforce a security policy, we need to either be the system >>> administrator or the distro developer. If a distro ship interpreters >>> using this flag, we don't need to recompile anything, but we need to be >>> able to control the enforcement according to the mount point >>> configuration (or an advanced MAC, or an IMA config). I don't see why an >>> userspace process should check if this flag is supported or not, it >>> should simply use it, and the sysadmin will enable an enforcement if it >>> makes sense for the whole system. >>> >> >> A userland program may need to do other risk mitigation if it sets >> O_MAYEXEC and the kernel doesn't recognize it. >> >> Personally, here's what I'd suggest: >> >> - Base this on top of the openat2 set >> - Change it that so that openat2() files are non-executable by default. Anyone wanting to do that needs to set O_MAYEXEC or upgrade the fd somehow. >> - Only have the openat2 syscall pay attention to O_MAYEXEC. Let open and openat continue ignoring the new flag. >> >> That works around a whole pile of potential ABI headaches. Note that >> we'd need to make that decision before the openat2 patches are merged. >> >> Even better would be to declare the new flag in some openat2-only flag >> space, so there's no confusion about it being supported by legacy open >> calls. >> >> If glibc wants to implement an open -> openat2 wrapper in userland >> later, it can set that flag in the wrapper implicitly to emulate the old >> behavior. >> >> Given that you're going to have to recompile software to take advantage >> of this anyway, what's the benefit to changing legacy syscalls? >> >>>>>> Or do I risk disabling this security feature if I do that? >>>>> >>>>> It is only a security feature if the kernel support it, otherwise it is >>>>> a no-op. >>>>> >>>> >>>> With a security feature, I think we really want userland to aware of >>>> whether it works. >>> >>> If userland would like to enforce something, it can already do it >>> without any kernel modification. The goal of the O_MAYEXEC flag is to >>> enable the kernel, hence sysadmins or system designers, to enforce a >>> global security policy that makes sense. >>> >> >> I don't see how this helps anything if you can't tell whether the kernel >> recognizes the damned thing. Also, our track record with global sysctl >> switches like this is pretty poor. They're an administrative headache as >> well as a potential attack vector. > > I tend to agree. The sysctl seems like it’s asking for trouble. I can see an ld.so.conf option to turn this thing off making sense. The sysctl is required to enable the adoption of this flag without breaking existing systems. Current systems may have "noexec" on mount points containing scripts. Without giving the ability to the sysadmin to control that behavior, updating to a newer version of an interpreter using O_MAYEXEC may break such systems. How would you do this with ld.so.conf ? -- Mickaël Salaün Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On 06/09/2019 21:03, James Morris wrote: > On Fri, 6 Sep 2019, Jeff Layton wrote: > >> The fact that open and openat didn't vet unknown flags is really a bug. >> >> Too late to fix it now, of course, and as Aleksa points out, we've >> worked around that in the past. Now though, we have a new openat2 >> syscall on the horizon. There's little need to continue these sorts of >> hacks. >> >> New open flags really have no place in the old syscalls, IMO. > > Agree here. It's unfortunate but a reality and Linus will reject any such > changes which break existing userspace. Do you mean that adding new flags to open(2) is not possible? Does it means that unspecified behaviors are definitely part of the Linux specification and can't be fixed? As I said, O_MAYEXEC should be ignored if it is not supported by the kernel, which perfectly fit with the current open(2) flags behavior, and should also behave the same with openat2(2). -- Mickaël Salaün Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On 06/09/2019 22:06, Andy Lutomirski wrote: > > >> On Sep 6, 2019, at 12:43 PM, Jeff Layton <jlayton@kernel.org> wrote: >> >>> On Sat, 2019-09-07 at 03:13 +1000, Aleksa Sarai wrote: >>>> On 2019-09-06, Jeff Layton <jlayton@kernel.org> wrote: >>>>> On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: >>>>>> On 06/09/2019 17:56, Florian Weimer wrote: >>>>>> Let's assume I want to add support for this to the glibc dynamic loader, >>>>>> while still being able to run on older kernels. >>>>>> >>>>>> Is it safe to try the open call first, with O_MAYEXEC, and if that fails >>>>>> with EINVAL, try again without O_MAYEXEC? >>>>> >>>>> The kernel ignore unknown open(2) flags, so yes, it is safe even for >>>>> older kernel to use O_MAYEXEC. >>>>> >>>> >>>> Well...maybe. What about existing programs that are sending down bogus >>>> open flags? Once you turn this on, they may break...or provide a way to >>>> circumvent the protections this gives. >>> >>> It should be noted that this has been a valid concern for every new O_* >>> flag introduced (and yet we still introduced new flags, despite the >>> concern) -- though to be fair, O_TMPFILE actually does have a >>> work-around with the O_DIRECTORY mask setup. >>> >>> The openat2() set adds O_EMPTYPATH -- though in fairness it's also >>> backwards compatible because empty path strings have always given ENOENT >>> (or EINVAL?) while O_EMPTYPATH is a no-op non-empty strings. >>> >>>> Maybe this should be a new flag that is only usable in the new openat2() >>>> syscall that's still under discussion? That syscall will enforce that >>>> all flags are recognized. You presumably wouldn't need the sysctl if you >>>> went that route too. >>> >>> I'm also interested in whether we could add an UPGRADE_NOEXEC flag to >>> how->upgrade_mask for the openat2(2) patchset (I reserved a flag bit for >>> it, since I'd heard about this work through the grape-vine). >>> >> >> I rather like the idea of having openat2 fds be non-executable by >> default, and having userland request it specifically via O_MAYEXEC (or >> some similar openat2 flag) if it's needed. Then you could add an >> UPGRADE_EXEC flag instead? >> >> That seems like something reasonable to do with a brand new API, and >> might be very helpful for preventing certain classes of attacks. >> >> > > There are at least four concepts of executability here: > > - Just check the file mode and any other relevant permissions. Return a normal fd. Makes sense for script interpreters, perhaps. This is the purpose of this patch series. It doesn't make sense to add memory restrictions nor constrain fexecve and such. > > - Make the fd fexecve-able. > > - Make the resulting fd mappable PROT_EXEC. > > - Make the resulting fd upgradable. > > I’m not at all convinced that the kernel needs to distinguish all these, but at least upgradability should be its own thing IMO. > -- Mickaël Salaün Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On Mon, 9 Sep 2019, Mickaël Salaün wrote: > > On 06/09/2019 21:03, James Morris wrote: > > On Fri, 6 Sep 2019, Jeff Layton wrote: > > > >> The fact that open and openat didn't vet unknown flags is really a bug. > >> > >> Too late to fix it now, of course, and as Aleksa points out, we've > >> worked around that in the past. Now though, we have a new openat2 > >> syscall on the horizon. There's little need to continue these sorts of > >> hacks. > >> > >> New open flags really have no place in the old syscalls, IMO. > > > > Agree here. It's unfortunate but a reality and Linus will reject any such > > changes which break existing userspace. > > Do you mean that adding new flags to open(2) is not possible? > > Does it means that unspecified behaviors are definitely part of the > Linux specification and can't be fixed? This is my understanding. > > As I said, O_MAYEXEC should be ignored if it is not supported by the > kernel, which perfectly fit with the current open(2) flags behavior, and > should also behave the same with openat2(2). The problem here is programs which are already using the value of O_MAYEXEC, which will break. Hence, openat2(2).
On 09/09/2019 12:12, James Morris wrote: > On Mon, 9 Sep 2019, Mickaël Salaün wrote: > >> >> On 06/09/2019 21:03, James Morris wrote: >>> On Fri, 6 Sep 2019, Jeff Layton wrote: >>> >>>> The fact that open and openat didn't vet unknown flags is really a bug. >>>> >>>> Too late to fix it now, of course, and as Aleksa points out, we've >>>> worked around that in the past. Now though, we have a new openat2 >>>> syscall on the horizon. There's little need to continue these sorts of >>>> hacks. >>>> >>>> New open flags really have no place in the old syscalls, IMO. >>> >>> Agree here. It's unfortunate but a reality and Linus will reject any such >>> changes which break existing userspace. >> >> Do you mean that adding new flags to open(2) is not possible? >> >> Does it means that unspecified behaviors are definitely part of the >> Linux specification and can't be fixed? > > This is my understanding. > >> >> As I said, O_MAYEXEC should be ignored if it is not supported by the >> kernel, which perfectly fit with the current open(2) flags behavior, and >> should also behave the same with openat2(2). > > The problem here is programs which are already using the value of > O_MAYEXEC, which will break. Hence, openat2(2). Well, it still depends on the sysctl, which doesn't enforce anything by default, hence doesn't break existing behavior, and this unused flags could be fixed/removed or reported by sysadmins or distro developers. -- Mickaël Salaün Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On 2019-09-09, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: > On 06/09/2019 21:03, James Morris wrote: > > On Fri, 6 Sep 2019, Jeff Layton wrote: > > > >> The fact that open and openat didn't vet unknown flags is really a bug. > >> > >> Too late to fix it now, of course, and as Aleksa points out, we've > >> worked around that in the past. Now though, we have a new openat2 > >> syscall on the horizon. There's little need to continue these sorts of > >> hacks. > >> > >> New open flags really have no place in the old syscalls, IMO. > > > > Agree here. It's unfortunate but a reality and Linus will reject any such > > changes which break existing userspace. > > Do you mean that adding new flags to open(2) is not possible? It is possible, as long as there is no case where a program that works today (and passes garbage to the unused bits in flags) works with the change. O_TMPFILE was okay because it's actually two flags (one is O_DIRECTORY) and no working program does file IO to a directory (there are also some other tricky things done there, I'll admit I don't fully understand it). O_EMPTYPATH works because it's a no-op with non-empty path strings, and empty path strings have always given an error (so no working program does it today). However, O_MAYEXEC will result in programs that pass garbage bits to potentially get -EACCES that worked previously. > As I said, O_MAYEXEC should be ignored if it is not supported by the > kernel, which perfectly fit with the current open(2) flags behavior, and > should also behave the same with openat2(2). NACK on having that behaviour with openat2(2). -EINVAL on unknown flags is how all other syscalls work (any new syscall proposed today that didn't do that would be rightly rejected), and is a quirk of open(2) which unfortunately cannot be fixed. The fact that *every new O_ flag needs to work around this problem* should be an indication that this interface mis-design should not be allowed to infect any more syscalls. Note that this point is regardless of the fact that O_MAYEXEC is a *security* flag -- if userspace wants to have a secure fallback on old kernels (which is "the right thing" to do) they would have to do more work than necessary. And programs that don't care don't have to do anything special. However with -EINVAL, the programs doing "the right thing" get an easy -EINVAL check. And programs that don't care can just un-set O_MAYEXEC and retry. You should be forced to deal with the case where a flag is not supported -- and this is doubly true of security flags!
On 2019-09-09, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: > On 09/09/2019 12:12, James Morris wrote: > > On Mon, 9 Sep 2019, Mickaël Salaün wrote: > >> As I said, O_MAYEXEC should be ignored if it is not supported by the > >> kernel, which perfectly fit with the current open(2) flags behavior, and > >> should also behave the same with openat2(2). > > > > The problem here is programs which are already using the value of > > O_MAYEXEC, which will break. Hence, openat2(2). > > Well, it still depends on the sysctl, which doesn't enforce anything by > default, hence doesn't break existing behavior, and this unused flags > could be fixed/removed or reported by sysadmins or distro developers. Okay, but then this means that new programs which really want to enforce O_MAYEXEC (and know that they really do want this feature) won't be able to unless an admin has set the relevant sysctl. Not to mention that the old-kernel fallback will not cover the "it's disabled by the sysctl" case -- so the fallback handling would need to be: int fd = open("foo", O_MAYEXEC|O_RDONLY); if (!(fcntl(fd, F_GETFL) & O_MAYEXEC)) fallback(); if (!sysctl_feature_is_enabled) fallback(); However, there is still a race here -- if an administrator enables O_MAYEXEC after the program gets the fd, then you still won't hit the fallback (and you can't tell that O_MAYEXEC checks weren't done). You could fix the issue with the sysctl by clearing O_MAYEXEC from f_flags if the sysctl is disabled. You could also avoid some of the problems with it being a global setting by making it a prctl(2) which processes can opt-in to (though this has its own major problems). Sorry, but I'm just really not a fan of this.
On 09/09/2019 13:54, Aleksa Sarai wrote: > On 2019-09-09, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: >> On 06/09/2019 21:03, James Morris wrote: >>> On Fri, 6 Sep 2019, Jeff Layton wrote: >>> >>>> The fact that open and openat didn't vet unknown flags is really a bug. >>>> >>>> Too late to fix it now, of course, and as Aleksa points out, we've >>>> worked around that in the past. Now though, we have a new openat2 >>>> syscall on the horizon. There's little need to continue these sorts of >>>> hacks. >>>> >>>> New open flags really have no place in the old syscalls, IMO. >>> >>> Agree here. It's unfortunate but a reality and Linus will reject any such >>> changes which break existing userspace. >> >> Do you mean that adding new flags to open(2) is not possible? > > It is possible, as long as there is no case where a program that works > today (and passes garbage to the unused bits in flags) works with the > change. > > O_TMPFILE was okay because it's actually two flags (one is O_DIRECTORY) > and no working program does file IO to a directory (there are also some > other tricky things done there, I'll admit I don't fully understand it). > > O_EMPTYPATH works because it's a no-op with non-empty path strings, and > empty path strings have always given an error (so no working program > does it today). > > However, O_MAYEXEC will result in programs that pass garbage bits to > potentially get -EACCES that worked previously. > >> As I said, O_MAYEXEC should be ignored if it is not supported by the >> kernel, which perfectly fit with the current open(2) flags behavior, and >> should also behave the same with openat2(2). > > NACK on having that behaviour with openat2(2). -EINVAL on unknown flags > is how all other syscalls work (any new syscall proposed today that > didn't do that would be rightly rejected), and is a quirk of open(2) > which unfortunately cannot be fixed. The fact that *every new O_ flag > needs to work around this problem* should be an indication that this > interface mis-design should not be allowed to infect any more syscalls. It's definitely OK (and a sane interface) to always return -EINVAL for unknown flags with openat2(2) (and other new syscalls). With openat2(2), userland need to handle the case where some flags may be unknown to the kernel (and handling the fact that this syscall may be unknown too). So there is not an issue with openat2(2). However, *userland* should not try to infer possible security restrictions from the O_MAYEXEC flag (then, my use of "ignore" above), which may return -EACCES or not, according to the current running system security policy. Following this reasoning, the current behavior or open(2) is fine for O_MAYEXEC. The openat2(2) strict flag handling (i.e. -EINVAL) is fine too for O_MAYEXEC. > > Note that this point is regardless of the fact that O_MAYEXEC is a > *security* flag -- if userspace wants to have a secure fallback on > old kernels (which is "the right thing" to do) they would have to do > more work than necessary. And programs that don't care don't have to do > anything special. Most of the time this reasoning is good for most security stuff. However, the O_MAYEXEC flag is not a security feature on its own, it is an indication to the kernel to how this file would be used by userland. The *kernel* security policy may tell back to userland if the system security policy allow it or not. Most of the time, Policy Decision Points (PDP) and Policy Enforcement Points (PEP) are in the same software component (e.g. the kernel). Here the kernel is the PDP and userland interpreters are PDP. Obviously, it means that these interpreters must be (sub)part of your TCB (thanks to other security features). > > However with -EINVAL, the programs doing "the right thing" get an easy > -EINVAL check. And programs that don't care can just un-set O_MAYEXEC > and retry. You should be forced to deal with the case where a flag is > not supported -- and this is doubly true of security flags! I'm in favor of doing this for openat2(2) with O_MAYEXEC, but it is not because of the "security purposes" of this flag, as I said above, it is because it is a saner ABI that every syscall should follow. But again, it doesn't change my point about open(2). :) -- Mickaël Salaün Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
On 09/09/2019 14:28, Aleksa Sarai wrote: > On 2019-09-09, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: >> On 09/09/2019 12:12, James Morris wrote: >>> On Mon, 9 Sep 2019, Mickaël Salaün wrote: >>>> As I said, O_MAYEXEC should be ignored if it is not supported by the >>>> kernel, which perfectly fit with the current open(2) flags behavior, and >>>> should also behave the same with openat2(2). >>> >>> The problem here is programs which are already using the value of >>> O_MAYEXEC, which will break. Hence, openat2(2). >> >> Well, it still depends on the sysctl, which doesn't enforce anything by >> default, hence doesn't break existing behavior, and this unused flags >> could be fixed/removed or reported by sysadmins or distro developers. > > Okay, but then this means that new programs which really want to enforce > O_MAYEXEC (and know that they really do want this feature) won't be able > to unless an admin has set the relevant sysctl. Not to mention that the > old-kernel fallback will not cover the "it's disabled by the sysctl" > case -- so the fallback handling would need to be: > > int fd = open("foo", O_MAYEXEC|O_RDONLY); > if (!(fcntl(fd, F_GETFL) & O_MAYEXEC)) > fallback(); > if (!sysctl_feature_is_enabled) > fallback(); > > However, there is still a race here -- if an administrator enables > O_MAYEXEC after the program gets the fd, then you still won't hit the > fallback (and you can't tell that O_MAYEXEC checks weren't done). I just replied to this concern here: https://lore.kernel.org/lkml/70e4244e-4dfb-6e67-416b-445e383aa1b5@ssi.gouv.fr/ > > You could fix the issue with the sysctl by clearing O_MAYEXEC from > f_flags if the sysctl is disabled. You could also avoid some of the > problems with it being a global setting by making it a prctl(2) which > processes can opt-in to (though this has its own major problems). Security definition and enforcement should be manageable by sysadmins and distro developers. > > Sorry, but I'm just really not a fan of this. I guess there is some misunderstanding. I just replied to another thread and I think it should answer your concerns (especially about the PDP and PEP): https://lore.kernel.org/lkml/70e4244e-4dfb-6e67-416b-445e383aa1b5@ssi.gouv.fr/ -- Mickaël Salaün Les données à caractère personnel recueillies et traitées dans le cadre de cet échange, le sont à seule fin d’exécution d’une relation professionnelle et s’opèrent dans cette seule finalité et pour la durée nécessaire à cette relation. Si vous souhaitez faire usage de vos droits de consultation, de rectification et de suppression de vos données, veuillez contacter contact.rgpd@sgdsn.gouv.fr. Si vous avez reçu ce message par erreur, nous vous remercions d’en informer l’expéditeur et de détruire le message. The personal data collected and processed during this exchange aims solely at completing a business relationship and is limited to the necessary duration of that relationship. If you wish to use your rights of consultation, rectification and deletion of your data, please contact: contact.rgpd@sgdsn.gouv.fr. If you have received this message in error, we thank you for informing the sender and destroying the message.
> On Sep 9, 2019, at 2:18 AM, Mickaël Salaün <mickael.salaun@ssi.gouv.fr> wrote: > > >> On 06/09/2019 20:41, Andy Lutomirski wrote: >> >> >>>> On Sep 6, 2019, at 11:38 AM, Jeff Layton <jlayton@kernel.org> wrote: >>>> >>>>> On Fri, 2019-09-06 at 19:14 +0200, Mickaël Salaün wrote: >>>>>> On 06/09/2019 18:48, Jeff Layton wrote: >>>>>>> On Fri, 2019-09-06 at 18:06 +0200, Mickaël Salaün wrote: >>>>>>> On 06/09/2019 17:56, Florian Weimer wrote: >>>>>>> Let's assume I want to add support for this to the glibc dynamic loader, >>>>>>> while still being able to run on older kernels. >>>>>>> >>>>>>> Is it safe to try the open call first, with O_MAYEXEC, and if that fails >>>>>>> with EINVAL, try again without O_MAYEXEC? >>>>>> >>>>>> The kernel ignore unknown open(2) flags, so yes, it is safe even for >>>>>> older kernel to use O_MAYEXEC. >>>>>> >>>>> >>>>> Well...maybe. What about existing programs that are sending down bogus >>>>> open flags? Once you turn this on, they may break...or provide a way to >>>>> circumvent the protections this gives. >>>> >>>> Well, I don't think we should nor could care about bogus programs that >>>> do not conform to the Linux ABI. >>>> >>> >>> But they do conform. The ABI is just undefined here. Unknown flags are >>> ignored so we never really know if $random_program may be setting them. >>> >>>>> Maybe this should be a new flag that is only usable in the new openat2() >>>>> syscall that's still under discussion? That syscall will enforce that >>>>> all flags are recognized. You presumably wouldn't need the sysctl if you >>>>> went that route too. >>>> >>>> Here is a thread about a new syscall: >>>> https://lore.kernel.org/lkml/1544699060.6703.11.camel@linux.ibm.com/ >>>> >>>> I don't think it fit well with auditing nor integrity. Moreover using >>>> the current open(2) behavior of ignoring unknown flags fit well with the >>>> usage of O_MAYEXEC (because it is only a hint to the kernel about the >>>> use of the *opened* file). >>>> >>> >>> The fact that open and openat didn't vet unknown flags is really a bug. >>> >>> Too late to fix it now, of course, and as Aleksa points out, we've >>> worked around that in the past. Now though, we have a new openat2 >>> syscall on the horizon. There's little need to continue these sorts of >>> hacks. >>> >>> New open flags really have no place in the old syscalls, IMO. >>> >>>>> Anyone that wants to use this will have to recompile anyway. If the >>>>> kernel doesn't support openat2 or if the flag is rejected then you know >>>>> that you have no O_MAYEXEC support and can decide what to do. >>>> >>>> If we want to enforce a security policy, we need to either be the system >>>> administrator or the distro developer. If a distro ship interpreters >>>> using this flag, we don't need to recompile anything, but we need to be >>>> able to control the enforcement according to the mount point >>>> configuration (or an advanced MAC, or an IMA config). I don't see why an >>>> userspace process should check if this flag is supported or not, it >>>> should simply use it, and the sysadmin will enable an enforcement if it >>>> makes sense for the whole system. >>>> >>> >>> A userland program may need to do other risk mitigation if it sets >>> O_MAYEXEC and the kernel doesn't recognize it. >>> >>> Personally, here's what I'd suggest: >>> >>> - Base this on top of the openat2 set >>> - Change it that so that openat2() files are non-executable by default. Anyone wanting to do that needs to set O_MAYEXEC or upgrade the fd somehow. >>> - Only have the openat2 syscall pay attention to O_MAYEXEC. Let open and openat continue ignoring the new flag. >>> >>> That works around a whole pile of potential ABI headaches. Note that >>> we'd need to make that decision before the openat2 patches are merged. >>> >>> Even better would be to declare the new flag in some openat2-only flag >>> space, so there's no confusion about it being supported by legacy open >>> calls. >>> >>> If glibc wants to implement an open -> openat2 wrapper in userland >>> later, it can set that flag in the wrapper implicitly to emulate the old >>> behavior. >>> >>> Given that you're going to have to recompile software to take advantage >>> of this anyway, what's the benefit to changing legacy syscalls? >>> >>>>>>> Or do I risk disabling this security feature if I do that? >>>>>> >>>>>> It is only a security feature if the kernel support it, otherwise it is >>>>>> a no-op. >>>>>> >>>>> >>>>> With a security feature, I think we really want userland to aware of >>>>> whether it works. >>>> >>>> If userland would like to enforce something, it can already do it >>>> without any kernel modification. The goal of the O_MAYEXEC flag is to >>>> enable the kernel, hence sysadmins or system designers, to enforce a >>>> global security policy that makes sense. >>>> >>> >>> I don't see how this helps anything if you can't tell whether the kernel >>> recognizes the damned thing. Also, our track record with global sysctl >>> switches like this is pretty poor. They're an administrative headache as >>> well as a potential attack vector. >> >> I tend to agree. The sysctl seems like it’s asking for trouble. I can see an ld.so.conf option to turn this thing off making sense. > > The sysctl is required to enable the adoption of this flag without > breaking existing systems. Current systems may have "noexec" on mount > points containing scripts. Without giving the ability to the sysadmin to > control that behavior, updating to a newer version of an interpreter > using O_MAYEXEC may break such systems. > > How would you do this with ld.so.conf ? > By telling user code not to use O_MAYEXEC? Alternatively, you could allow O_MAYEXEC even on a noexec mount and have a strong_noexec option that blocks it.
diff --git a/fs/fcntl.c b/fs/fcntl.c index 3d40771e8e7c..4cf05a2fd162 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -1031,7 +1031,7 @@ static int __init fcntl_init(void) * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ - BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != + BUILD_BUG_ON(22 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | __FMODE_EXEC | __FMODE_NONOTIFY)); diff --git a/fs/open.c b/fs/open.c index a59abe3c669a..1b9b6fedf7cd 100644 --- a/fs/open.c +++ b/fs/open.c @@ -989,6 +989,12 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o acc_mode = 0; } + /* Check execution permissions on open. */ + if (flags & O_MAYEXEC) { + acc_mode |= MAY_OPENEXEC; + flags |= __FMODE_EXEC; + } + op->open_flag = flags; /* O_TRUNC implies we need access checks for write permissions */ diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index d019df946cb2..af88fb6c8313 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h @@ -9,7 +9,7 @@ (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \ FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_MAYEXEC) #ifndef force_o_largefile #define force_o_largefile() (!IS_ENABLED(CONFIG_ARCH_32BIT_OFF_T)) diff --git a/include/linux/fs.h b/include/linux/fs.h index 997a530ff4e9..848f5711bdf0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -99,6 +99,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define MAY_CHDIR 0x00000040 /* called from RCU mode, don't block */ #define MAY_NOT_BLOCK 0x00000080 +/* the inode is opened with O_MAYEXEC */ +#define MAY_OPENEXEC 0x00000100 /* * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 9dc0bf0c5a6e..cbb9425d6e7c 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -97,6 +97,9 @@ #define O_NDELAY O_NONBLOCK #endif +/* command execution from file is intended, check exec permissions */ +#define O_MAYEXEC 040000000 + #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ #define F_SETFD 2 /* set/clear close_on_exec */