Message ID | 20211110190626.257017-2-mic@digikod.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add trusted_for(2) (was O_MAYEXEC) | expand |
Hi Mickaël, On 11/10/21 20:06, Mickaël Salaün wrote: > diff --git a/fs/open.c b/fs/open.c > index f732fb94600c..96a80abec41b 100644 > --- a/fs/open.c > +++ b/fs/open.c > @@ -480,6 +482,114 @@ SYSCALL_DEFINE2(access, const char __user *, filename, int, mode) > return do_faccessat(AT_FDCWD, filename, mode, 0); > } > > +#define TRUST_POLICY_EXEC_MOUNT BIT(0) > +#define TRUST_POLICY_EXEC_FILE BIT(1) > + > +int sysctl_trusted_for_policy __read_mostly; > + > +/** ... > + */ > +SYSCALL_DEFINE3(trusted_for, const int, fd, const enum trusted_for_usage, usage, Please, don't use enums for interfaces. They are implementation defined types, and vary between compilers and within the same compiler also depending on optimization flags. C17::6.7.2.2.4: [ Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined,130) but shall be capable of representing the values of all the members of the enumeration. ] See also: <https://stackoverflow.com/questions/366017/what-is-the-size-of-an-enum-in-c> So, please use only standard integer types for interfaces. And in the case of enums, since the language specifies that enumeration constants (the macro-like identifiers) are of type int, it makes sense for functions to use int. C17::6.7.2.2.3: [ The identifiers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted. ] I'd use an int for the API/ABI, even if it's expected to be assigned values of 'enum trusted_for_usage' (that should be specified in the manual page in DESCRIPTION, but not in SYNOPSIS, which should specify int). TL;DR: ISO C specifies that for the following code: enum foo {BAR}; enum foo foobar; typeof(foo) shall be int typeof(foobar) is implementation-defined Since foobar = BAR; assigns an int, the best thing to do to avoid implementation-defined behavior, is to declare foobar as int too. > diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h > index 528a478dbda8..c535e0e43cc8 100644 > --- a/include/linux/syscalls.h > +++ b/include/linux/syscalls.h > @@ -462,6 +463,7 @@ asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); > asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode); > asmlinkage long sys_faccessat2(int dfd, const char __user *filename, int mode, > int flags); > +asmlinkage long sys_trusted_for(int fd, enum trusted_for_usage usage, u32 flags); Same here. > asmlinkage long sys_chdir(const char __user *filename); > asmlinkage long sys_fchdir(unsigned int fd); > asmlinkage long sys_chroot(const char __user *filename); Thanks, Alex
On 12/11/2021 20:16, Alejandro Colomar (man-pages) wrote: > Hi Mickaël, Hi Alejandro, > > On 11/10/21 20:06, Mickaël Salaün wrote: >> diff --git a/fs/open.c b/fs/open.c >> index f732fb94600c..96a80abec41b 100644 >> --- a/fs/open.c >> +++ b/fs/open.c >> @@ -480,6 +482,114 @@ SYSCALL_DEFINE2(access, const char __user *, >> filename, int, mode) >> return do_faccessat(AT_FDCWD, filename, mode, 0); >> } >> +#define TRUST_POLICY_EXEC_MOUNT BIT(0) >> +#define TRUST_POLICY_EXEC_FILE BIT(1) >> + >> +int sysctl_trusted_for_policy __read_mostly; >> + >> +/** > ... >> + */ >> +SYSCALL_DEFINE3(trusted_for, const int, fd, const enum >> trusted_for_usage, usage, > > Please, don't use enums for interfaces. They are implementation defined > types, and vary between compilers and within the same compiler also > depending on optimization flags. > > C17::6.7.2.2.4: > [ > Each enumerated type shall be compatible with char, > a signed integer type, or an unsigned integer type. > The choice of type is implementation-defined,130) > but shall be capable of representing the values of > all the members of the enumeration. > ] > > See also: > <https://stackoverflow.com/questions/366017/what-is-the-size-of-an-enum-in-c> > > > So, please use only standard integer types for interfaces. > > And in the case of enums, since the language specifies that enumeration > constants (the macro-like identifiers) are of type int, it makes sense > for functions to use int. > > C17::6.7.2.2.3: > [ > The identifiers in an enumerator list are declared as constants > that have type int and may appear wherever such are permitted. > ] > > I'd use an int for the API/ABI, even if it's expected to be assigned > values of 'enum trusted_for_usage' (that should be specified in the > manual page in DESCRIPTION, but not in SYNOPSIS, which should specify int). > > > > TL;DR: > > ISO C specifies that for the following code: > > enum foo {BAR}; > > enum foo foobar; > > typeof(foo) shall be int > typeof(foobar) is implementation-defined I tested with some version of GCC (from 4.9 to 11) and clang (10 and 11) with different optimizations and the related sizes are at least the same as for the int type. > > Since foobar = BAR; assigns an int, the best thing to do to avoid > implementation-defined behavior, is to declare foobar as int too. OK, so it should be enough to change the syscall argument type from enum trusted_for_usage to int, but we can keep the UAPI with the enum (i.e. we don't need to change the value to #define TRUSTED_FOR_EXECUTION 1) right? > > >> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h >> index 528a478dbda8..c535e0e43cc8 100644 >> --- a/include/linux/syscalls.h >> +++ b/include/linux/syscalls.h >> @@ -462,6 +463,7 @@ asmlinkage long sys_fallocate(int fd, int mode, >> loff_t offset, loff_t len); >> asmlinkage long sys_faccessat(int dfd, const char __user *filename, >> int mode); >> asmlinkage long sys_faccessat2(int dfd, const char __user *filename, >> int mode, >> int flags); >> +asmlinkage long sys_trusted_for(int fd, enum trusted_for_usage usage, >> u32 flags); > > Same here. > >> asmlinkage long sys_chdir(const char __user *filename); >> asmlinkage long sys_fchdir(unsigned int fd); >> asmlinkage long sys_chroot(const char __user *filename); > > Thanks, > Alex > >
Hi Mickaël, On 11/13/21 14:02, Mickaël Salaün wrote: >> TL;DR: >> >> ISO C specifies that for the following code: >> >> enum foo {BAR}; >> >> enum foo foobar; >> >> typeof(foo) shall be int >> typeof(foobar) is implementation-defined > > I tested with some version of GCC (from 4.9 to 11) and clang (10 and 11) > with different optimizations and the related sizes are at least the same > as for the int type. GCC has -fshort-enums to make enum types be as short as possible. I expected -Os to turn this on, since it saves space, but it doesn't. Still, not relying on enum == int is better, IMO. > >> >> Since foobar = BAR; assigns an int, the best thing to do to avoid >> implementation-defined behavior, is to declare foobar as int too. > > OK, so it should be enough to change the syscall argument type from enum > trusted_for_usage to int, but we can keep the UAPI with the enum (i.e. > we don't need to change the value to #define TRUSTED_FOR_EXECUTION 1) right? Correct. The enumerations are guaranteed to be int (except in case of UB, see below), so they'll be (almost) the same as a #define after the preprocessor. If you do enum foo { FOO = 1L << INT_WIDTH }; since that doesn't fit in either int or unsigned int, it is Undefined Behavior, and here GCC decides to use long for FOO. +++++++++ UB example ++++++++++++++ $ cat foo.c #include <limits.h> #include <stdio.h> enum foo { FOO = 1L << UINT_WIDTH }; int main(void) { printf("\tsizeof(enum foo) = %zu\n", sizeof(enum foo)); printf("\tsizeof(FOO) = %zu\n", sizeof(FOO)); } $ cc foo.c -Wall -Wextra -Werror -Wpedantic -pedantic-errors -std=c2x foo.c:6:23: error: ISO C restricts enumerator values to range of 'int' [-Wpedantic] 6 | FOO = 1L << UINT_WIDTH | ^~ $ cc foo.c -Wall -Wextra -Werror -std=c2x $ ./a.out sizeof(enum foo) = 8 sizeof(FOO) = 8 +++++++++++++ -fshort-enums example +++++++++++++++ $ cat foo.c #include <stdio.h> enum foo { FOO = 1 }; int main(void) { printf("\tsizeof(enum foo) = %zu\n", sizeof(enum foo)); printf("\tsizeof(FOO) = %zu\n", sizeof(FOO)); } $ cc foo.c -Wall -Wextra -Werror -Wpedantic -pedantic-errors -fshort-enums $ ./a.out sizeof(enum foo) = 1 sizeof(FOO) = 4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cheers, Alex > >> >> >>> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h >>> index 528a478dbda8..c535e0e43cc8 100644 >>> --- a/include/linux/syscalls.h >>> +++ b/include/linux/syscalls.h >>> @@ -462,6 +463,7 @@ asmlinkage long sys_fallocate(int fd, int mode, >>> loff_t offset, loff_t len); >>> asmlinkage long sys_faccessat(int dfd, const char __user *filename, >>> int mode); >>> asmlinkage long sys_faccessat2(int dfd, const char __user *filename, >>> int mode, >>> int flags); >>> +asmlinkage long sys_trusted_for(int fd, enum trusted_for_usage usage, >>> u32 flags); >> >> Same here. >> >>> asmlinkage long sys_chdir(const char __user *filename); >>> asmlinkage long sys_fchdir(unsigned int fd); >>> asmlinkage long sys_chroot(const char __user *filename); >> >> Thanks, >> Alex >> >>
On 13/11/2021 20:56, Alejandro Colomar (man-pages) wrote: > Hi Mickaël, > > On 11/13/21 14:02, Mickaël Salaün wrote: >>> TL;DR: >>> >>> ISO C specifies that for the following code: >>> >>> enum foo {BAR}; >>> >>> enum foo foobar; >>> >>> typeof(foo) shall be int >>> typeof(foobar) is implementation-defined >> >> I tested with some version of GCC (from 4.9 to 11) and clang (10 and 11) >> with different optimizations and the related sizes are at least the same >> as for the int type. > > GCC has -fshort-enums to make enum types be as short as possible. I > expected -Os to turn this on, since it saves space, but it doesn't. > > Still, not relying on enum == int is better, IMO. > >> >>> >>> Since foobar = BAR; assigns an int, the best thing to do to avoid >>> implementation-defined behavior, is to declare foobar as int too. >> >> OK, so it should be enough to change the syscall argument type from enum >> trusted_for_usage to int, but we can keep the UAPI with the enum (i.e. >> we don't need to change the value to #define TRUSTED_FOR_EXECUTION 1) >> right? > > Correct. The enumerations are guaranteed to be int (except in case of > UB, see below), so they'll be (almost) the same as a #define after the > preprocessor. Thanks for the detailed explanation! I'll send a new patch taking into account your suggestion. > > > If you do > > enum foo { > FOO = 1L << INT_WIDTH > }; > > since that doesn't fit in either int or unsigned int, > it is Undefined Behavior, > and here GCC decides to use long for FOO. > > +++++++++ UB example ++++++++++++++ > > $ cat foo.c > #include <limits.h> > #include <stdio.h> > > > enum foo { > FOO = 1L << UINT_WIDTH > }; > > int main(void) > { > printf("\tsizeof(enum foo) = %zu\n", sizeof(enum foo)); > printf("\tsizeof(FOO) = %zu\n", sizeof(FOO)); > } > > $ cc foo.c -Wall -Wextra -Werror -Wpedantic -pedantic-errors -std=c2x > foo.c:6:23: error: ISO C restricts enumerator values to range of 'int' > [-Wpedantic] > 6 | FOO = 1L << UINT_WIDTH > | ^~ > $ cc foo.c -Wall -Wextra -Werror -std=c2x > $ ./a.out > sizeof(enum foo) = 8 > sizeof(FOO) = 8 > > +++++++++++++ -fshort-enums example +++++++++++++++ > > $ cat foo.c > #include <stdio.h> > > > enum foo { > FOO = 1 > }; > > int main(void) > { > printf("\tsizeof(enum foo) = %zu\n", sizeof(enum foo)); > printf("\tsizeof(FOO) = %zu\n", sizeof(FOO)); > } > > $ cc foo.c -Wall -Wextra -Werror -Wpedantic -pedantic-errors -fshort-enums > $ ./a.out > sizeof(enum foo) = 1 > sizeof(FOO) = 4 > > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > Cheers, > Alex > > >> >>> >>> >>>> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h >>>> index 528a478dbda8..c535e0e43cc8 100644 >>>> --- a/include/linux/syscalls.h >>>> +++ b/include/linux/syscalls.h >>>> @@ -462,6 +463,7 @@ asmlinkage long sys_fallocate(int fd, int mode, >>>> loff_t offset, loff_t len); >>>> asmlinkage long sys_faccessat(int dfd, const char __user *filename, >>>> int mode); >>>> asmlinkage long sys_faccessat2(int dfd, const char __user *filename, >>>> int mode, >>>> int flags); >>>> +asmlinkage long sys_trusted_for(int fd, enum trusted_for_usage usage, >>>> u32 flags); >>> >>> Same here. >>> >>>> asmlinkage long sys_chdir(const char __user *filename); >>>> asmlinkage long sys_fchdir(unsigned int fd); >>>> asmlinkage long sys_chroot(const char __user *filename); >>> >>> Thanks, >>> Alex >>> >>> >
Hi Alejandro, On Sat, Nov 13, 2021 at 8:56 PM Alejandro Colomar (man-pages) <alx.manpages@gmail.com> wrote: > On 11/13/21 14:02, Mickaël Salaün wrote: > >> TL;DR: > >> > >> ISO C specifies that for the following code: > >> > >> enum foo {BAR}; > >> > >> enum foo foobar; > >> > >> typeof(foo) shall be int > >> typeof(foobar) is implementation-defined > > > > I tested with some version of GCC (from 4.9 to 11) and clang (10 and 11) > > with different optimizations and the related sizes are at least the same > > as for the int type. > > GCC has -fshort-enums to make enum types be as short as possible. I > expected -Os to turn this on, since it saves space, but it doesn't. Changing optimization level must not change the ABI, else debugging would become even more of a nightmare. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Geert, On 11/14/21 16:32, Geert Uytterhoeven wrote: > Hi Alejandro, > > On Sat, Nov 13, 2021 at 8:56 PM Alejandro Colomar (man-pages) > <alx.manpages@gmail.com> wrote: >> On 11/13/21 14:02, Mickaël Salaün wrote: >>>> TL;DR: >>>> >>>> ISO C specifies that for the following code: >>>> >>>> enum foo {BAR}; >>>> >>>> enum foo foobar; >>>> >>>> typeof(foo) shall be int >>>> typeof(foobar) is implementation-defined >>> >>> I tested with some version of GCC (from 4.9 to 11) and clang (10 and 11) >>> with different optimizations and the related sizes are at least the same >>> as for the int type. >> >> GCC has -fshort-enums to make enum types be as short as possible. I >> expected -Os to turn this on, since it saves space, but it doesn't. > > Changing optimization level must not change the ABI, else debugging > would become even more of a nightmare. I agree, but if you invoke implementation-defined, then it's not (only) the compiler's fault. Instead of not allowing GCC to enable -fshort-enums ever, one can write ISO C-complying code in the parts that will be exposed as an interface, by just using int. That allows using -fshort-enums for whatever reasons it might be good. Not saying that the kernel wants to enable it, but it costs nothing to write non-implementation-defined code that doesn't forbid it. It's comparable to passing a struct (not a pointer to it) to a function. If you change the size of the struct, you screw the interface. Better pass pointers, or standard types. Cheers, Alex
diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst index 2a501c9ddc55..e364d6c45790 100644 --- a/Documentation/admin-guide/sysctl/fs.rst +++ b/Documentation/admin-guide/sysctl/fs.rst @@ -48,6 +48,7 @@ Currently, these files are in /proc/sys/fs: - suid_dumpable - super-max - super-nr +- trusted_for_policy aio-nr & aio-max-nr @@ -382,3 +383,52 @@ Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes on a 64bit one. The current default value for max_user_watches is the 1/25 (4%) of the available low memory, divided for the "watch" cost in bytes. + + +trusted_for_policy +------------------ + +An interpreter can call :manpage:`trusted_for(2)` with a +``TRUSTED_FOR_EXECUTION`` usage to check that opened regular files are expected +to be executable. If the file is not identified as executable, then the +syscall returns -EACCES. This may allow a script interpreter to check +executable permission before reading commands from a file, or a dynamic linker +to only load executable shared objects. One interesting use case is to enforce +a "write xor execute" policy through interpreters. + +The ability to restrict code execution must be thought as a system-wide policy, +which first starts by restricting mount points with the ``noexec`` option. +This option is also automatically applied to special filesystems such as /proc . +This prevents files on such mount points to be directly executed by the kernel +or mapped as executable memory (e.g. libraries). With script interpreters +using :manpage:`trusted_for(2)`, the executable permission can then be checked +before reading commands from files. This makes it possible to enforce the +``noexec`` at the interpreter level, and thus propagates this security policy +to scripts. 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. + +There are two complementary security policies: enforce the ``noexec`` mount +option, and enforce executable file permission. These policies are handled by +the ``fs.trusted_for_policy`` sysctl (writable only with ``CAP_SYS_ADMIN``) as +a bitmask: + +1 - Mount restriction: checks that the mount options for the underlying VFS + mount do not prevent execution. + +2 - File permission restriction: checks that the file is marked as + executable for the current process (e.g., POSIX permissions, ACLs). + +Note that as long as a policy is enforced, checking any non-regular file with +:manpage:`trusted_for(2)` returns -EACCES (e.g. TTYs, pipe), even when such a +file is marked as executable or is on an executable mount point. + +Code samples can be found in +tools/testing/selftests/interpreter/trust_policy_test.c and interpreter patches +(for the original O_MAYEXEC) are available at +https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC . +See also an overview article: https://lwn.net/Articles/820000/ . diff --git a/fs/open.c b/fs/open.c index f732fb94600c..96a80abec41b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -32,6 +32,8 @@ #include <linux/ima.h> #include <linux/dnotify.h> #include <linux/compat.h> +#include <linux/sysctl.h> +#include <uapi/linux/trusted-for.h> #include "internal.h" @@ -480,6 +482,114 @@ SYSCALL_DEFINE2(access, const char __user *, filename, int, mode) return do_faccessat(AT_FDCWD, filename, mode, 0); } +#define TRUST_POLICY_EXEC_MOUNT BIT(0) +#define TRUST_POLICY_EXEC_FILE BIT(1) + +int sysctl_trusted_for_policy __read_mostly; + +/** + * sys_trusted_for - Check that a FD is trusted for a specific usage + * + * @fd: File descriptor to check. + * @usage: Identify the user space usage intended for the file descriptor (only + * TRUSTED_FOR_EXECUTION for now). + * @flags: Must be 0. + * + * This system call enables user space to ask the kernel: is this file + * descriptor's content trusted to be used for this purpose? The set of @usage + * currently only contains TRUSTED_FOR_EXECUTION, but other may follow (e.g. + * configuration, sensitive data). If the kernel identifies the file + * descriptor as trustworthy for this usage, this call returns 0 and the caller + * should then take this information into account. + * + * The execution usage means that the content of the file descriptor is trusted + * according to the system policy to be executed by user space, which means + * that it interprets the content or (try to) maps it as executable memory. + * + * A simple system-wide security policy can be set by the system administrator + * through a sysctl configuration consistent with the mount points or the file + * access rights: Documentation/admin-guide/sysctl/fs.rst + * + * @flags could be used in the future to do complementary checks (e.g. + * signature or integrity requirements, origin of the file). + * + * Possible returned errors are: + * + * - EINVAL: unknown @usage or unknown @flags; + * - EBADF: @fd is not a file descriptor for the calling thread; + * - EACCES: the requested usage is denied (and user space should enforce it). + */ +SYSCALL_DEFINE3(trusted_for, const int, fd, const enum trusted_for_usage, usage, + const u32, flags) +{ + int mask, err = -EACCES; + struct fd f; + struct inode *inode; + + if (flags) + return -EINVAL; + + /* Only handles execution for now. */ + if (usage != TRUSTED_FOR_EXECUTION) + return -EINVAL; + mask = MAY_EXEC; + + f = fdget(fd); + if (!f.file) + return -EBADF; + inode = file_inode(f.file); + + /* + * For compatibility reasons, without a defined security policy, we + * must map the execute permission to the read permission. Indeed, + * from user space point of view, being able to execute data (e.g. + * scripts) implies to be able to read this data. + */ + if ((mask & MAY_EXEC)) { + /* + * If there is a system-wide execute policy enforced, then + * forbids access to non-regular files and special superblocks. + */ + if ((sysctl_trusted_for_policy & (TRUST_POLICY_EXEC_MOUNT | + TRUST_POLICY_EXEC_FILE))) { + if (!S_ISREG(inode->i_mode)) + goto out_fd; + /* + * Denies access to pseudo filesystems that will never + * be mountable (e.g. sockfs, pipefs) but can still be + * reachable through /proc/self/fd, or memfd-like file + * descriptors, or nsfs-like files. + * + * According to the selftests, SB_NOEXEC seems to be + * only used by proc and nsfs filesystems. + */ + if ((f.file->f_path.dentry->d_sb->s_flags & + (SB_NOUSER | SB_KERNMOUNT | SB_NOEXEC))) + goto out_fd; + } + + if ((sysctl_trusted_for_policy & TRUST_POLICY_EXEC_MOUNT) && + path_noexec(&f.file->f_path)) + goto out_fd; + /* + * For compatibility reasons, if the system-wide policy doesn't + * enforce file permission checks, then replaces the execute + * permission request with a read permission request. + */ + if (!(sysctl_trusted_for_policy & TRUST_POLICY_EXEC_FILE)) + mask &= ~MAY_EXEC; + /* To be executed *by* user space, files must be readable. */ + mask |= MAY_READ; + } + + err = inode_permission(file_mnt_user_ns(f.file), inode, + mask | MAY_ACCESS); + +out_fd: + fdput(f); + return err; +} + SYSCALL_DEFINE1(chdir, const char __user *, filename) { struct path path; diff --git a/include/linux/fs.h b/include/linux/fs.h index 3afca821df32..caea61fcb283 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -87,6 +87,7 @@ extern int sysctl_protected_symlinks; extern int sysctl_protected_hardlinks; extern int sysctl_protected_fifos; extern int sysctl_protected_regular; +extern int sysctl_trusted_for_policy; typedef __kernel_rwf_t rwf_t; diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 528a478dbda8..c535e0e43cc8 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -72,6 +72,7 @@ struct open_how; struct mount_attr; struct landlock_ruleset_attr; enum landlock_rule_type; +enum trusted_for_usage; #include <linux/types.h> #include <linux/aio_abi.h> @@ -462,6 +463,7 @@ asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode); asmlinkage long sys_faccessat2(int dfd, const char __user *filename, int mode, int flags); +asmlinkage long sys_trusted_for(int fd, enum trusted_for_usage usage, u32 flags); asmlinkage long sys_chdir(const char __user *filename); asmlinkage long sys_fchdir(unsigned int fd); asmlinkage long sys_chroot(const char __user *filename); diff --git a/include/uapi/linux/trusted-for.h b/include/uapi/linux/trusted-for.h new file mode 100644 index 000000000000..cc4f030c5103 --- /dev/null +++ b/include/uapi/linux/trusted-for.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_TRUSTED_FOR_H +#define _UAPI_LINUX_TRUSTED_FOR_H + +/** + * enum trusted_for_usage - Usage for which a file descriptor is trusted + * + * Argument of trusted_for(2). + */ +enum trusted_for_usage { + /** + * @TRUSTED_FOR_EXECUTION: Check that the data read from a file + * descriptor is trusted to be executed or interpreted (e.g. scripts). + */ + TRUSTED_FOR_EXECUTION = 1, +}; + +#endif /* _UAPI_LINUX_TRUSTED_FOR_H */ diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 083be6af29d7..002dc830c165 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -115,6 +115,7 @@ static int sixty = 60; static int __maybe_unused neg_one = -1; static int __maybe_unused two = 2; +static int __maybe_unused three = 3; static int __maybe_unused four = 4; static unsigned long zero_ul; static unsigned long one_ul = 1; @@ -936,7 +937,6 @@ static int proc_taint(struct ctl_table *table, int write, return err; } -#ifdef CONFIG_PRINTK static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { @@ -945,7 +945,6 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, return proc_dointvec_minmax(table, write, buffer, lenp, ppos); } -#endif /** * struct do_proc_dointvec_minmax_conv_param - proc_dointvec_minmax() range checking structure @@ -3357,6 +3356,15 @@ static struct ctl_table fs_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = &two, }, + { + .procname = "trusted_for_policy", + .data = &sysctl_trusted_for_policy, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_dointvec_minmax_sysadmin, + .extra1 = SYSCTL_ZERO, + .extra2 = &three, + }, #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) { .procname = "binfmt_misc",