diff mbox

[RFC] shebang: restrict python interactive prompt/interpreter

Message ID 1485874105.5036.5.camel@linux.vnet.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mimi Zohar Jan. 31, 2017, 2:48 p.m. UTC
This patch, posted as a proof of concept, defines a new, minor LSM named
"shebang", that restricts python such that scripts are allowed to execute,
while the interactive prompt/interpreter is not available.  When used in
conjunction with an IMA appraise execute policy requiring files signatures,
only signed python scripts would be allowed to execute.

Based on pathname (very lame!), this patch prevents the interactive
prompt/interpreter from being executed.  Before making it just a bit more
robust, do we really need a new minor LSM or can the existing LSMs
(eg. SELinux, Smack, AppArmor) be configured to provide this support?

Any suggestions or other solutions would be much appreciated!

thanks!

Mimi Zohar <zohar@linux.vnet.ibm.com>
---
 security/Kconfig                  |  1 +
 security/Makefile                 |  2 ++
 security/shebang/Kconfig          | 15 ++++++++++++
 security/shebang/Makefile         |  3 +++
 security/shebang/shebang_python.c | 50 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 71 insertions(+)
 create mode 100644 security/shebang/Kconfig
 create mode 100644 security/shebang/Makefile
 create mode 100644 security/shebang/shebang_python.c

Comments

Paul Moore Jan. 31, 2017, 3:55 p.m. UTC | #1
On Tue, Jan 31, 2017 at 9:48 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> This patch, posted as a proof of concept, defines a new, minor LSM named
> "shebang", that restricts python such that scripts are allowed to execute,
> while the interactive prompt/interpreter is not available.  When used in
> conjunction with an IMA appraise execute policy requiring files signatures,
> only signed python scripts would be allowed to execute.
>
> Based on pathname (very lame!), this patch prevents the interactive
> prompt/interpreter from being executed.  Before making it just a bit more
> robust, do we really need a new minor LSM or can the existing LSMs
> (eg. SELinux, Smack, AppArmor) be configured to provide this support?

I've never tried this, but since SELinux takes the label/creds from
the script that is exec()'d and not the interpreter, I expect that one
could craft policy that prevented the direct execution of the
interpreter but still allowed scripts to run.  The policy for this
wouldn't be hard to write, although I suspect it would be a total
non-starter for everything but a fixed use case appliance.  I've CC'd
Stephen, perhaps he's played with doing something like this.

I recognize that you are interested in this restriction in the context
of IMA, so there is presumably some vetting of the scripts before
authorizing them, but it still seems like there is a non-trivial risk
of this restriction being circumvented.

> Any suggestions or other solutions would be much appreciated!
>
> thanks!
>
> Mimi Zohar <zohar@linux.vnet.ibm.com>
> ---
>  security/Kconfig                  |  1 +
>  security/Makefile                 |  2 ++
>  security/shebang/Kconfig          | 15 ++++++++++++
>  security/shebang/Makefile         |  3 +++
>  security/shebang/shebang_python.c | 50 +++++++++++++++++++++++++++++++++++++++
>  5 files changed, 71 insertions(+)
>  create mode 100644 security/shebang/Kconfig
>  create mode 100644 security/shebang/Makefile
>  create mode 100644 security/shebang/shebang_python.c
>
> diff --git a/security/Kconfig b/security/Kconfig
> index 118f4549404e..8b12837ce933 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -164,6 +164,7 @@ source security/tomoyo/Kconfig
>  source security/apparmor/Kconfig
>  source security/loadpin/Kconfig
>  source security/yama/Kconfig
> +source security/shebang/Kconfig
>
>  source security/integrity/Kconfig
>
> diff --git a/security/Makefile b/security/Makefile
> index f2d71cdb8e19..00a8dbebb07f 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -9,6 +9,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
>  subdir-$(CONFIG_SECURITY_APPARMOR)     += apparmor
>  subdir-$(CONFIG_SECURITY_YAMA)         += yama
>  subdir-$(CONFIG_SECURITY_LOADPIN)      += loadpin
> +subdir-$(CONFIG_SECURITY_SHEBANG)      += shebang
>
>  # always enable default capabilities
>  obj-y                                  += commoncap.o
> @@ -24,6 +25,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)         += tomoyo/
>  obj-$(CONFIG_SECURITY_APPARMOR)                += apparmor/
>  obj-$(CONFIG_SECURITY_YAMA)            += yama/
>  obj-$(CONFIG_SECURITY_LOADPIN)         += loadpin/
> +obj-$(CONFIG_SECURITY_SHEBANG)         += shebang/
>  obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
>
>  # Object integrity file lists
> diff --git a/security/shebang/Kconfig b/security/shebang/Kconfig
> new file mode 100644
> index 000000000000..c2e943159307
> --- /dev/null
> +++ b/security/shebang/Kconfig
> @@ -0,0 +1,15 @@
> +config SECURITY_SHEBANG
> +       bool "Restrict python interactive prompt/interpreter"
> +       depends on SECURITY
> +       help
> +         Restrict python so that python scripts are allowed to execute,
> +         while the interactive prompt/interpreter is not available.  When
> +         used in conjunction with an IMA appraise policy requiring files
> +         signatures, only signed scripts will be executed.
> +
> +config SECURITY_INTERP_PATHNAME
> +       string "interpreter pathname"
> +       depends on SECURITY_SHEBANG
> +       default "/usr/bin/python"
> +       help
> +         This option defines a script interpreter pathname.
> diff --git a/security/shebang/Makefile b/security/shebang/Makefile
> new file mode 100644
> index 000000000000..f1b83dcb96d1
> --- /dev/null
> +++ b/security/shebang/Makefile
> @@ -0,0 +1,3 @@
> +obj-$(CONFIG_SECURITY_SHEBANG) += shebang.o
> +
> +shebang-y := shebang_python.o
> diff --git a/security/shebang/shebang_python.c b/security/shebang/shebang_python.c
> new file mode 100644
> index 000000000000..5f319badd2b3
> --- /dev/null
> +++ b/security/shebang/shebang_python.c
> @@ -0,0 +1,50 @@
> +/*
> + * shebang security module
> + *
> + * Copyright (C) 2017 IBM Corporation
> + *
> + * Authors:
> + * Mimi Zohar <zohar@linux.vnet.ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#define pr_fmt(fmt) "shebang: " fmt
> +#include <linux/module.h>
> +#include <linux/binfmts.h>
> +#include <linux/lsm_hooks.h>
> +
> +static char *pathname;
> +
> +/**
> + * shebang_bprm_check
> + * @bprm: contains the linux_binprm structure
> + */
> +int shebang_bprm_check(struct linux_binprm *bprm)
> +{
> +       if ((bprm->interp == bprm->filename) &&
> +           strcmp(bprm->interp, pathname) == 0) {
> +               pr_info("prevent executing %s \n", bprm->interp);
> +               return -EPERM;
> +       }
> +       return 0;
> +}
> +
> +static struct security_hook_list shebang_hooks[] = {
> +       LSM_HOOK_INIT(bprm_check_security, shebang_bprm_check)
> +};
> +
> +static int __init init_shebang(void)
> +{
> +       pathname = kstrdup(CONFIG_SECURITY_INTERP_PATHNAME, GFP_KERNEL);
> +       security_add_hooks(shebang_hooks, ARRAY_SIZE(shebang_hooks), "shebang");
> +       pr_info("initialized\n");
> +       return 0;
> +}
> +
> +late_initcall(init_shebang);
> +
> +MODULE_LICENSE("GPL");
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mimi Zohar Jan. 31, 2017, 4:26 p.m. UTC | #2
On Tue, 2017-01-31 at 10:55 -0500, Paul Moore wrote:
> On Tue, Jan 31, 2017 at 9:48 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> > This patch, posted as a proof of concept, defines a new, minor LSM named
> > "shebang", that restricts python such that scripts are allowed to execute,
> > while the interactive prompt/interpreter is not available.  When used in
> > conjunction with an IMA appraise execute policy requiring files signatures,
> > only signed python scripts would be allowed to execute.
> >
> > Based on pathname (very lame!), this patch prevents the interactive
> > prompt/interpreter from being executed.  Before making it just a bit more
> > robust, do we really need a new minor LSM or can the existing LSMs
> > (eg. SELinux, Smack, AppArmor) be configured to provide this support?
> 
> I've never tried this, but since SELinux takes the label/creds from
> the script that is exec()'d and not the interpreter, I expect that one
> could craft policy that prevented the direct execution of the
> interpreter but still allowed scripts to run.  The policy for this
> wouldn't be hard to write, although I suspect it would be a total
> non-starter for everything but a fixed use case appliance.  I've CC'd
> Stephen, perhaps he's played with doing something like this.

> I recognize that you are interested in this restriction in the context
> of IMA, so there is presumably some vetting of the scripts before
> authorizing them, but it still seems like there is a non-trivial risk
> of this restriction being circumvented.

This isn't any different than any other signed code.  File signatures
can be used to limit which code can be executed/accessed on the system
based on file provenance.  It doesn't say anything about the correctness
of the code.  That is a separate issue, which needs to be addressed.

Going beyond validating the script's file signature would require
changes to python to differentiate between opening a file containing
"code" vs. data.

Mimi

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Smalley Jan. 31, 2017, 5:34 p.m. UTC | #3
On Tue, 2017-01-31 at 10:55 -0500, Paul Moore wrote:
> On Tue, Jan 31, 2017 at 9:48 AM, Mimi Zohar <zohar@linux.vnet.ibm.com
> > wrote:
> > 
> > This patch, posted as a proof of concept, defines a new, minor LSM
> > named
> > "shebang", that restricts python such that scripts are allowed to
> > execute,
> > while the interactive prompt/interpreter is not available.  When
> > used in
> > conjunction with an IMA appraise execute policy requiring files
> > signatures,
> > only signed python scripts would be allowed to execute.
> > 
> > Based on pathname (very lame!), this patch prevents the interactive
> > prompt/interpreter from being executed.  Before making it just a
> > bit more
> > robust, do we really need a new minor LSM or can the existing LSMs
> > (eg. SELinux, Smack, AppArmor) be configured to provide this
> > support?
> 
> I've never tried this, but since SELinux takes the label/creds from
> the script that is exec()'d and not the interpreter, I expect that
> one
> could craft policy that prevented the direct execution of the
> interpreter but still allowed scripts to run.  The policy for this
> wouldn't be hard to write, although I suspect it would be a total
> non-starter for everything but a fixed use case appliance.  I've CC'd
> Stephen, perhaps he's played with doing something like this.

load_script() calls open_exec() on the interpreter while still running
in the caller's credentials, so the caller requires execute permission
to the interpreter (and this is correct behavior).

TOMOYO/AppArmor have a way to defer the checking to the bprm hooks (via
the current->in_execve flag, added by TOMOYO) so that they can choose
whether to use the old or new credentials for the permission checks,
but that only makes a difference if changing credentials on the exec.

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paul Moore Jan. 31, 2017, 6:36 p.m. UTC | #4
On Tue, Jan 31, 2017 at 12:34 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> On Tue, 2017-01-31 at 10:55 -0500, Paul Moore wrote:
>> On Tue, Jan 31, 2017 at 9:48 AM, Mimi Zohar <zohar@linux.vnet.ibm.com
>> > wrote:
>> >
>> > This patch, posted as a proof of concept, defines a new, minor LSM
>> > named
>> > "shebang", that restricts python such that scripts are allowed to
>> > execute,
>> > while the interactive prompt/interpreter is not available.  When
>> > used in
>> > conjunction with an IMA appraise execute policy requiring files
>> > signatures,
>> > only signed python scripts would be allowed to execute.
>> >
>> > Based on pathname (very lame!), this patch prevents the interactive
>> > prompt/interpreter from being executed.  Before making it just a
>> > bit more
>> > robust, do we really need a new minor LSM or can the existing LSMs
>> > (eg. SELinux, Smack, AppArmor) be configured to provide this
>> > support?
>>
>> I've never tried this, but since SELinux takes the label/creds from
>> the script that is exec()'d and not the interpreter, I expect that
>> one
>> could craft policy that prevented the direct execution of the
>> interpreter but still allowed scripts to run.  The policy for this
>> wouldn't be hard to write, although I suspect it would be a total
>> non-starter for everything but a fixed use case appliance.  I've CC'd
>> Stephen, perhaps he's played with doing something like this.
>
> load_script() calls open_exec() on the interpreter while still running
> in the caller's credentials, so the caller requires execute permission
> to the interpreter (and this is correct behavior).

Thanks for the correction.  I made the mistake of not looking at the
script binfmt handler and to be honest I've never wanted to block
access in this way on any of my systems ;)
Mimi Zohar Jan. 31, 2017, 8:09 p.m. UTC | #5
On Tue, 2017-01-31 at 12:34 -0500, Stephen Smalley wrote:
> On Tue, 2017-01-31 at 10:55 -0500, Paul Moore wrote:
> > On Tue, Jan 31, 2017 at 9:48 AM, Mimi Zohar <zohar@linux.vnet.ibm.com
> > > wrote:
> > > 
> > > This patch, posted as a proof of concept, defines a new, minor LSM named
> > > "shebang", that restricts python such that scripts are allowed to
> > > execute,
> > > while the interactive prompt/interpreter is not available.  When used in
> > > conjunction with an IMA appraise execute policy requiring files signatures,
> > > only signed python scripts would be allowed to execute.
> > > 
> > > Based on pathname (very lame!), this patch prevents the interactive
> > > prompt/interpreter from being executed.  Before making it just a bit more
> > > robust, do we really need a new minor LSM or can the existing LSMs
> > > (eg. SELinux, Smack, AppArmor) be configured to provide this support?
> > 
> > I've never tried this, but since SELinux takes the label/creds from
> > the script that is exec()'d and not the interpreter, I expect that one
> > could craft policy that prevented the direct execution of the
> > interpreter but still allowed scripts to run.  The policy for this
> > wouldn't be hard to write, although I suspect it would be a total
> > non-starter for everything but a fixed use case appliance.  I've CC'd
> > Stephen, perhaps he's played with doing something like this.
> 
> load_script() calls open_exec() on the interpreter while still running
> in the caller's credentials, so the caller requires execute permission
> to the interpreter (and this is correct behavior).
> 
> TOMOYO/AppArmor have a way to defer the checking to the bprm hooks (via
> the current->in_execve flag, added by TOMOYO) so that they can choose
> whether to use the old or new credentials for the permission checks,
> but that only makes a difference if changing credentials on the exec.

So with SELinux, is it possible to prevent the python interactive
prompt/interpreter?

Mimi

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Smalley Jan. 31, 2017, 9:10 p.m. UTC | #6
On Tue, 2017-01-31 at 15:09 -0500, Mimi Zohar wrote:
> On Tue, 2017-01-31 at 12:34 -0500, Stephen Smalley wrote:
> > 
> > On Tue, 2017-01-31 at 10:55 -0500, Paul Moore wrote:
> > > 
> > > On Tue, Jan 31, 2017 at 9:48 AM, Mimi Zohar <zohar@linux.vnet.ibm
> > > .com
> > > > 
> > > > wrote:
> > > > 
> > > > This patch, posted as a proof of concept, defines a new, minor
> > > > LSM named
> > > > "shebang", that restricts python such that scripts are allowed
> > > > to
> > > > execute,
> > > > while the interactive prompt/interpreter is not
> > > > available.  When used in
> > > > conjunction with an IMA appraise execute policy requiring files
> > > > signatures,
> > > > only signed python scripts would be allowed to execute.
> > > > 
> > > > Based on pathname (very lame!), this patch prevents the
> > > > interactive
> > > > prompt/interpreter from being executed.  Before making it just
> > > > a bit more
> > > > robust, do we really need a new minor LSM or can the existing
> > > > LSMs
> > > > (eg. SELinux, Smack, AppArmor) be configured to provide this
> > > > support?
> > > 
> > > I've never tried this, but since SELinux takes the label/creds
> > > from
> > > the script that is exec()'d and not the interpreter, I expect
> > > that one
> > > could craft policy that prevented the direct execution of the
> > > interpreter but still allowed scripts to run.  The policy for
> > > this
> > > wouldn't be hard to write, although I suspect it would be a total
> > > non-starter for everything but a fixed use case appliance.  I've
> > > CC'd
> > > Stephen, perhaps he's played with doing something like this.
> > 
> > load_script() calls open_exec() on the interpreter while still
> > running
> > in the caller's credentials, so the caller requires execute
> > permission
> > to the interpreter (and this is correct behavior).
> > 
> > TOMOYO/AppArmor have a way to defer the checking to the bprm hooks
> > (via
> > the current->in_execve flag, added by TOMOYO) so that they can
> > choose
> > whether to use the old or new credentials for the permission
> > checks,
> > but that only makes a difference if changing credentials on the
> > exec.
> 
> So with SELinux, is it possible to prevent the python interactive
> prompt/interpreter?

You would have to allow open, read, and execute permission to the
python interpreter even just to run python scripts.  You could refrain
from allowing execute_no_trans to the python interpreter, in which case
a direct execve() of the interpreter will fail but script execution can
still succeed.  Of course, to do this, you would need a distinct type
on the /usr/bin/python file, and the processes of interest would need
to run in confined domains (i.e. no use of unconfined domains, or at
least not within the scope of what you are trying to protect).  And
this only prevents direct execve() of the interpreter, nothing else.

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/security/Kconfig b/security/Kconfig
index 118f4549404e..8b12837ce933 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -164,6 +164,7 @@  source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/loadpin/Kconfig
 source security/yama/Kconfig
+source security/shebang/Kconfig
 
 source security/integrity/Kconfig
 
diff --git a/security/Makefile b/security/Makefile
index f2d71cdb8e19..00a8dbebb07f 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -9,6 +9,7 @@  subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
 subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
+subdir-$(CONFIG_SECURITY_SHEBANG)	+= shebang
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -24,6 +25,7 @@  obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
 obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
+obj-$(CONFIG_SECURITY_SHEBANG)		+= shebang/
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/shebang/Kconfig b/security/shebang/Kconfig
new file mode 100644
index 000000000000..c2e943159307
--- /dev/null
+++ b/security/shebang/Kconfig
@@ -0,0 +1,15 @@ 
+config SECURITY_SHEBANG
+	bool "Restrict python interactive prompt/interpreter"
+	depends on SECURITY
+	help
+	  Restrict python so that python scripts are allowed to execute,
+	  while the interactive prompt/interpreter is not available.  When
+	  used in conjunction with an IMA appraise policy requiring files
+	  signatures, only signed scripts will be executed.
+
+config SECURITY_INTERP_PATHNAME
+	string "interpreter pathname"
+	depends on SECURITY_SHEBANG
+	default "/usr/bin/python"
+	help
+	  This option defines a script interpreter pathname.
diff --git a/security/shebang/Makefile b/security/shebang/Makefile
new file mode 100644
index 000000000000..f1b83dcb96d1
--- /dev/null
+++ b/security/shebang/Makefile
@@ -0,0 +1,3 @@ 
+obj-$(CONFIG_SECURITY_SHEBANG) += shebang.o
+
+shebang-y := shebang_python.o
diff --git a/security/shebang/shebang_python.c b/security/shebang/shebang_python.c
new file mode 100644
index 000000000000..5f319badd2b3
--- /dev/null
+++ b/security/shebang/shebang_python.c
@@ -0,0 +1,50 @@ 
+/*
+ * shebang security module
+ *
+ * Copyright (C) 2017 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "shebang: " fmt
+#include <linux/module.h>
+#include <linux/binfmts.h>
+#include <linux/lsm_hooks.h>
+
+static char *pathname;
+
+/**
+ * shebang_bprm_check
+ * @bprm: contains the linux_binprm structure
+ */
+int shebang_bprm_check(struct linux_binprm *bprm)
+{
+	if ((bprm->interp == bprm->filename) &&
+	    strcmp(bprm->interp, pathname) == 0) {
+		pr_info("prevent executing %s \n", bprm->interp);
+		return -EPERM;
+	}
+	return 0;
+}
+
+static struct security_hook_list shebang_hooks[] = {
+	LSM_HOOK_INIT(bprm_check_security, shebang_bprm_check)
+};
+
+static int __init init_shebang(void)
+{
+	pathname = kstrdup(CONFIG_SECURITY_INTERP_PATHNAME, GFP_KERNEL);
+	security_add_hooks(shebang_hooks, ARRAY_SIZE(shebang_hooks), "shebang");
+	pr_info("initialized\n");
+	return 0;
+}
+
+late_initcall(init_shebang);
+
+MODULE_LICENSE("GPL");