Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 12/14/15 12:17 AM, Mike Frysinger wrote: > > (1) the examples i already provided do not involve the user at all, and > include systems where the user has no direct access to the shell. You didn't really provide any examples. You mentioned ChromeOS and vaguely referenced "other verified boot systems". If non-general-purpose systems is the set of systems for which this proposal is in scope, that changes the impact. Since you generally build custom versions for such systems, a configuration-time option to enable this behavior is more reasonable. > (2) choice over runtime functionality is by the sysadmin, not the user. In this case, or in general? > (3) i disagree over the scope of noexec. i think this is in-scope. I really don't agree that it's in the spirit of noexec. - -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/ -BEGIN PGP SIGNATURE- Version: GnuPG v2 iEUEARECAAYFAlZxyEoACgkQu1hp8GTqdKs7iwCeN3RSffaijMfXrzceHrbksjXE W1oAl0qJHWNo/qNu0cOijRbbNEzDJt4= =kLgz -END PGP SIGNATURE-
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 12/14/15 12:32 AM, Mike Frysinger wrote: > On 13 Dec 2015 17:24, Chet Ramey wrote: >> On 12/12/15 4:01 PM, Mike Frysinger wrote: >>> Today, if you have a script that lives on a noexec mount point, the >>> kernel will reject attempts to run it directly: >>> $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh >>> $ chmod a+rx /dev/shm/test.sh >>> $ /dev/shm/test.sh >>> bash: /dev/shm/test.sh: Permission denied >>> >>> But bash itself has no problem running this file: >> >> It's hard to see how this proposal improves overall system security. Th ere >> are a dozen ways a minimally-competent attacker can circumvent it. > > you're assuming the attacker has unlimited access to resources and contro l > over the environment and execution. Of course -- that's the general case. You're talking about changes to a general tool installed in such environments. > i already noted there are ways to run > arbitrary code -- when you have arbitrary code access. there also are ca ses > (such as i described) which this change would block attacks because the > attacker does not have such unfettered access. they're leveraging a smal l > bug elsewhere to escalate to a fuller environment. What's the intended set of systems for which this would be useful? >> A worse problem is that the abstraction is in the wrong place. The shel l, >> like other programs, requests services from the kernel to do things. Th e >> kernel is the arbiter of restrictions on those services. If asked to >> execute a file, the shell asks the kernel whether the file is executable , >> then tries to execute it. If asked to read a file, the shell tries to >> open it. The kernel, or some agent it invokes, is where the access >> decision is made. If you want to, for instance, disallow the shell and >> other utilities from opening executable files for reading on file system s >> with noexec set, the shell binary is not the place to embed that policy. > > i'm aware of the fundamental structure of UNIX-like systems. Yes, I know you are. I'm placing my point in context. > bash itself > is providing services to a program by executing the requested code I suppose you can make that argument, but I don't think it fits within what I understand the intent of `noexec' to be. > and in > a sense, has a responsibility to control that. otherwise, you seem to be > arguing against the existence of rbash, or job control, or similar shell > limiting/control functionality. I actually think rbash is kind of useless. In the case of job control, or ulimit, or trap, or cd, the shell is exposing kernel functionality to the user and allowing him to access it. > i understand this is a disruptive change. how about making it a compile > time flag, or perhaps a new shopt ? It depends on the set of intended target systems and the users' scope of access to the entire system. On some captive system like a chromebook or a linux-based video player (like an airplane seat-back player, for instance), I can see a compile-time flag making sense. I don't think this has a place on a general-purpose user system. - -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/ -BEGIN PGP SIGNATURE- Version: GnuPG v2 iEYEARECAAYFAlZxzE0ACgkQu1hp8GTqdKv0bACfb3m6AM0N59cQZJkWe3GYFwKb Ic0An28bMKeihs7sVsfG9EXoFCB0MGmH =ALQH -END PGP SIGNATURE-
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 12/16/15 3:29 PM, John McKown wrote: > FWIW (not much), I'm going to go with Chet on this. It may be my ignorance > speaking, but what can I do in a BASH shell script which I cannot do (at > all) just by entering the commands by hand? That's where the scope of the proposal makes a difference. If it's intended for captive systems where the user does not have direct access to the shell or the file system, that's a different thing than a general purpose system. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 12/15/15 4:53 AM, konsolebox wrote: > Ok I accept your point. So it's actually about `source` and `bash > file`, correct? So would this mean every script I `source` would need > +x bit now? And if it's not about the +x bit and only about `noexec`, > would stuff I place that I would want to not execute (with execve(), > etc.) in a `noexec` directory no longer be `source`-able, even though > I'm still wanting those to be `source`-d? `source` is meant to only > require readable permission. Correct. If this were to be in effect, anything that you wanted to source would fail if the file to be read were on a file system mounted noexec. > You complicate it. I'm both a user and an administrator to my > personal system and I don't want that function running by default in > my bash. Simple. This raises the queation of the set of systems to which this is intended to apply. It's clearly inappropriate for general-purpose Unix/Linux systems, but single-purpose systems on which the user does not have access to the file system or the shell are a different story. > The thing is, you're trying to implement the concept of `noexec` in > the application level. You're making use of `noexec` as a flag to > make bash restrict itself from `source`-ing scripts located on a mount > point or directory with such attribute. `noexec` (and the kernel that > implements `noexec`) really has nothing to do with it. You're just > trying to -extend- the scope of `noexec` to applications. That is the > inconsistency which is clear. You're just wanting bash to behave > based on its concept, and not really based on a rule of a system or a > particular system feature. This is true. The question is whether or not your mental model of how `noexec' should work includes this case. It's clearly true that the proposal embeds policy in the bash binary. Whether or not that policy is appropriate depends on your answer to the previous question. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On Tue, Dec 15, 2015 at 7:30 AM, Mike Frysingerwrote: > On 15 Dec 2015 06:47, konsolebox wrote: >> t On Mon, Dec 14, 2015 at 1:17 PM, Mike Frysinger wrote: >> > On 13 Dec 2015 16:50, konsolebox wrote: >> >> On Sun, Dec 13, 2015 at 5:01 AM, Mike Frysinger wrote: >> >> > Today, if you have a script that lives on a noexec mount point, the >> >> > kernel will reject attempts to run it directly: >> >> > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh >> >> > $ chmod a+rx /dev/shm/test.sh >> >> > $ /dev/shm/test.sh >> >> > bash: /dev/shm/test.sh: Permission denied >> >> > >> >> > But bash itself has no problem running this file: >> >> > $ bash /dev/shm/test.sh >> >> > hi >> >> > Or with letting other scripts run this file: >> >> > $ bash -c '. /dev/shm/test.sh' >> >> > hi >> >> > Or with reading the script from stdin: >> >> > $ bash > >> > hi >> >> > >> >> > This detracts from the security of the overall system. People writing >> >> > scripts sometimes want to save/restore state (s) and will >> >> > restore the content from a noexec point using the aforementioned source >> >> > command without realizing that it executes code too. Of course their >> >> > code is wrong, but it would be nice if the system would catch & reject >> >> > it explicitly to stave of inadvertent usage. >> >> > >> >> > This is not a perfect solution as it can still be worked around by >> >> > inlining the code itself: >> >> > $ bash -c "$(cat /dev/shm/test.sh)" >> >> > hi >> >> > >> >> > But this makes things a bit harder for malicious attackers (depending >> >> > how exactly they've managed to escalate), but it also helps developers >> >> > from getting it wrong in the first place. >> >> >> >> Application-level based security on an environment where people using >> >> the application has direct control over the environment for me is not >> >> so sensible, and is a dirty hack. A shell is also not meant for that. >> >> If you want such feature perhaps you should add it on a restricted >> >> shell, granting it really makes sense adding it. But forcing that >> >> feature to be default on every user (like me who doesn't want its >> >> inconsistency) is wrong. A shell reads and executes and is something >> >> not in the scope of `noexec`, not in the scope of kernel-land >> >> security, so we have to deal with it. >> > >> > (1) the examples i already provided do not involve the user at all, and >> > include systems where the user has no direct access to the shell. >> >> And the one that made the code execute remotely through for example an >> exploit is not a user? > > you're conflating concepts, but still, the answer is no. having a user > sitting at an interactive terminal and typing in commands or getting the > system to directly execute bash is not what i described. systems that > do not permit access to any shells anywhere, and instead the attack is > breaking out of one process to write a text file somewhere that a diff > system/periodic process will later source. you could get the same setup > as having a system you can only access over HTTP (i.e. no shell access) > and exploiting apache/php/whatever to write to a cache file that will be > read by another app. > > i recall some router firmwares being attacked in this way -- a remote > bug only permitted the writing of data to common data locations, but > they picked a place where privileged init scripts would source saved > state. Ok I accept your point. So it's actually about `source` and `bash file`, correct? So would this mean every script I `source` would need +x bit now? And if it's not about the +x bit and only about `noexec`, would stuff I place that I would want to not execute (with execve(), etc.) in a `noexec` directory no longer be `source`-able, even though I'm still wanting those to be `source`-d? `source` is meant to only require readable permission. >> > (2) choice over runtime functionality is by the sysadmin, not the user. >> >> Doesn't matter to me. And I'm referring to the real user or the >> person, and not the account. I don't want an inconsistent >> functionality running in my bash whether I'm using a privileged >> account or not. > > it isn't inconsistent: no user gets to exec code from noexec points You complicate it. I'm both a user and an administrator to my personal system and I don't want that function running by default in my bash. Simple. >> > (3) i disagree over the scope of noexec. i think this is in-scope. >> >> Being a little forgiving, I could say that scripts with #! headers >> -perhaps- are still in the scope of `noexec` since they are respected >> by the kernel as executables, even though they are not real >> instructions running within the processor's transistors themselves >> (they are just read and -virtually- executed where the shell acts on >> behalf of them), but how about those scripts without #! headers? >> Clearly they're no longer -executables-. And
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 15 Dec 2015 06:47, konsolebox wrote: > t On Mon, Dec 14, 2015 at 1:17 PM, Mike Frysingerwrote: > > On 13 Dec 2015 16:50, konsolebox wrote: > >> On Sun, Dec 13, 2015 at 5:01 AM, Mike Frysinger wrote: > >> > Today, if you have a script that lives on a noexec mount point, the > >> > kernel will reject attempts to run it directly: > >> > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh > >> > $ chmod a+rx /dev/shm/test.sh > >> > $ /dev/shm/test.sh > >> > bash: /dev/shm/test.sh: Permission denied > >> > > >> > But bash itself has no problem running this file: > >> > $ bash /dev/shm/test.sh > >> > hi > >> > Or with letting other scripts run this file: > >> > $ bash -c '. /dev/shm/test.sh' > >> > hi > >> > Or with reading the script from stdin: > >> > $ bash >> > hi > >> > > >> > This detracts from the security of the overall system. People writing > >> > scripts sometimes want to save/restore state (s) and will > >> > restore the content from a noexec point using the aforementioned source > >> > command without realizing that it executes code too. Of course their > >> > code is wrong, but it would be nice if the system would catch & reject > >> > it explicitly to stave of inadvertent usage. > >> > > >> > This is not a perfect solution as it can still be worked around by > >> > inlining the code itself: > >> > $ bash -c "$(cat /dev/shm/test.sh)" > >> > hi > >> > > >> > But this makes things a bit harder for malicious attackers (depending > >> > how exactly they've managed to escalate), but it also helps developers > >> > from getting it wrong in the first place. > >> > >> Application-level based security on an environment where people using > >> the application has direct control over the environment for me is not > >> so sensible, and is a dirty hack. A shell is also not meant for that. > >> If you want such feature perhaps you should add it on a restricted > >> shell, granting it really makes sense adding it. But forcing that > >> feature to be default on every user (like me who doesn't want its > >> inconsistency) is wrong. A shell reads and executes and is something > >> not in the scope of `noexec`, not in the scope of kernel-land > >> security, so we have to deal with it. > > > > (1) the examples i already provided do not involve the user at all, and > > include systems where the user has no direct access to the shell. > > And the one that made the code execute remotely through for example an > exploit is not a user? you're conflating concepts, but still, the answer is no. having a user sitting at an interactive terminal and typing in commands or getting the system to directly execute bash is not what i described. systems that do not permit access to any shells anywhere, and instead the attack is breaking out of one process to write a text file somewhere that a diff system/periodic process will later source. you could get the same setup as having a system you can only access over HTTP (i.e. no shell access) and exploiting apache/php/whatever to write to a cache file that will be read by another app. i recall some router firmwares being attacked in this way -- a remote bug only permitted the writing of data to common data locations, but they picked a place where privileged init scripts would source saved state. > Also consider use of `source` or `eval` may it be in a subshell or not. these cases have already been cited in this thread, and still are not relevant to the scenarios described > > (2) choice over runtime functionality is by the sysadmin, not the user. > > Doesn't matter to me. And I'm referring to the real user or the > person, and not the account. I don't want an inconsistent > functionality running in my bash whether I'm using a privileged > account or not. it isn't inconsistent: no user gets to exec code from noexec points > > (3) i disagree over the scope of noexec. i think this is in-scope. > > Being a little forgiving, I could say that scripts with #! headers > -perhaps- are still in the scope of `noexec` since they are respected > by the kernel as executables, even though they are not real > instructions running within the processor's transistors themselves > (they are just read and -virtually- executed where the shell acts on > behalf of them), but how about those scripts without #! headers? > Clearly they're no longer -executables-. And clearly you're just > wanting bash to restrict things based on the conceptual purpose of > `noexec`, even though it is not exactly or strictly in the scope of > `noexec`. I'm a purist and I don't like that, and I don't want to > have that inconsistency in default bash. you're describing libraries which the kernel also blocks. there's no relevant difference between fragments you source and libraries that ELF programs link against either directly (e.g. -lfoo) or indirectly (e.g. dlopen(libfoo)). the kernel blocks both as i described in my first e-mail. -mike signature.asc
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
t On Mon, Dec 14, 2015 at 1:17 PM, Mike Frysingerwrote: > On 13 Dec 2015 16:50, konsolebox wrote: >> On Sun, Dec 13, 2015 at 5:01 AM, Mike Frysinger wrote: >> > Today, if you have a script that lives on a noexec mount point, the >> > kernel will reject attempts to run it directly: >> > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh >> > $ chmod a+rx /dev/shm/test.sh >> > $ /dev/shm/test.sh >> > bash: /dev/shm/test.sh: Permission denied >> > >> > But bash itself has no problem running this file: >> > $ bash /dev/shm/test.sh >> > hi >> > Or with letting other scripts run this file: >> > $ bash -c '. /dev/shm/test.sh' >> > hi >> > Or with reading the script from stdin: >> > $ bash > > hi >> > >> > This detracts from the security of the overall system. People writing >> > scripts sometimes want to save/restore state (s) and will >> > restore the content from a noexec point using the aforementioned source >> > command without realizing that it executes code too. Of course their >> > code is wrong, but it would be nice if the system would catch & reject >> > it explicitly to stave of inadvertent usage. >> > >> > This is not a perfect solution as it can still be worked around by >> > inlining the code itself: >> > $ bash -c "$(cat /dev/shm/test.sh)" >> > hi >> > >> > But this makes things a bit harder for malicious attackers (depending >> > how exactly they've managed to escalate), but it also helps developers >> > from getting it wrong in the first place. >> >> Application-level based security on an environment where people using >> the application has direct control over the environment for me is not >> so sensible, and is a dirty hack. A shell is also not meant for that. >> If you want such feature perhaps you should add it on a restricted >> shell, granting it really makes sense adding it. But forcing that >> feature to be default on every user (like me who doesn't want its >> inconsistency) is wrong. A shell reads and executes and is something >> not in the scope of `noexec`, not in the scope of kernel-land >> security, so we have to deal with it. > > (1) the examples i already provided do not involve the user at all, and > include systems where the user has no direct access to the shell. And the one that made the code execute remotely through for example an exploit is not a user? Also consider use of `source` or `eval` may it be in a subshell or not. eval "$(cat /path/script.sh)" source <(cat /path/script.sh) > (2) choice over runtime functionality is by the sysadmin, not the user. Doesn't matter to me. And I'm referring to the real user or the person, and not the account. I don't want an inconsistent functionality running in my bash whether I'm using a privileged account or not. > (3) i disagree over the scope of noexec. i think this is in-scope. Being a little forgiving, I could say that scripts with #! headers -perhaps- are still in the scope of `noexec` since they are respected by the kernel as executables, even though they are not real instructions running within the processor's transistors themselves (they are just read and -virtually- executed where the shell acts on behalf of them), but how about those scripts without #! headers? Clearly they're no longer -executables-. And clearly you're just wanting bash to restrict things based on the conceptual purpose of `noexec`, even though it is not exactly or strictly in the scope of `noexec`. I'm a purist and I don't like that, and I don't want to have that inconsistency in default bash.
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
2015-12-12 17:53:35 -0500, Mike Frysinger: [...] > > It will almost > > certainly get in the way of a reasonable use case. > > can you name a reasonable use case this breaks ? bash << EOF some code EOF here-documents with many shells (including bash) are implemented as deleted temporary files (typically in /tmp which sometimes has noexec). -- Stephane
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
2015-12-12 16:01:26 -0500, Mike Frysinger: [...] > This is not a perfect solution as it can still be worked around by > inlining the code itself: > $ bash -c "$(cat /dev/shm/test.sh)" > hi Or cat /dev/shm/test.sh | bash I think this kind of hardening is better left to things like selinux/apparmor. -- Stephane
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 13 Dec 2015 12:21, Piotr Grzybowski wrote: > On Sat, Dec 12, 2015 at 11:53 PM, Mike Frysinger wrote: > > On 12 Dec 2015 15:06, Bob Proulx wrote: > >> It will almost > >> certainly get in the way of a reasonable use case. > > > > can you name a reasonable use case this breaks ? > > source /media/noexecmountpoint/sh/functions.sh; > find_all_files_with_executable_bit /media/noexecmountpoint; i think you're doing it wrong. if you want to run code off of mount point, then you should be mounting it executable. > Mike: I kind of understand your idea, but noexec flag given in the > mount significates something else then your patch addresses. i disagree -mike signature.asc Description: Digital signature
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 12 Dec 2015 23:05, Stephane Chazelas wrote: > 2015-12-12 16:01:26 -0500, Mike Frysinger: > [...] > > This is not a perfect solution as it can still be worked around by > > inlining the code itself: > > $ bash -c "$(cat /dev/shm/test.sh)" > > hi > > Or > > cat /dev/shm/test.sh | bash right, there's no way to look through pipes > I think this kind of hardening is better left to things like > selinux/apparmor. security is not an all-or-nothing proposotion. the whole point is to have defence in depth. -mike signature.asc Description: Digital signature
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 12/12/15 4:01 PM, Mike Frysinger wrote: > From: Mike Frysinger> > Today, if you have a script that lives on a noexec mount point, the > kernel will reject attempts to run it directly: > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh > $ chmod a+rx /dev/shm/test.sh > $ /dev/shm/test.sh > bash: /dev/shm/test.sh: Permission denied > > But bash itself has no problem running this file: It's hard to see how this proposal improves overall system security. There are a dozen ways a minimally-competent attacker can circumvent it. Unless you want to completely remove the ability for bash and other utilities to read files from a noexec file system, or run on a system with no writable file systems at all, this does no good. Its primary effect would seem to be annoying and frustrating users. A worse problem is that the abstraction is in the wrong place. The shell, like other programs, requests services from the kernel to do things. The kernel is the arbiter of restrictions on those services. If asked to execute a file, the shell asks the kernel whether the file is executable, then tries to execute it. If asked to read a file, the shell tries to open it. The kernel, or some agent it invokes, is where the access decision is made. If you want to, for instance, disallow the shell and other utilities from opening executable files for reading on file systems with noexec set, the shell binary is not the place to embed that policy. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 13 Dec 2015 17:24, Chet Ramey wrote: > On 12/12/15 4:01 PM, Mike Frysinger wrote: > > Today, if you have a script that lives on a noexec mount point, the > > kernel will reject attempts to run it directly: > > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh > > $ chmod a+rx /dev/shm/test.sh > > $ /dev/shm/test.sh > > bash: /dev/shm/test.sh: Permission denied > > > > But bash itself has no problem running this file: > > It's hard to see how this proposal improves overall system security. There > are a dozen ways a minimally-competent attacker can circumvent it. you're assuming the attacker has unlimited access to resources and control over the environment and execution. i already noted there are ways to run arbitrary code -- when you have arbitrary code access. there also are cases (such as i described) which this change would block attacks because the attacker does not have such unfettered access. they're leveraging a small bug elsewhere to escalate to a fuller environment. > Unless > you want to completely remove the ability for bash and other utilities to > read files from a noexec file system, or run on a system with no writable > file systems at all, this does no good. Its primary effect would seem to > be annoying and frustrating users. > > A worse problem is that the abstraction is in the wrong place. The shell, > like other programs, requests services from the kernel to do things. The > kernel is the arbiter of restrictions on those services. If asked to > execute a file, the shell asks the kernel whether the file is executable, > then tries to execute it. If asked to read a file, the shell tries to > open it. The kernel, or some agent it invokes, is where the access > decision is made. If you want to, for instance, disallow the shell and > other utilities from opening executable files for reading on file systems > with noexec set, the shell binary is not the place to embed that policy. i'm aware of the fundamental structure of UNIX-like systems. bash itself is providing services to a program by executing the requested code and in a sense, has a responsibility to control that. otherwise, you seem to be arguing against the existence of rbash, or job control, or similar shell limiting/control functionality. i understand this is a disruptive change. how about making it a compile time flag, or perhaps a new shopt ? -mike signature.asc Description: Digital signature
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 13 Dec 2015 16:50, konsolebox wrote: > On Sun, Dec 13, 2015 at 5:01 AM, Mike Frysinger wrote: > > Today, if you have a script that lives on a noexec mount point, the > > kernel will reject attempts to run it directly: > > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh > > $ chmod a+rx /dev/shm/test.sh > > $ /dev/shm/test.sh > > bash: /dev/shm/test.sh: Permission denied > > > > But bash itself has no problem running this file: > > $ bash /dev/shm/test.sh > > hi > > Or with letting other scripts run this file: > > $ bash -c '. /dev/shm/test.sh' > > hi > > Or with reading the script from stdin: > > $ bash > hi > > > > This detracts from the security of the overall system. People writing > > scripts sometimes want to save/restore state (like variables) and will > > restore the content from a noexec point using the aforementioned source > > command without realizing that it executes code too. Of course their > > code is wrong, but it would be nice if the system would catch & reject > > it explicitly to stave of inadvertent usage. > > > > This is not a perfect solution as it can still be worked around by > > inlining the code itself: > > $ bash -c "$(cat /dev/shm/test.sh)" > > hi > > > > But this makes things a bit harder for malicious attackers (depending > > how exactly they've managed to escalate), but it also helps developers > > from getting it wrong in the first place. > > Application-level based security on an environment where people using > the application has direct control over the environment for me is not > so sensible, and is a dirty hack. A shell is also not meant for that. > If you want such feature perhaps you should add it on a restricted > shell, granting it really makes sense adding it. But forcing that > feature to be default on every user (like me who doesn't want its > inconsistency) is wrong. A shell reads and executes and is something > not in the scope of `noexec`, not in the scope of kernel-land > security, so we have to deal with it. (1) the examples i already provided do not involve the user at all, and include systems where the user has no direct access to the shell. (2) choice over runtime functionality is by the sysadmin, not the user. (3) i disagree over the scope of noexec. i think this is in-scope. -mike signature.asc Description: Digital signature
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On Sat, Dec 12, 2015 at 3:01 PM, Mike Frysingerwrote: > From: Mike Frysinger > > Today, if you have a script that lives on a noexec mount point, the > kernel will reject attempts to run it directly: > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh > $ chmod a+rx /dev/shm/test.sh > $ /dev/shm/test.sh > bash: /dev/shm/test.sh: Permission denied > > But bash itself has no problem running this file: > $ bash /dev/shm/test.sh > hi > Or with letting other scripts run this file: > $ bash -c '. /dev/shm/test.sh' > hi > Or with reading the script from stdin: > $ bashhi > > This detracts from the security of the overall system. People writing > scripts sometimes want to save/restore state (like variables) and will > restore the content from a noexec point using the aforementioned source > command without realizing that it executes code too. Of course their > code is wrong, but it would be nice if the system would catch & reject > it explicitly to stave of inadvertent usage. > > This is not a perfect solution as it can still be worked around by > inlining the code itself: > $ bash -c "$(cat /dev/shm/test.sh)" > hi If this is a bug in BASH, then it is likely also a bug in: Python, PERL, Ruby, LUA, oorexx, . But, quite honestly, I haven't checked it out because I don't have a "noexec" mountpoint handy here at home. -- Schrodinger's backup: The condition of any backup is unknown until a restore is attempted. Yoda of Borg, we are. Futile, resistance is, yes. Assimilated, you will be. He's about as useful as a wax frying pan. 10 to the 12th power microphones = 1 Megaphone Maranatha! <>< John McKown
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 12 Dec 2015 22:12, John McKown wrote: > On Sat, Dec 12, 2015 at 3:01 PM, Mike Frysinger wrote: > > Today, if you have a script that lives on a noexec mount point, the > > kernel will reject attempts to run it directly: > > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh > > $ chmod a+rx /dev/shm/test.sh > > $ /dev/shm/test.sh > > bash: /dev/shm/test.sh: Permission denied > > > > But bash itself has no problem running this file: > > $ bash /dev/shm/test.sh > > hi > > Or with letting other scripts run this file: > > $ bash -c '. /dev/shm/test.sh' > > hi > > Or with reading the script from stdin: > > $ bash > hi > > > > This detracts from the security of the overall system. People writing > > scripts sometimes want to save/restore state (like variables) and will > > restore the content from a noexec point using the aforementioned source > > command without realizing that it executes code too. Of course their > > code is wrong, but it would be nice if the system would catch & reject > > it explicitly to stave of inadvertent usage. > > > > This is not a perfect solution as it can still be worked around by > > inlining the code itself: > > $ bash -c "$(cat /dev/shm/test.sh)" > > hi > > > > If this is a bug in BASH, then it is likely also a bug in: Python, PERL, > Ruby, LUA, oorexx, . But, > quite honestly, I haven't checked it out because I don't have a "noexec" > mountpoint handy here at home. i'm aware. it'd make sense in my mind to have all dynamic interpreters detect the source files before attempting to execute them. i'm looking at shells to start with as they're way more common to be installed and to be a target. -mike signature.asc Description: Digital signature
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
On 12 Dec 2015 15:06, Bob Proulx wrote: > Mike Frysinger wrote: > > But bash itself has no problem running this file: > > $ bash /dev/shm/test.sh > > hi > >... > > This detracts from the security of the overall system. People > > writing scripts sometimes want to save/restore state (like > > variables) and will restore the content from a noexec point using > > the aforementioned source command without realizing that it executes > > code too. Of course their code is wrong, but it would be nice if > > the system would catch & reject it explicitly to stave of > > inadvertent usage. > > I don't think it makes sense for a userland program to be an enforcer > of this type of check. It gives a false impression of a security that > does not exist. Which I think is more dangerous. i disagree, and it's the right place imo: the program that does the interpreting in the first place (i.e. the shell) should be checking for the settings where it's going to be loading that interpreted code. the reason binary loaders (e.g. ELF ldso's) don't need to do this is the kernel either prevents it directly (`./foo`) or indirectly (when the ldso tries to mmap the file with exec bits, the kernel will check for the noexec mount setting). > It will almost > certainly get in the way of a reasonable use case. can you name a reasonable use case this breaks ? > And nothing > prevents one from running a private copy of a shell without such a > check. Or any of the many compatible /bin/sh variants such as ksh, > zsh, ash, dash, and so forth. you're assuming (1) the user has access to a writable && exec mount point and (2) those other shells are installed. clamping both of those loop holes are trivial and i've seen a number of systems that do exactly that. Chrome OS for example only mounts / as executable and that is also read only. i imagine other verified boot systems enforce similar sanity, as do remote hosts (a number of systems i have ssh access do this). i also plan on sending patches for shells i care about (e.g. dash). -mike signature.asc Description: Digital signature
[PATCH/RFC] do not source/exec scripts on noexec mount points
From: Mike FrysingerToday, if you have a script that lives on a noexec mount point, the kernel will reject attempts to run it directly: $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh $ chmod a+rx /dev/shm/test.sh $ /dev/shm/test.sh bash: /dev/shm/test.sh: Permission denied But bash itself has no problem running this file: $ bash /dev/shm/test.sh hi Or with letting other scripts run this file: $ bash -c '. /dev/shm/test.sh' hi Or with reading the script from stdin: $ bash #include +#if defined (HAVE_SYS_STATVFS_H) +# include +#endif + #include "../bashansi.h" #include "../bashintl.h" @@ -160,6 +164,26 @@ file_error_and_exit: return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); } +#if defined (HAVE_SYS_STATVFS_H) && defined (ST_NOEXEC) + /* If the script is loaded from a noexec mount point, throw an error. */ + { +struct statvfs stvfs; + +if (fstatvfs (fd, ) == -1) + { + close (fd); + goto file_error_and_exit; + } + +if (stvfs.f_flag & ST_NOEXEC) + { + close (fd); + errno = EACCES; + goto file_error_and_exit; + } + } +#endif + if (S_ISREG (finfo.st_mode) && file_size <= SSIZE_MAX) { string = (char *)xmalloc (1 + file_size); diff --git a/config.h.in b/config.h.in index 894892f..b16f1d6 100644 --- a/config.h.in +++ b/config.h.in @@ -1039,6 +1039,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_STAT_H +/* Define if you have . */ +#undef HAVE_SYS_STATVFS_H + /* Define if you have the header file. */ #undef HAVE_SYS_STREAM_H diff --git a/configure b/configure index 52f6f5c..061b15e 100755 --- a/configure +++ b/configure @@ -9301,7 +9301,7 @@ fi done for ac_header in sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ -sys/param.h sys/socket.h sys/stat.h \ +sys/param.h sys/socket.h sys/stat.h sys/statvfs.h \ sys/time.h sys/times.h sys/types.h sys/wait.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` diff --git a/configure.ac b/configure.ac index f0d4aee..81b2a7c 100644 --- a/configure.ac +++ b/configure.ac @@ -717,7 +717,7 @@ AC_CHECK_HEADERS(unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \ regex.h syslog.h ulimit.h) AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ -sys/param.h sys/socket.h sys/stat.h \ +sys/param.h sys/socket.h sys/stat.h sys/statvfs.h \ sys/time.h sys/times.h sys/types.h sys/wait.h) AC_CHECK_HEADERS(netinet/in.h arpa/inet.h) diff --git a/shell.c b/shell.c index 0e47cf4..4739a31 100644 --- a/shell.c +++ b/shell.c @@ -46,6 +46,10 @@ # include #endif +#if defined (HAVE_SYS_STATVFS_H) +# include +#endif + #include "bashintl.h" #define NEED_SH_SETLINEBUF_DECL/* used in externs.h */ @@ -334,6 +338,8 @@ static void shell_reinitialize __P((void)); static void show_shell_usage __P((FILE *, int)); +static void check_noexec __P((int, const char *)); + #ifdef __CYGWIN__ static void _cygwin32_check_tmp () @@ -717,6 +723,7 @@ main (argc, argv, env) { /* In this mode, bash is reading a script from stdin, which is a pipe or redirected file. */ + check_noexec (0, "stdin"); #if defined (BUFFERED_INPUT) default_buffered_input = fileno (stdin); /* == 0 */ #else @@ -1442,6 +1449,28 @@ start_debugger () #endif } +static void +check_noexec (int fd, const char *filename) +{ +#if defined (HAVE_SYS_STATVFS_H) && defined (ST_NOEXEC) + /* Make sure the file isn't on a noexec mount point. */ + struct statvfs stvfs; + + if (fstatvfs (fd, ) == -1) +{ + file_error (filename); + exit (EX_NOTFOUND); +} + + if (stvfs.f_flag & ST_NOEXEC) +{ + errno = EACCES; + file_error (filename); + exit (EX_NOEXEC); +} +#endif +} + static int open_shell_script (script_name) char *script_name; @@ -1579,6 +1608,8 @@ open_shell_script (script_name) SET_CLOSE_ON_EXEC (fileno (default_input)); #endif /* !BUFFERED_INPUT */ + check_noexec (fd, filename); + /* Just about the only way for this code to be executed is if something like `bash -i /dev/stdin' is executed. */ if (interactive_shell && fd_is_tty) -- 2.6.2
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
Hello Mike, you want to forbid reading and interpreting scripts from the mount point that is marked as noexec. If nothing gets executed from the noexec area, as in your example, this is going to far. After this, do I have to move all my scripts away from the noexec area if I want bash to read them and run the commands (neither of which executes from the noexec mountpoint)? sincerely, pg On Sat, Dec 12, 2015 at 10:01 PM, Mike Frysingerwrote: > From: Mike Frysinger > > Today, if you have a script that lives on a noexec mount point, the > kernel will reject attempts to run it directly: > $ printf '#!/bin/sh\necho hi\n' > /dev/shm/test.sh > $ chmod a+rx /dev/shm/test.sh > $ /dev/shm/test.sh > bash: /dev/shm/test.sh: Permission denied > > But bash itself has no problem running this file: > $ bash /dev/shm/test.sh > hi > Or with letting other scripts run this file: > $ bash -c '. /dev/shm/test.sh' > hi > Or with reading the script from stdin: > $ bashhi > > This detracts from the security of the overall system. People writing > scripts sometimes want to save/restore state (like variables) and will > restore the content from a noexec point using the aforementioned source > command without realizing that it executes code too. Of course their > code is wrong, but it would be nice if the system would catch & reject > it explicitly to stave of inadvertent usage. > > This is not a perfect solution as it can still be worked around by > inlining the code itself: > $ bash -c "$(cat /dev/shm/test.sh)" > hi > > But this makes things a bit harder for malicious attackers (depending > how exactly they've managed to escalate), but it also helps developers > from getting it wrong in the first place. > --- > builtins/evalfile.c | 24 > config.h.in | 3 +++ > configure | 2 +- > configure.ac| 2 +- > shell.c | 31 +++ > 5 files changed, 60 insertions(+), 2 deletions(-) > > diff --git a/builtins/evalfile.c b/builtins/evalfile.c > index eb51c27..ed031d6 100644 > --- a/builtins/evalfile.c > +++ b/builtins/evalfile.c > @@ -32,6 +32,10 @@ > #include > #include > > +#if defined (HAVE_SYS_STATVFS_H) > +# include > +#endif > + > #include "../bashansi.h" > #include "../bashintl.h" > > @@ -160,6 +164,26 @@ file_error_and_exit: >return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); > } > > +#if defined (HAVE_SYS_STATVFS_H) && defined (ST_NOEXEC) > + /* If the script is loaded from a noexec mount point, throw an error. */ > + { > +struct statvfs stvfs; > + > +if (fstatvfs (fd, ) == -1) > + { > + close (fd); > + goto file_error_and_exit; > + } > + > +if (stvfs.f_flag & ST_NOEXEC) > + { > + close (fd); > + errno = EACCES; > + goto file_error_and_exit; > + } > + } > +#endif > + >if (S_ISREG (finfo.st_mode) && file_size <= SSIZE_MAX) > { >string = (char *)xmalloc (1 + file_size); > diff --git a/config.h.in b/config.h.in > index 894892f..b16f1d6 100644 > --- a/config.h.in > +++ b/config.h.in > @@ -1039,6 +1039,9 @@ > /* Define if you have the header file. */ > #undef HAVE_SYS_STAT_H > > +/* Define if you have . */ > +#undef HAVE_SYS_STATVFS_H > + > /* Define if you have the header file. */ > #undef HAVE_SYS_STREAM_H > > diff --git a/configure b/configure > index 52f6f5c..061b15e 100755 > --- a/configure > +++ b/configure > @@ -9301,7 +9301,7 @@ fi > done > > for ac_header in sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ > -sys/param.h sys/socket.h sys/stat.h \ > +sys/param.h sys/socket.h sys/stat.h sys/statvfs.h \ > sys/time.h sys/times.h sys/types.h sys/wait.h > do : >as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` > diff --git a/configure.ac b/configure.ac > index f0d4aee..81b2a7c 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -717,7 +717,7 @@ AC_CHECK_HEADERS(unistd.h stdlib.h stdarg.h varargs.h > limits.h string.h \ > stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \ > regex.h syslog.h ulimit.h) > AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ > -sys/param.h sys/socket.h sys/stat.h \ > +sys/param.h sys/socket.h sys/stat.h sys/statvfs.h \ > sys/time.h sys/times.h sys/types.h sys/wait.h) > AC_CHECK_HEADERS(netinet/in.h arpa/inet.h) > > diff --git a/shell.c b/shell.c > index 0e47cf4..4739a31 100644 > --- a/shell.c > +++ b/shell.c > @@ -46,6 +46,10 @@ > # include > #endif > > +#if defined (HAVE_SYS_STATVFS_H) > +# include > +#endif > + > #include "bashintl.h" > > #define NEED_SH_SETLINEBUF_DECL/* used in externs.h */ > @@ -334,6 +338,8 @@ static void shell_reinitialize __P((void)); > > static void show_shell_usage
Re: [PATCH/RFC] do not source/exec scripts on noexec mount points
Mike Frysinger wrote: > But bash itself has no problem running this file: > $ bash /dev/shm/test.sh > hi >... > This detracts from the security of the overall system. People > writing scripts sometimes want to save/restore state (like > variables) and will restore the content from a noexec point using > the aforementioned source command without realizing that it executes > code too. Of course their code is wrong, but it would be nice if > the system would catch & reject it explicitly to stave of > inadvertent usage. I don't think it makes sense for a userland program to be an enforcer of this type of check. It gives a false impression of a security that does not exist. Which I think is more dangerous. It will almost certainly get in the way of a reasonable use case. And nothing prevents one from running a private copy of a shell without such a check. Or any of the many compatible /bin/sh variants such as ksh, zsh, ash, dash, and so forth. Bob