Message ID | 20200505153156.925111-2-mic@digikod.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add support for O_MAYEXEC | expand |
On Tue, May 05, 2020 at 05:31:51PM +0200, Mickaël Salaün wrote: > When the O_MAYEXEC flag is passed, openat2(2) may be subject to > additional restrictions depending on a security policy managed by the > kernel through a sysctl or implemented by an LSM thanks to the > inode_permission hook. This new flag is ignored by open(2) and > openat(2). > > The underlying idea is to be able to restrict scripts interpretation > according to a policy defined by the system administrator. For this to > be possible, script interpreters must use the O_MAYEXEC flag > appropriately. To be fully effective, these interpreters also need to > handle the other ways to execute code: command line parameters (e.g., > option -e for Perl), module loading (e.g., option -m for Python), stdin, > file sourcing, environment variables, configuration files, etc. > According to the threat model, it may be acceptable to allow some script > interpreters (e.g. Bash) to interpret commands from stdin, may it be a > TTY or a pipe, because it may not be enough to (directly) perform > syscalls. Further documentation can be found in a following patch. You touch on this lightly in the cover letter, but it seems there are plans for Python to restrict stdin parsing? Are there patches pending anywhere for other interpreters? (e.g. does CLIP OS have such patches?) There's always a push-back against adding features that have external dependencies, and then those external dependencies can't happen without the kernel first adding a feature. :) I like getting these catch-22s broken, and I think the kernel is the right place to start, especially since the threat model (and implementation) is already proven out in CLIP OS, and now with IMA. So, while the interpreter side of this is still under development, this gives them the tool they need to get it done on the kernel side. So showing those pieces (as you've done) is great, and I think finding a little bit more detail here would be even better. > A simple security policy implementation, configured through a dedicated > sysctl, is available in a following patch. > > This is an updated subset of the patch initially written by Vincent > Strubel for CLIP OS 4: > https://github.com/clipos-archive/src_platform_clip-patches/blob/f5cb330d6b684752e403b4e41b39f7004d88e561/1901_open_mayexec.patch > This patch has been used for more than 11 years with customized script > interpreters. Some examples (with the original name O_MAYEXEC) can be > found here: > https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC > > Signed-off-by: Mickaël Salaün <mic@digikod.net> > Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> > Signed-off-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr> nit: this needs to be reordered. It's expected that the final SoB matches the sender. If you're trying to show co-authorship, please see: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by Based on what I've inferred about author ordering, I think you want: Co-developed-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr> Signed-off-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr> Co-developed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> Co-developed-by: Mickaël Salaün <mic@digikod.net> Signed-off-by: Mickaël Salaün <mic@digikod.net> > Reviewed-by: Deven Bowers <deven.desai@linux.microsoft.com> > Cc: Aleksa Sarai <cyphar@cyphar.com> > Cc: Al Viro <viro@zeniv.linux.org.uk> > Cc: Kees Cook <keescook@chromium.org> Everything else appears good to me, but Al and Aleksa know VFS internals way better. :) Reviewed-by: Kees Cook <keescook@chromium.org>
On 12/05/2020 23.05, Kees Cook wrote: > On Tue, May 05, 2020 at 05:31:51PM +0200, Mickaël Salaün wrote: >> When the O_MAYEXEC flag is passed, openat2(2) may be subject to >> additional restrictions depending on a security policy managed by the >> kernel through a sysctl or implemented by an LSM thanks to the >> inode_permission hook. This new flag is ignored by open(2) and >> openat(2). >> >> The underlying idea is to be able to restrict scripts interpretation >> according to a policy defined by the system administrator. For this to >> be possible, script interpreters must use the O_MAYEXEC flag >> appropriately. To be fully effective, these interpreters also need to >> handle the other ways to execute code: command line parameters (e.g., >> option -e for Perl), module loading (e.g., option -m for Python), stdin, >> file sourcing, environment variables, configuration files, etc. >> According to the threat model, it may be acceptable to allow some script >> interpreters (e.g. Bash) to interpret commands from stdin, may it be a >> TTY or a pipe, because it may not be enough to (directly) perform >> syscalls. Further documentation can be found in a following patch. > > You touch on this lightly in the cover letter, but it seems there are > plans for Python to restrict stdin parsing? Are there patches pending > anywhere for other interpreters? (e.g. does CLIP OS have such patches?) > > There's always a push-back against adding features that have external > dependencies, and then those external dependencies can't happen without > the kernel first adding a feature. :) I like getting these catch-22s > broken, and I think the kernel is the right place to start, especially > since the threat model (and implementation) is already proven out in > CLIP OS, and now with IMA. So, while the interpreter side of this is > still under development, this gives them the tool they need to get it > done on the kernel side. So showing those pieces (as you've done) is > great, and I think finding a little bit more detail here would be even > better. Hi, Python core dev here. Yes, there are plans to use feature for Python in combination with additional restrictions. For backwards compatibility reasons we cannot change the behavior of the default Python interpreter. I have plans to provide a restricted Python binary that prohibits piping from stdin, disables -c "some_code()", restricts import locations, and a couple of other things. O_MAYEXEC flag makes it easier to block imports from noexec filesystems. My PoC [1] for a talk [2] last year is inspired by IMA appraisal and a previous talk by Mickaël on O_MAYEXEC. Christian [1] https://github.com/zooba/spython/blob/master/linux_xattr/spython.c [2] https://speakerdeck.com/tiran/europython-2019-auditing-hooks-and-security-transparency-for-cpython
On Tue, May 12, 2020 at 11:40:35PM +0200, Christian Heimes wrote: > On 12/05/2020 23.05, Kees Cook wrote: > > On Tue, May 05, 2020 at 05:31:51PM +0200, Mickaël Salaün wrote: > >> When the O_MAYEXEC flag is passed, openat2(2) may be subject to > >> additional restrictions depending on a security policy managed by the > >> kernel through a sysctl or implemented by an LSM thanks to the > >> inode_permission hook. This new flag is ignored by open(2) and > >> openat(2). > >> > >> The underlying idea is to be able to restrict scripts interpretation > >> according to a policy defined by the system administrator. For this to > >> be possible, script interpreters must use the O_MAYEXEC flag > >> appropriately. To be fully effective, these interpreters also need to > >> handle the other ways to execute code: command line parameters (e.g., > >> option -e for Perl), module loading (e.g., option -m for Python), stdin, > >> file sourcing, environment variables, configuration files, etc. > >> According to the threat model, it may be acceptable to allow some script > >> interpreters (e.g. Bash) to interpret commands from stdin, may it be a > >> TTY or a pipe, because it may not be enough to (directly) perform > >> syscalls. Further documentation can be found in a following patch. > > > > You touch on this lightly in the cover letter, but it seems there are > > plans for Python to restrict stdin parsing? Are there patches pending > > anywhere for other interpreters? (e.g. does CLIP OS have such patches?) > > > > There's always a push-back against adding features that have external > > dependencies, and then those external dependencies can't happen without > > the kernel first adding a feature. :) I like getting these catch-22s > > broken, and I think the kernel is the right place to start, especially > > since the threat model (and implementation) is already proven out in > > CLIP OS, and now with IMA. So, while the interpreter side of this is > > still under development, this gives them the tool they need to get it > > done on the kernel side. So showing those pieces (as you've done) is > > great, and I think finding a little bit more detail here would be even > > better. > > Hi, > > Python core dev here. > > Yes, there are plans to use feature for Python in combination with > additional restrictions. For backwards compatibility reasons we cannot > change the behavior of the default Python interpreter. I have plans to > provide a restricted Python binary that prohibits piping from stdin, > disables -c "some_code()", restricts import locations, and a couple of > other things. O_MAYEXEC flag makes it easier to block imports from > noexec filesystems. > > My PoC [1] for a talk [2] last year is inspired by IMA appraisal and a > previous talk by Mickaël on O_MAYEXEC. > > Christian > > [1] https://github.com/zooba/spython/blob/master/linux_xattr/spython.c > [2] > https://speakerdeck.com/tiran/europython-2019-auditing-hooks-and-security-transparency-for-cpython Ah, fantastic; thank you! Yes, this will go a long way for helping demonstration to other folks that there are people who will be using this feature. :)
On 12/05/2020 23:05, Kees Cook wrote: > On Tue, May 05, 2020 at 05:31:51PM +0200, Mickaël Salaün wrote: >> When the O_MAYEXEC flag is passed, openat2(2) may be subject to >> additional restrictions depending on a security policy managed by the >> kernel through a sysctl or implemented by an LSM thanks to the >> inode_permission hook. This new flag is ignored by open(2) and >> openat(2). >> >> The underlying idea is to be able to restrict scripts interpretation >> according to a policy defined by the system administrator. For this to >> be possible, script interpreters must use the O_MAYEXEC flag >> appropriately. To be fully effective, these interpreters also need to >> handle the other ways to execute code: command line parameters (e.g., >> option -e for Perl), module loading (e.g., option -m for Python), stdin, >> file sourcing, environment variables, configuration files, etc. >> According to the threat model, it may be acceptable to allow some script >> interpreters (e.g. Bash) to interpret commands from stdin, may it be a >> TTY or a pipe, because it may not be enough to (directly) perform >> syscalls. Further documentation can be found in a following patch. > > You touch on this lightly in the cover letter, but it seems there are > plans for Python to restrict stdin parsing? Are there patches pending > anywhere for other interpreters? (e.g. does CLIP OS have such patches?) There is some example from CLIP OS 4 here : https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC If you take a look at the whole pointed patches there is more than the O_MAYEXEC changes (which matches this search) e.g., to prevent Python interactive execution. There is patches for Bash, Wine, Java (Icedtea), Busybox's ash, Perl and Python. There is also some related patches which do not directly rely on O_MAYEXEC but which restrict the use of browser plugins and extensions, which may be seen as scripts too: https://github.com/clipos-archive/clipos4_portage-overlay/tree/master/www-client > > There's always a push-back against adding features that have external > dependencies, and then those external dependencies can't happen without > the kernel first adding a feature. :) I like getting these catch-22s > broken, and I think the kernel is the right place to start, especially > since the threat model (and implementation) is already proven out in > CLIP OS, and now with IMA. So, while the interpreter side of this is > still under development, this gives them the tool they need to get it > done on the kernel side. So showing those pieces (as you've done) is > great, and I think finding a little bit more detail here would be even > better. OK, I can add my previous comment in the next cover letter. > >> A simple security policy implementation, configured through a dedicated >> sysctl, is available in a following patch. >> >> This is an updated subset of the patch initially written by Vincent >> Strubel for CLIP OS 4: >> https://github.com/clipos-archive/src_platform_clip-patches/blob/f5cb330d6b684752e403b4e41b39f7004d88e561/1901_open_mayexec.patch >> This patch has been used for more than 11 years with customized script >> interpreters. Some examples (with the original name O_MAYEXEC) can be >> found here: >> https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC >> >> Signed-off-by: Mickaël Salaün <mic@digikod.net> >> Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> >> Signed-off-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr> > > nit: this needs to be reordered. It's expected that the final SoB > matches the sender. OK, I just sorted the list alphabetically. > If you're trying to show co-authorship, please > see: > > https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by > > Based on what I've inferred about author ordering, I think you want: > > Co-developed-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr> > Signed-off-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr> > Co-developed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> > Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> > Co-developed-by: Mickaël Salaün <mic@digikod.net> > Signed-off-by: Mickaël Salaün <mic@digikod.net> OK, according to the doc I'll remove myself as Co-developped-by because I'm already in the From, though. > >> Reviewed-by: Deven Bowers <deven.desai@linux.microsoft.com> >> Cc: Aleksa Sarai <cyphar@cyphar.com> >> Cc: Al Viro <viro@zeniv.linux.org.uk> >> Cc: Kees Cook <keescook@chromium.org> > > Everything else appears good to me, but Al and Aleksa know VFS internals > way better. :) > > Reviewed-by: Kees Cook <keescook@chromium.org> > Thanks!
diff --git a/fs/fcntl.c b/fs/fcntl.c index 2e4c0fa2074b..0357ad667563 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -1033,7 +1033,7 @@ static int __init fcntl_init(void) * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ - BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != + BUILD_BUG_ON(22 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | __FMODE_EXEC | __FMODE_NONOTIFY)); diff --git a/fs/open.c b/fs/open.c index 719b320ede52..f3f08a36d1d2 100644 --- a/fs/open.c +++ b/fs/open.c @@ -962,6 +962,8 @@ inline struct open_how build_open_how(int flags, umode_t mode) .mode = mode & S_IALLUGO, }; + /* O_MAYEXEC is ignored by syscalls relying on build_open_how(). */ + how.flags &= ~O_MAYEXEC; /* O_PATH beats everything else. */ if (how.flags & O_PATH) how.flags &= O_PATH_FLAGS; @@ -1029,6 +1031,12 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) if (flags & __O_SYNC) flags |= O_DSYNC; + /* Checks execution permissions on open. */ + if (flags & O_MAYEXEC) { + acc_mode |= MAY_OPENEXEC; + flags |= __FMODE_EXEC; + } + op->open_flag = flags; /* O_TRUNC implies we need access checks for write permissions */ diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index 7bcdcf4f6ab2..e188a360fa5f 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h @@ -10,7 +10,7 @@ (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \ FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_MAYEXEC) /* List of all valid flags for the how->upgrade_mask argument: */ #define VALID_UPGRADE_FLAGS \ diff --git a/include/linux/fs.h b/include/linux/fs.h index 4f6f59b4f22a..313c934de9ee 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -101,6 +101,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define MAY_CHDIR 0x00000040 /* called from RCU mode, don't block */ #define MAY_NOT_BLOCK 0x00000080 +/* the inode is opened with O_MAYEXEC */ +#define MAY_OPENEXEC 0x00000100 /* * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 9dc0bf0c5a6e..bca90620119f 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -97,6 +97,13 @@ #define O_NDELAY O_NONBLOCK #endif +/* + * Code execution from file is intended, checks such permission. A simple + * policy can be enforced system-wide as explained in + * Documentation/admin-guide/sysctl/fs.rst . + */ +#define O_MAYEXEC 040000000 + #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ #define F_SETFD 2 /* set/clear close_on_exec */