Commit dda9b53f authored by Simon Ruderich's avatar Simon Ruderich
Browse files

slsm: add protect flag disallowing LD_PRELOAD and ptrace

Tests still missing.
parent 30ba7b2b
......@@ -33,6 +33,8 @@ bits (`x` is not necessary to `cd`) and a set of SLSM-specific flags:
* If a program `A` execs program `B` and the `inherit` flag applies for `A` at
`B`, the process inherits `A`s permissions. `B` is then confined to those
permissions in the above sense.
* The `protect` flag prevents other programs from ptracing or injecting
functions using `LD_PRELOAD` into the protected process.
# Interface #
......@@ -45,7 +47,7 @@ Currently available flags are
* `m` bit mask indicating the access mode (read is 4, write is 2, execute is 1)
* `a` the absolute path to the program this rule should apply to (optional)
* `f` SLSM-specific flags described above, `inherit` is 1, `confine` is 2,
`exact` is 4
`exact` is 4, `protect` is 8 (optional)
# Examples #
......@@ -53,7 +55,9 @@ Currently available flags are
For convenience, we store all our private keys in a separate directory
`~/.ssh/private` and want to prevent all programs except `/usr/bin/ssh-add`
from reading the files contained therein, but allow listing the keys:
from reading the files contained therein, but allow listing the keys. Also
nobody must be able to debug/inject code into `ssh-add` or the protection can
easily be circumvented.
1. shut everyone out:
p=/home/user/.ssh/private\0m=0\0\0
......@@ -61,11 +65,13 @@ from reading the files contained therein, but allow listing the keys:
p=/home/user/.ssh/private\0m=4\0f=4\0\0
3. allow `ssh-add` to read file contents:
p=/home/user/.ssh/private\0m=4\0a=/usr/bin/ssh-add\0\0
4. prevent anybody from ptracing/`LD_PRELOAD`ing ssh-add
p=/usr/bin/ssh-add\0m=7\0f=8\0\0
To apply this setup, run something like the following (replace user with your
user name):
printf 'p=/home/user/.ssh/private\0m=0\0\0p=/home/user/.ssh/private\0m=4\0f=4\0\0p=/home/user/.ssh/private\0m=4\0a=/usr/bin/ssh-add\0\0' >/sys/kernel/security/slsm/profiles
printf 'p=/home/user/.ssh/private\0m=0\0\0p=/home/user/.ssh/private\0m=4\0f=4\0\0p=/home/user/.ssh/private\0m=4\0a=/usr/bin/ssh-add\0\0p=/usr/bin/ssh-add\0m=7\0f=8\0\0' >/sys/kernel/security/slsm/profiles
## Restricting a media player ##
......
......@@ -25,6 +25,15 @@ struct passt_task {
};
static struct passt_task *task_security(const struct task_struct *t) {
struct passt_task *s;
rcu_read_lock();
s = __task_cred(t)->security;
rcu_read_unlock();
return s;
}
/**
* passt_dup_task - duplicates all resources related to @old_pt
*
......@@ -96,6 +105,7 @@ static int passt_bprm_set_creds(struct linux_binprm *bprm) {
char *buffer = NULL;
const char *name = NULL;
int error = 0;
const char *reason = "";
struct slsm_perms perms;
if (bprm->cred_prepared)
......@@ -111,6 +121,34 @@ static int passt_bprm_set_creds(struct linux_binprm *bprm) {
perms = slsm_query_perms(name, pt->label);
if (perms.mode & SLSM_MODE_X) {
int unsafe = bprm->unsafe;
int ptrace_mask = LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP;
if ((unsafe & ptrace_mask) && (perms.flags & SLSM_FLAG_PROTECT)) {
error = -EPERM;
reason = " (ptrace not allowed)";
goto audit;
}
unsafe &= ~ptrace_mask;
/* TODO: LSM_UNSAFE_SHARE is set for init on boot, ignore then
* but respect (-> -EPERM) later? */
unsafe &= ~LSM_UNSAFE_SHARE;
/* Ensure processes which use prctl(PR_SET_NO_NEW_PRIVS) will
* never get more privileges. */
if (unsafe & LSM_UNSAFE_NO_NEW_PRIVS) {
pt->confined = 1;
}
unsafe &= ~LSM_UNSAFE_NO_NEW_PRIVS;
/* Any other unchecked unsafe bits left? */
if (unsafe) {
error = -EPERM;
reason = " (unsafe)";
goto audit;
}
if (pt->confined || (perms.flags & SLSM_FLAG_INHERIT)) {
pt->confined = 1;
printk(KERN_INFO "slsm: %s inherited %s\n", name, pt->label);
......@@ -136,7 +174,7 @@ static int passt_bprm_set_creds(struct linux_binprm *bprm) {
audit:
/* TODO: log stuff properly */
printk(KERN_INFO "DENIED: %s exec %s\n", pt->label, name);
printk(KERN_INFO "DENIED: %s exec %s%s\n", pt->label, name, reason);
cleanup:
kfree(buffer);
......@@ -153,14 +191,69 @@ static void passt_bprm_committing_creds(struct linux_binprm *bprm) {
}
/**
* passt_bprm_secureexec - determine if secureexec is needed
* passt_bprm_secureexec - determine if secureexec is needed which disables
* e.g. LD_PRELOAD
* @bprm: binprm for exec (NOT NULL)
*
* Returns: %1 if secureexec is needed else %0
*/
static int passt_bprm_secureexec(struct linux_binprm *bprm) {
// TODO: what's secureexec?
struct passt_task *pt = current_security();
char *buffer = NULL;
const char *name = NULL;
struct slsm_perms perms;
int ret = 0;
/* buffer freed below, name is pointer into buffer */
name = passt_get_path(&bprm->file->f_path, &buffer);
if (IS_ERR(name)) {
ret = 1; /* set secureexec to prevent possible attacks */
name = bprm->filename;
goto cleanup;
}
perms = slsm_query_perms(name, pt->label);
if (perms.flags & SLSM_FLAG_PROTECT) {
ret = 1; /* set secureexec */
}
cleanup:
kfree(buffer);
if (ret) {
printk(KERN_INFO "slsm: secureexec for %s\n", name);
}
return ret;
}
static int passt_ptrace_access_check(struct task_struct *child,
unsigned int mode) {
struct passt_task *pt = current_security();
struct passt_task *pt_child = task_security(child);
struct slsm_perms perms;
/* NOTE: We're using the (inherited) program label here, not the
* actual path to the binary. */
perms = slsm_query_perms(pt_child->label, pt->label);
if (perms.flags & SLSM_FLAG_PROTECT) {
printk(KERN_INFO "slsm: preventing ptrace of %s (label)\n",
pt_child->label);
return -EPERM;
}
return 0;
}
static int passt_ptrace_traceme(struct task_struct *parent) {
struct passt_task *pt = current_security();
struct passt_task *pt_parent = task_security(parent);
struct slsm_perms perms;
/* NOTE: We're using the (inherited) program label here, not the
* actual path to the binary. */
perms = slsm_query_perms(pt->label, pt_parent->label);
if (perms.flags & SLSM_FLAG_PROTECT) {
printk(KERN_INFO "slsm: preventing ptrace of %s (label)\n",
pt->label);
return -EPERM;
}
return 0;
}
......@@ -306,8 +399,8 @@ static int passt_unix_may_send(struct socket *sock, struct socket *other) {
static struct security_hook_list passt_hooks[] = {
/* LSM_HOOK_INIT(ptrace_access_check, passt_ptrace_access_check), */
/* LSM_HOOK_INIT(ptrace_traceme, passt_ptrace_traceme), */
LSM_HOOK_INIT(ptrace_access_check, passt_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, passt_ptrace_traceme),
/* LSM_HOOK_INIT(capget, passt_capget), */
/* LSM_HOOK_INIT(capable, passt_capable), */
......
......@@ -157,7 +157,7 @@ unsigned slsm_perms_mode_grant(struct slsm_perms perms, struct slsm_perms perms_
unsigned slsm_perms_would_elevate(struct slsm_perms perms, struct slsm_perms perms_would_get) {
unsigned flags, flags_would_get;
unsigned restrictions = SLSM_FLAG_INHERIT | SLSM_FLAG_CONFINE;
unsigned restrictions = SLSM_FLAG_INHERIT | SLSM_FLAG_CONFINE | SLSM_FLAG_PROTECT;
if (!slsm_perms_mode_grant(perms, perms_would_get))
return 1;
......
......@@ -43,6 +43,7 @@ struct tree_node {
#define SLSM_FLAG_INHERIT (1 << 0)
#define SLSM_FLAG_CONFINE (1 << 1)
#define SLSM_FLAG_EXACT (1 << 2)
#define SLSM_FLAG_PROTECT (1 << 3)
/* NOTE: when adding new flags adapt slsm_perms_would_elevate() */
struct slsm_perms {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment