Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions Documentation/admin-guide/sysctl/fs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ Currently, these files are in /proc/sys/fs:
- suid_dumpable
- super-max
- super-nr
- tpe
- tpe_restrict_all
- tpe_invert
- tpe_gid


aio-nr & aio-max-nr
Expand Down Expand Up @@ -326,6 +330,60 @@ This denotes the maximum number of mounts that may exist
in a mount namespace.


tpe
---

This indicates whether Trusted Path Execution (TPE) is
enabled.

When tpe is set to (0), TPE is disabled. When tpe is set
to (1), you will be able to choose a gid to add to the
supplementary groups of users you want to mark as "untrusted."
These users will not be able to execute any files that are not in
root-owned directories writable only by root. This makes it far
harder for attackers to execute their own code.

The kernel config option CONFIG_SECURITY_TPE sets the
default value of tpe.


tpe_restrict_all
----------------

If tpe_restrict_all is enabled, all non-root users will be covered under
a weaker TPE restriction. This is separate from, and in addition to,
the main TPE options that you have selected elsewhere. Thus, if a
"trusted" GID is chosen, this restriction applies to even that GID.
Under this restriction, all non-root users will only be allowed to
execute files in directories they own that are not group or
world-writable, or in directories owned by root and writable only by
root.

The kernel config option CONFIG_SECURITY_TPE_ALL sets the
default value of tpe_restrict_all.


tpe_invert
----------

If tpe_invert is enabled, the group you specify in the TPE configuration will
decide what group TPE restrictions will be *disabled* for. This
option is useful if you want TPE restrictions to be applied to most
users on the system.

The kernel config option CONFIG_SECURITY_TPE_INVERT sets the
default value of tpe_invert.


tpe_gid
-------

Setting this GID determines what group TPE restrictions will be
enabled or disabled for.

The kernel config option CONFIG_SECURITY_TPE_GID sets the
default value of tpe_gid.


2. /proc/sys/fs/binfmt_misc
===========================
Expand Down
2 changes: 1 addition & 1 deletion fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ obj-y := open.o read_write.o file_table.o super.o \
pnode.o splice.o sync.o utimes.o d_path.o \
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
fs_types.o fs_context.o fs_parser.o fsopen.o init.o \
kernel_read_file.o remap_range.o
kernel_read_file.o remap_range.o tpe.o

ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o block_dev.o direct-io.o mpage.o
Expand Down
5 changes: 5 additions & 0 deletions fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,11 @@ static int bprm_execve(struct linux_binprm *bprm,
if (retval)
goto out;

if (!tpe_allow(file)) {
retval = -EACCES;
goto out;
}

retval = exec_binprm(bprm);
if (retval < 0)
goto out;
Expand Down
75 changes: 75 additions & 0 deletions fs/tpe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/cred.h>
#include <linux/printk.h>

#define TPE_GLOBAL_UID(x) from_kuid_munged(&init_user_ns, (x))
#define TPE_GLOBAL_GID(x) from_kgid_munged(&init_user_ns, (x))
#define tpe_is_global_root(x) uid_eq((x), GLOBAL_ROOT_UID)
#define tpe_is_global_nonroot(x) (!uid_eq((x), GLOBAL_ROOT_UID))
#define tpe_is_global_nonroot_gid(x) (!gid_eq((x), GLOBAL_ROOT_GID))

int security_tpe = IS_ENABLED(CONFIG_SECURITY_TPE);
int security_tpe_all = IS_ENABLED(CONFIG_SECURITY_TPE_ALL);
int security_tpe_invert = IS_ENABLED(CONFIG_SECURITY_TPE_INVERT);
kgid_t security_tpe_gid = KGIDT_INIT(CONFIG_SECURITY_TPE_GID);

int
tpe_allow(const struct file *file)
{
struct inode *inode = d_backing_inode(file->f_path.dentry->d_parent);
struct inode *file_inode = d_backing_inode(file->f_path.dentry);
const struct cred *cred = current_cred();
char *msg = NULL;
char *msg2 = NULL;

if (!security_tpe)
return 1;

// never restrict root
if (tpe_is_global_root(cred->uid))
return 1;

if (security_tpe_all) {
if (tpe_is_global_nonroot(inode->i_uid) && !uid_eq(inode->i_uid, cred->uid))
msg = "directory not owned by user";
else if (inode->i_mode & S_IWOTH)
msg = "file in world-writable directory";
else if ((inode->i_mode & S_IWGRP) && tpe_is_global_nonroot_gid(inode->i_gid))
msg = "file in group-writable directory";
else if (file_inode->i_mode & S_IWOTH)
msg = "file is world-writable";
} else {
if (security_tpe_invert && !in_group_p(security_tpe_gid))
msg2 = "not being in trusted group";
else if (!security_tpe_invert && in_group_p(security_tpe_gid))
msg2 = "being in untrusted group";
else
return 1;

if (tpe_is_global_nonroot(inode->i_uid))
msg = "file in non-root-owned directory";
else if (inode->i_mode & S_IWOTH)
msg = "file in world-writable directory";
else if ((inode->i_mode & S_IWGRP) && tpe_is_global_nonroot_gid(inode->i_gid))
msg = "file in group-writable directory";
else if (file_inode->i_mode & S_IWOTH)
msg = "file is world-writable";
}

if (msg) {
char fullmsg[70] = {0};

if (msg2)
snprintf(fullmsg, sizeof(fullmsg)-1, "%s and %s", msg, msg2);
else
snprintf(fullmsg, sizeof(fullmsg)-1, "%s", msg);

pr_warn_ratelimited("TPE: denied attempt to execute file Reason: %s\n", fullmsg);
return 0;
}
return 1;
}
6 changes: 6 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ extern int sysctl_protected_hardlinks;
extern int sysctl_protected_fifos;
extern int sysctl_protected_regular;

extern int tpe_allow(const struct file *file);
extern int security_tpe;
extern int security_tpe_all;
extern int security_tpe_invert;
extern kgid_t security_tpe_gid;

typedef __kernel_rwf_t rwf_t;

struct buffer_head;
Expand Down
35 changes: 35 additions & 0 deletions kernel/sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3407,6 +3407,41 @@ static struct ctl_table fs_table[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ONE,
},
{
.procname = "tpe",
.data = &security_tpe,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax_sysadmin,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
{
.procname = "tpe_restrict_all",
.data = &security_tpe_all,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax_sysadmin,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
{
.procname = "tpe_invert",
.data = &security_tpe_invert,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax_sysadmin,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
{
.procname = "tpe_gid",
.data = &security_tpe_gid,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax_sysadmin,
.extra1 = SYSCTL_ZERO,
},
{ }
};

Expand Down
69 changes: 69 additions & 0 deletions security/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,75 @@ config SECURITY_TIOCSTI_RESTRICT

If you are unsure how to answer this question, answer N.

config SECURITY_TPE
bool "Trusted Path Execution (TPE)"
default n
help
If you say Y here, you will be able to choose a gid to add to the
supplementary groups of users you want to mark as "untrusted."
These users will not be able to execute any files that are not in
root-owned directories writable only by root.

This setting can be overridden at runtime via the fs.enable_tpe
sysctl.

If unsure, say N.

config SECURITY_TPE_ALL
bool "Partially restrict all non-root users"
depends on SECURITY_TPE
help
If you say Y here, all non-root users will be covered under
a weaker TPE restriction. This is separate from, and in addition to,
the main TPE options that you have selected elsewhere. Thus, if a
"trusted" GID is chosen, this restriction applies to even that GID.
Under this restriction, all non-root users will only be allowed to
execute files in directories they own that are not group or
world-writable, or in directories owned by root and writable only by
root.

This setting can be overridden at runtime via the fs.tpe_restrict_all
sysctl.

config SECURITY_TPE_INVERT
bool "Invert GID option"
depends on SECURITY_TPE
help
If you say Y here, the group you specify in the TPE configuration will
decide what group TPE restrictions will be *disabled* for. This
option is useful if you want TPE restrictions to be applied to most
users on the system.

This setting can be overridden at runtime via the fs.tpe_invert
sysctl.

config SECURITY_TPE_GID
int
default SECURITY_TPE_UNTRUSTED_GID if (SECURITY_TPE && !SECURITY_TPE_INVERT)
default SECURITY_TPE_TRUSTED_GID if (SECURITY_TPE && SECURITY_TPE_INVERT)

config SECURITY_TPE_UNTRUSTED_GID
int "GID for TPE-untrusted users"
depends on SECURITY_TPE && !SECURITY_TPE_INVERT
default 1005
help
Setting this GID determines what group TPE restrictions will be
*enabled* for.

This setting can be overridden at runtime via the fs.tpe_gid
sysctl.

config SECURITY_TPE_TRUSTED_GID
int "GID for TPE-trusted users"
depends on SECURITY_TPE && SECURITY_TPE_INVERT
default 1005
help
Setting this GID determines what group TPE restrictions will be
*disabled* for.

This setting can be overridden at runtime via the fs.tpe_gid
sysctl.

config SECURITY
bool "Enable different security models"
depends on SYSFS
Expand Down