Re: [PATCH/RFC] do not source/exec scripts on noexec mount points

2015-12-12 Thread John McKown
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

2015-12-12 Thread Mike Frysinger
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: Ruler

2015-12-12 Thread Stephane Chazelas
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




Re: [PATCH/RFC] do not source/exec scripts on noexec mount points

2015-12-12 Thread Mike Frysinger
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

2015-12-12 Thread Mike Frysinger
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, ) == -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

2015-12-12 Thread Piotr Grzybowski
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, ) == -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

2015-12-12 Thread Bob Proulx
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