Unverified Commit 326bb02c by Stéphane Graber Committed by GitHub

Merge pull request #3641 from brauner/2021-01-30/fixes

attach: pidfd-based hardening and file-descriptor-only LSM interactions
parents ee4aad1e fbf281d3
...@@ -135,6 +135,7 @@ typedef struct lxc_attach_options_t { ...@@ -135,6 +135,7 @@ typedef struct lxc_attach_options_t {
/* .stdout_fd = */ 1, \ /* .stdout_fd = */ 1, \
/* .stderr_fd = */ 2, \ /* .stderr_fd = */ 2, \
/* .log_fd = */ -EBADF, \ /* .log_fd = */ -EBADF, \
/* .lsm_label = */ NULL, \
} }
/*! /*!
......
...@@ -3454,33 +3454,33 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) ...@@ -3454,33 +3454,33 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
if (cg_init(cgfsng_ops, conf)) if (cg_init(cgfsng_ops, conf))
return NULL; return NULL;
cgfsng_ops->data_init = cgfsng_data_init; cgfsng_ops->data_init = cgfsng_data_init;
cgfsng_ops->payload_destroy = cgfsng_payload_destroy; cgfsng_ops->payload_destroy = cgfsng_payload_destroy;
cgfsng_ops->monitor_destroy = cgfsng_monitor_destroy; cgfsng_ops->monitor_destroy = cgfsng_monitor_destroy;
cgfsng_ops->monitor_create = cgfsng_monitor_create; cgfsng_ops->monitor_create = cgfsng_monitor_create;
cgfsng_ops->monitor_enter = cgfsng_monitor_enter; cgfsng_ops->monitor_enter = cgfsng_monitor_enter;
cgfsng_ops->monitor_delegate_controllers = cgfsng_monitor_delegate_controllers; cgfsng_ops->monitor_delegate_controllers = cgfsng_monitor_delegate_controllers;
cgfsng_ops->payload_delegate_controllers = cgfsng_payload_delegate_controllers; cgfsng_ops->payload_delegate_controllers = cgfsng_payload_delegate_controllers;
cgfsng_ops->payload_create = cgfsng_payload_create; cgfsng_ops->payload_create = cgfsng_payload_create;
cgfsng_ops->payload_enter = cgfsng_payload_enter; cgfsng_ops->payload_enter = cgfsng_payload_enter;
cgfsng_ops->payload_finalize = cgfsng_payload_finalize; cgfsng_ops->payload_finalize = cgfsng_payload_finalize;
cgfsng_ops->escape = cgfsng_escape; cgfsng_ops->escape = cgfsng_escape;
cgfsng_ops->num_hierarchies = cgfsng_num_hierarchies; cgfsng_ops->num_hierarchies = cgfsng_num_hierarchies;
cgfsng_ops->get_hierarchies = cgfsng_get_hierarchies; cgfsng_ops->get_hierarchies = cgfsng_get_hierarchies;
cgfsng_ops->get_cgroup = cgfsng_get_cgroup; cgfsng_ops->get_cgroup = cgfsng_get_cgroup;
cgfsng_ops->get = cgfsng_get; cgfsng_ops->get = cgfsng_get;
cgfsng_ops->set = cgfsng_set; cgfsng_ops->set = cgfsng_set;
cgfsng_ops->freeze = cgfsng_freeze; cgfsng_ops->freeze = cgfsng_freeze;
cgfsng_ops->unfreeze = cgfsng_unfreeze; cgfsng_ops->unfreeze = cgfsng_unfreeze;
cgfsng_ops->setup_limits_legacy = cgfsng_setup_limits_legacy; cgfsng_ops->setup_limits_legacy = cgfsng_setup_limits_legacy;
cgfsng_ops->setup_limits = cgfsng_setup_limits; cgfsng_ops->setup_limits = cgfsng_setup_limits;
cgfsng_ops->driver = "cgfsng"; cgfsng_ops->driver = "cgfsng";
cgfsng_ops->version = "1.0.0"; cgfsng_ops->version = "1.0.0";
cgfsng_ops->attach = cgfsng_attach; cgfsng_ops->attach = cgfsng_attach;
cgfsng_ops->chown = cgfsng_chown; cgfsng_ops->chown = cgfsng_chown;
cgfsng_ops->mount = cgfsng_mount; cgfsng_ops->mount = cgfsng_mount;
cgfsng_ops->devices_activate = cgfsng_devices_activate; cgfsng_ops->devices_activate = cgfsng_devices_activate;
cgfsng_ops->get_limiting_cgroup = cgfsng_get_limiting_cgroup; cgfsng_ops->get_limiting_cgroup = cgfsng_get_limiting_cgroup;
return move_ptr(cgfsng_ops); return move_ptr(cgfsng_ops);
} }
...@@ -441,6 +441,22 @@ again: ...@@ -441,6 +441,22 @@ again:
return buf; return buf;
} }
static char *apparmor_process_label_get_at(struct lsm_ops *ops, int fd_pid)
{
__do_free char *label = NULL;
size_t len;
label = read_file_at(fd_pid, "attr/current");
if (!label)
return log_error_errno(NULL, errno, "Failed to get AppArmor context");
len = strcspn(label, "\n \t");
if (len)
label[len] = '\0';
return move_ptr(label);
}
/* /*
* Probably makes sense to reorganize these to only read * Probably makes sense to reorganize these to only read
* the label once * the label once
...@@ -1180,45 +1196,33 @@ static int apparmor_process_label_set_at(struct lsm_ops *ops, int label_fd, cons ...@@ -1180,45 +1196,33 @@ static int apparmor_process_label_set_at(struct lsm_ops *ops, int label_fd, cons
static int apparmor_process_label_set(struct lsm_ops *ops, const char *inlabel, static int apparmor_process_label_set(struct lsm_ops *ops, const char *inlabel,
struct lxc_conf *conf, bool on_exec) struct lxc_conf *conf, bool on_exec)
{ {
int label_fd, ret; __do_close int label_fd = -EBADF;
pid_t tid; int ret;
const char *label; const char *label;
if (!ops->aa_enabled) if (!ops->aa_enabled)
return log_error(-1, "AppArmor not enabled"); return log_error_errno(-EOPNOTSUPP, EOPNOTSUPP, "AppArmor not enabled");
label = inlabel ? inlabel : conf->lsm_aa_profile_computed; label = inlabel ? inlabel : conf->lsm_aa_profile_computed;
if (!label) { if (!label)
ERROR("LSM wasn't prepared"); return log_error_errno(-EINVAL, EINVAL, "LSM wasn't prepared");
return -1;
}
/* user may request that we just ignore apparmor */ /* user may request that we just ignore apparmor */
if (strcmp(label, AA_UNCHANGED) == 0) { if (strcmp(label, AA_UNCHANGED) == 0)
INFO("AppArmor profile unchanged per user request"); return log_info(0, "AppArmor profile unchanged per user request");
return 0;
}
if (strcmp(label, "unconfined") == 0 && apparmor_am_unconfined(ops)) { if (strcmp(label, "unconfined") == 0 && apparmor_am_unconfined(ops))
INFO("AppArmor profile unchanged"); return log_info(0, "AppArmor profile unchanged");
return 0;
} label_fd = apparmor_process_label_fd_get(ops, lxc_raw_gettid(), on_exec);
tid = lxc_raw_gettid(); if (label_fd < 0)
label_fd = apparmor_process_label_fd_get(ops, tid, on_exec); return log_error_errno(-EINVAL, EINVAL, "Failed to change AppArmor profile to %s", label);
if (label_fd < 0) {
SYSERROR("Failed to change AppArmor profile to %s", label);
return -1;
}
ret = apparmor_process_label_set_at(ops, label_fd, label, on_exec); ret = apparmor_process_label_set_at(ops, label_fd, label, on_exec);
close(label_fd); if (ret < 0)
if (ret < 0) { return log_error_errno(-EINVAL, EINVAL, "Failed to change AppArmor profile to %s", label);
ERROR("Failed to change AppArmor profile to %s", label);
return -1;
}
INFO("Changed AppArmor profile to %s", label); return log_info(0, "Changed AppArmor profile to %s", label);
return 0;
} }
static struct lsm_ops apparmor_ops = { static struct lsm_ops apparmor_ops = {
...@@ -1237,6 +1241,7 @@ static struct lsm_ops apparmor_ops = { ...@@ -1237,6 +1241,7 @@ static struct lsm_ops apparmor_ops = {
.process_label_fd_get = apparmor_process_label_fd_get, .process_label_fd_get = apparmor_process_label_fd_get,
.process_label_get = apparmor_process_label_get, .process_label_get = apparmor_process_label_get,
.process_label_set = apparmor_process_label_set, .process_label_set = apparmor_process_label_set,
.process_label_get_at = apparmor_process_label_get_at,
.process_label_set_at = apparmor_process_label_set_at, .process_label_set_at = apparmor_process_label_set_at,
}; };
......
...@@ -30,6 +30,7 @@ struct lsm_ops { ...@@ -30,6 +30,7 @@ struct lsm_ops {
int (*prepare)(struct lsm_ops *ops, struct lxc_conf *conf, const char *lxcpath); int (*prepare)(struct lsm_ops *ops, struct lxc_conf *conf, const char *lxcpath);
void (*cleanup)(struct lsm_ops *ops, struct lxc_conf *conf, const char *lxcpath); void (*cleanup)(struct lsm_ops *ops, struct lxc_conf *conf, const char *lxcpath);
int (*process_label_fd_get)(struct lsm_ops *ops, pid_t pid, bool on_exec); int (*process_label_fd_get)(struct lsm_ops *ops, pid_t pid, bool on_exec);
char *(*process_label_get_at)(struct lsm_ops *ops, int fd_pid);
int (*process_label_set_at)(struct lsm_ops *ops, int label_fd, const char *label, bool on_exec); int (*process_label_set_at)(struct lsm_ops *ops, int label_fd, const char *label, bool on_exec);
}; };
......
...@@ -13,6 +13,11 @@ static char *nop_process_label_get(struct lsm_ops *ops, pid_t pid) ...@@ -13,6 +13,11 @@ static char *nop_process_label_get(struct lsm_ops *ops, pid_t pid)
return NULL; return NULL;
} }
static char *nop_process_label_get_at(struct lsm_ops *ops, int fd_pid)
{
return NULL;
}
static int nop_process_label_set(struct lsm_ops *ops, const char *label, struct lxc_conf *conf, static int nop_process_label_set(struct lsm_ops *ops, const char *label, struct lxc_conf *conf,
bool on_exec) bool on_exec)
{ {
...@@ -63,8 +68,9 @@ static struct lsm_ops nop_ops = { ...@@ -63,8 +68,9 @@ static struct lsm_ops nop_ops = {
.prepare = nop_prepare, .prepare = nop_prepare,
.process_label_fd_get = nop_process_label_fd_get, .process_label_fd_get = nop_process_label_fd_get,
.process_label_get = nop_process_label_get, .process_label_get = nop_process_label_get,
.process_label_set = nop_process_label_set, .process_label_set = nop_process_label_set,
.process_label_set_at = nop_process_label_set_at, .process_label_get_at = nop_process_label_get_at,
.process_label_set_at = nop_process_label_set_at,
}; };
struct lsm_ops *lsm_nop_ops_init(void) struct lsm_ops *lsm_nop_ops_init(void)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
#include "lsm.h" #include "lsm.h"
#include "memory_utils.h"
#define DEFAULT_LABEL "unconfined_t" #define DEFAULT_LABEL "unconfined_t"
...@@ -41,6 +42,32 @@ static char *selinux_process_label_get(struct lsm_ops *ops, pid_t pid) ...@@ -41,6 +42,32 @@ static char *selinux_process_label_get(struct lsm_ops *ops, pid_t pid)
} }
/* /*
* selinux_process_label_get_at: Get SELinux context of a process
*
* @fd_pid : file descriptor to /proc/<pid> of the process
*
* Returns the context of the given pid. The caller must free()
* the returned string.
*
* Note that this relies on /proc being available.
*/
static char *selinux_process_label_get_at(struct lsm_ops *ops, int fd_pid)
{
__do_free char *label = NULL;
size_t len;
label = read_file_at(fd_pid, "attr/current");
if (!label)
return log_error_errno(NULL, errno, "Failed to get SELinux context");
len = strcspn(label, "\n \t");
if (len)
label[len] = '\0';
return move_ptr(label);
}
/*
* selinux_process_label_set: Set SELinux context of a process * selinux_process_label_set: Set SELinux context of a process
* *
* @label : label string * @label : label string
...@@ -154,6 +181,7 @@ static struct lsm_ops selinux_ops = { ...@@ -154,6 +181,7 @@ static struct lsm_ops selinux_ops = {
.process_label_fd_get = selinux_process_label_fd_get, .process_label_fd_get = selinux_process_label_fd_get,
.process_label_get = selinux_process_label_get, .process_label_get = selinux_process_label_get,
.process_label_set = selinux_process_label_set, .process_label_set = selinux_process_label_set,
.process_label_get_at = selinux_process_label_get_at,
.process_label_set_at = selinux_process_label_set_at, .process_label_set_at = selinux_process_label_set_at,
}; };
......
Markdown is supported
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