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 Sat, Dec 12, 2015 at 3: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: > $ 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 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
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
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 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: > $ 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, &stvfs) == -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 chec
[PATCH/RFC] do not source/exec scripts on noexec mount points
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: $ 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, &stvfs) == -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, &stvfs) == -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: Ruler
2015-12-11 20:41:26 -0700, valkrem: > Hi all, > > I am looking for a screen ruler (script) that display the column position of > a variables for a given file. > > > Example > Assume I have a file named "test" and has three variables > > Id Date length > > 123 20150518 2750 > 125 20140324 3500 > > When I invoke the command -ruler ( or the script name) I will see the > following > > bash$ ruler test > 12 3 > 12345678901234567890 > --- > 123 20150518 2750 > 125 20140324 3500 [...] Maybe something like: #! /bin/bash - shopt -s checkwinsize (:) # seems to trigger bash to set $COLUMNS cat "$@" | awk -v c="$COLUMNS" -v l="$LINES" 'BEGIN { for (i = 1; i <= c; i++) { a = a (i % 10 ? " " : (i/10)%10) b = b (i % 10) } } NR % (l-5) == 1 {print a "\n" b} {print}' | less -S -- Stephane