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
...@@ -57,6 +57,7 @@ lxc_log_define(attach, lxc); ...@@ -57,6 +57,7 @@ lxc_log_define(attach, lxc);
static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT; static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT;
struct attach_context { struct attach_context {
unsigned int attach_flags;
int init_pid; int init_pid;
int dfd_init_pid; int dfd_init_pid;
int dfd_self_pid; int dfd_self_pid;
...@@ -69,6 +70,49 @@ struct attach_context { ...@@ -69,6 +70,49 @@ struct attach_context {
struct lsm_ops *lsm_ops; struct lsm_ops *lsm_ops;
}; };
static pid_t pidfd_get_pid(int pidfd)
{
__do_free char *line = NULL;
__do_fclose FILE *f = NULL;
size_t len = 0;
char path[STRLITERALLEN("/proc/self/fdinfo/") +
INTTYPE_TO_STRLEN(int) + 1 ] = "/proc/self/fdinfo/";
int ret;
if (pidfd < 0)
return -EBADF;
ret = snprintf(path + STRLITERALLEN("/proc/self/fdinfo/"),
INTTYPE_TO_STRLEN(int), "%d", pidfd);
if (ret < 0 || ret > (size_t)INTTYPE_TO_STRLEN(int))
return ret_errno(EIO);
f = fopen_cloexec(path, "re");
if (!f)
return -errno;
while (getline(&line, &len, f) != -1) {
const char *prefix = "Pid:\t";
const size_t prefix_len = STRLITERALLEN("Pid:\t");
int pid = -ESRCH;
char *slider = line;
if (strncmp(slider, prefix, prefix_len))
continue;
slider += prefix_len;
slider = lxc_trim_whitespace_in_place(slider);
ret = lxc_safe_int(slider, &pid);
if (ret)
return -ret;
return pid;
}
return ret_errno(ENOENT);
}
static inline bool sync_wake_pid(int fd, pid_t pid) static inline bool sync_wake_pid(int fd, pid_t pid)
{ {
return lxc_write_nointr(fd, &pid, sizeof(pid_t)) == sizeof(pid_t); return lxc_write_nointr(fd, &pid, sizeof(pid_t)) == sizeof(pid_t);
...@@ -89,6 +133,12 @@ static inline bool sync_wait_fd(int fd, int *fd_recv) ...@@ -89,6 +133,12 @@ static inline bool sync_wait_fd(int fd, int *fd_recv)
return lxc_abstract_unix_recv_fds(fd, fd_recv, 1, NULL, 0) > 0; return lxc_abstract_unix_recv_fds(fd, fd_recv, 1, NULL, 0) > 0;
} }
static bool attach_lsm(lxc_attach_options_t *options)
{
return (options->namespaces & CLONE_NEWNS) &&
(options->attach_flags & (LXC_ATTACH_LSM | LXC_ATTACH_LSM_LABEL));
}
static struct attach_context *alloc_attach_context(void) static struct attach_context *alloc_attach_context(void)
{ {
struct attach_context *ctx; struct attach_context *ctx;
...@@ -127,10 +177,11 @@ static int get_personality(const char *name, const char *lxcpath, ...@@ -127,10 +177,11 @@ static int get_personality(const char *name, const char *lxcpath,
} }
static int get_attach_context(struct attach_context *ctx, static int get_attach_context(struct attach_context *ctx,
struct lxc_container *container) struct lxc_container *container,
lxc_attach_options_t *options)
{ {
__do_close int dfd_self_pid = -EBADF, dfd_init_pid = -EBADF, fd_status = -EBADF; __do_close int dfd_self_pid = -EBADF, dfd_init_pid = -EBADF, fd_status = -EBADF, init_pidfd = -EBADF;
__do_free char *line = NULL; __do_free char *line = NULL, *lsm_label = NULL;
__do_fclose FILE *f_status = NULL; __do_fclose FILE *f_status = NULL;
int ret; int ret;
bool found; bool found;
...@@ -138,8 +189,14 @@ static int get_attach_context(struct attach_context *ctx, ...@@ -138,8 +189,14 @@ static int get_attach_context(struct attach_context *ctx,
size_t line_bufsz = 0; size_t line_bufsz = 0;
ctx->container = container; ctx->container = container;
ctx->attach_flags = options->attach_flags;
init_pidfd = lxc_cmd_get_init_pidfd(container->name, container->config_path);
if (init_pidfd >= 0)
ctx->init_pid = pidfd_get_pid(init_pidfd);
else
ctx->init_pid = lxc_cmd_get_init_pid(container->name, container->config_path);
ctx->init_pid = lxc_cmd_get_init_pid(container->name, container->config_path);
if (ctx->init_pid < 0) if (ctx->init_pid < 0)
return log_error(-1, "Failed to get init pid"); return log_error(-1, "Failed to get init pid");
...@@ -163,6 +220,14 @@ static int get_attach_context(struct attach_context *ctx, ...@@ -163,6 +220,14 @@ static int get_attach_context(struct attach_context *ctx,
if (fd_status < 0) if (fd_status < 0)
return -errno; return -errno;
if (init_pidfd >= 0) {
ret = lxc_raw_pidfd_send_signal(init_pidfd, 0, NULL, 0);
if (ret)
return log_error_errno(-errno, errno, "Container process exited or PID has been recycled");
else
TRACE("Container process still running and PID was not recycled");
}
f_status = fdopen(fd_status, "re"); f_status = fdopen(fd_status, "re");
if (!f_status) if (!f_status)
return log_error_errno(-errno, errno, "Failed to open file descriptor %d", fd_status); return log_error_errno(-errno, errno, "Failed to open file descriptor %d", fd_status);
...@@ -183,8 +248,16 @@ static int get_attach_context(struct attach_context *ctx, ...@@ -183,8 +248,16 @@ static int get_attach_context(struct attach_context *ctx,
ctx->lsm_ops = lsm_init_static(); ctx->lsm_ops = lsm_init_static();
/* Move to file descriptor-only lsm label retrieval. */ if (attach_lsm(options)) {
ctx->lsm_label = ctx->lsm_ops->process_label_get(ctx->lsm_ops, ctx->init_pid); if (ctx->attach_flags & LXC_ATTACH_LSM_LABEL)
lsm_label = options->lsm_label;
else
lsm_label = ctx->lsm_ops->process_label_get_at(ctx->lsm_ops, dfd_init_pid);
if (!lsm_label)
WARN("No security context received");
else
INFO("Retrieved security context %s", lsm_label);
}
ctx->ns_inherited = 0; ctx->ns_inherited = 0;
ret = get_personality(container->name, container->config_path, &ctx->personality); ret = get_personality(container->name, container->config_path, &ctx->personality);
...@@ -199,6 +272,7 @@ static int get_attach_context(struct attach_context *ctx, ...@@ -199,6 +272,7 @@ static int get_attach_context(struct attach_context *ctx,
ctx->dfd_init_pid = move_fd(dfd_init_pid); ctx->dfd_init_pid = move_fd(dfd_init_pid);
ctx->dfd_self_pid = move_fd(dfd_self_pid); ctx->dfd_self_pid = move_fd(dfd_self_pid);
ctx->lsm_label = move_ptr(lsm_label);
return 0; return 0;
} }
...@@ -284,7 +358,8 @@ static inline void close_nsfds(struct attach_context *ctx) ...@@ -284,7 +358,8 @@ static inline void close_nsfds(struct attach_context *ctx)
static void put_attach_context(struct attach_context *ctx) static void put_attach_context(struct attach_context *ctx)
{ {
if (ctx) { if (ctx) {
free_disarm(ctx->lsm_label); if (!(ctx->attach_flags & LXC_ATTACH_LSM_LABEL))
free_disarm(ctx->lsm_label);
close_prot_errno_disarm(ctx->dfd_init_pid); close_prot_errno_disarm(ctx->dfd_init_pid);
if (ctx->container) { if (ctx->container) {
...@@ -712,13 +787,12 @@ static bool fetch_seccomp(struct lxc_container *c, lxc_attach_options_t *options ...@@ -712,13 +787,12 @@ static bool fetch_seccomp(struct lxc_container *c, lxc_attach_options_t *options
int ret; int ret;
bool bret; bool bret;
if (!(options->namespaces & CLONE_NEWNS) || if (!attach_lsm(options)) {
!(options->attach_flags & LXC_ATTACH_LSM)) {
free_disarm(c->lxc_conf->seccomp.seccomp); free_disarm(c->lxc_conf->seccomp.seccomp);
return true; return true;
} }
/* Remove current setting. */ /* Remove current setting. */
if (!c->set_config_item(c, "lxc.seccomp.profile", "") && if (!c->set_config_item(c, "lxc.seccomp.profile", "") &&
!c->set_config_item(c, "lxc.seccomp", "")) !c->set_config_item(c, "lxc.seccomp", ""))
return false; return false;
...@@ -774,9 +848,9 @@ struct attach_payload { ...@@ -774,9 +848,9 @@ struct attach_payload {
static void put_attach_payload(struct attach_payload *p) static void put_attach_payload(struct attach_payload *p)
{ {
close_prot_errno_disarm(p->ipc_socket); if (p) {
close_prot_errno_disarm(p->terminal_pts_fd); close_prot_errno_disarm(p->ipc_socket);
if (p->ctx) { close_prot_errno_disarm(p->terminal_pts_fd);
put_attach_context(p->ctx); put_attach_context(p->ctx);
p->ctx = NULL; p->ctx = NULL;
} }
...@@ -784,6 +858,8 @@ static void put_attach_payload(struct attach_payload *p) ...@@ -784,6 +858,8 @@ static void put_attach_payload(struct attach_payload *p)
__noreturn static void do_attach(struct attach_payload *ap) __noreturn static void do_attach(struct attach_payload *ap)
{ {
lxc_attach_exec_t attach_function = move_ptr(ap->exec_function);
void *attach_function_args = move_ptr(ap->exec_payload);
int lsm_fd, ret; int lsm_fd, ret;
uid_t new_uid; uid_t new_uid;
gid_t new_gid; gid_t new_gid;
...@@ -792,10 +868,6 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -792,10 +868,6 @@ __noreturn static void do_attach(struct attach_payload *ap)
lxc_attach_options_t* options = ap->options; lxc_attach_options_t* options = ap->options;
struct attach_context *ctx = ap->ctx; struct attach_context *ctx = ap->ctx;
struct lxc_conf *conf = ctx->container->lxc_conf; struct lxc_conf *conf = ctx->container->lxc_conf;
bool needs_lsm = (options->namespaces & CLONE_NEWNS) &&
(options->attach_flags & LXC_ATTACH_LSM) &&
ctx->lsm_label;
char *lsm_label = NULL;
/* A description of the purpose of this functionality is provided in the /* A description of the purpose of this functionality is provided in the
* lxc-attach(1) manual page. We have to remount here and not in the * lxc-attach(1) manual page. We have to remount here and not in the
...@@ -851,7 +923,8 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -851,7 +923,8 @@ __noreturn static void do_attach(struct attach_payload *ap)
TRACE("Set up environment"); TRACE("Set up environment");
/* This remark only affects fully unprivileged containers: /*
* This remark only affects fully unprivileged containers:
* Receive fd for LSM security module before we set{g,u}id(). The reason * Receive fd for LSM security module before we set{g,u}id(). The reason
* is that on set{g,u}id() the kernel will a) make us undumpable and b) * is that on set{g,u}id() the kernel will a) make us undumpable and b)
* we will change our effective uid. This means our effective uid will * we will change our effective uid. This means our effective uid will
...@@ -862,7 +935,7 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -862,7 +935,7 @@ __noreturn static void do_attach(struct attach_payload *ap)
* mounted with hidepid={1,2}. So let's get the lsm label fd before the * mounted with hidepid={1,2}. So let's get the lsm label fd before the
* set{g,u}id(). * set{g,u}id().
*/ */
if (needs_lsm) { if (attach_lsm(options) && ctx->lsm_label) {
if (!sync_wait_fd(ap->ipc_socket, ATTACH_SYNC_LSM(&lsm_fd))) { if (!sync_wait_fd(ap->ipc_socket, ATTACH_SYNC_LSM(&lsm_fd))) {
SYSERROR("Failed to receive lsm label fd"); SYSERROR("Failed to receive lsm label fd");
goto on_error; goto on_error;
...@@ -911,17 +984,12 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -911,17 +984,12 @@ __noreturn static void do_attach(struct attach_payload *ap)
else else
new_gid = ns_root_gid; new_gid = ns_root_gid;
if (needs_lsm) { if (attach_lsm(options) && ctx->lsm_label) {
bool on_exec; bool on_exec;
/* Change into our new LSM profile. */ /* Change into our new LSM profile. */
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false; on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false;
if (options->attach_flags & LXC_ATTACH_LSM_LABEL) ret = ctx->lsm_ops->process_label_set_at(ctx->lsm_ops, lsm_fd, ctx->lsm_label, on_exec);
lsm_label = options->lsm_label;
if (!lsm_label)
lsm_label = ctx->lsm_label;
ret = ctx->lsm_ops->process_label_set_at(ctx->lsm_ops, lsm_fd,
lsm_label, on_exec);
close_prot_errno_disarm(lsm_fd); close_prot_errno_disarm(lsm_fd);
if (ret < 0) if (ret < 0)
goto on_error; goto on_error;
...@@ -950,10 +1018,6 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -950,10 +1018,6 @@ __noreturn static void do_attach(struct attach_payload *ap)
goto on_error; goto on_error;
} }
close_prot_errno_disarm(ap->ipc_socket);
put_attach_context(ctx);
ap->ctx = NULL;
/* The following is done after the communication socket is shut down. /* The following is done after the communication socket is shut down.
* That way, all errors that might (though unlikely) occur up until this * That way, all errors that might (though unlikely) occur up until this
* point will have their messages printed to the original stderr (if * point will have their messages printed to the original stderr (if
...@@ -1007,6 +1071,8 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -1007,6 +1071,8 @@ __noreturn static void do_attach(struct attach_payload *ap)
TRACE("Prepared terminal file descriptor %d", ap->terminal_pts_fd); TRACE("Prepared terminal file descriptor %d", ap->terminal_pts_fd);
} }
put_attach_payload(ap);
/* Avoid unnecessary syscalls. */ /* Avoid unnecessary syscalls. */
if (new_uid == ns_root_uid) if (new_uid == ns_root_uid)
new_uid = LXC_INVALID_UID; new_uid = LXC_INVALID_UID;
...@@ -1023,10 +1089,9 @@ __noreturn static void do_attach(struct attach_payload *ap) ...@@ -1023,10 +1089,9 @@ __noreturn static void do_attach(struct attach_payload *ap)
goto on_error; goto on_error;
/* We're done, so we can now do whatever the user intended us to do. */ /* We're done, so we can now do whatever the user intended us to do. */
_exit(ap->exec_function(ap->exec_payload)); _exit(attach_function(attach_function_args));
on_error: on_error:
put_attach_payload(ap);
ERROR("Failed to attach to container"); ERROR("Failed to attach to container");
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
...@@ -1106,8 +1171,10 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1106,8 +1171,10 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
name = container->name; name = container->name;
lxcpath = container->config_path; lxcpath = container->config_path;
if (!options) if (!options) {
options = &attach_static_default_options; options = &attach_static_default_options;
options->lsm_label = NULL;
}
ctx = alloc_attach_context(); ctx = alloc_attach_context();
if (!ctx) { if (!ctx) {
...@@ -1115,7 +1182,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1115,7 +1182,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate attach context"); return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate attach context");
} }
ret = get_attach_context(ctx, container); ret = get_attach_context(ctx, container, options);
if (ret) { if (ret) {
put_attach_context(ctx); put_attach_context(ctx);
return log_error(-1, "Failed to get attach context"); return log_error(-1, "Failed to get attach context");
...@@ -1419,14 +1486,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1419,14 +1486,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
to_cleanup_pid = attached_pid; to_cleanup_pid = attached_pid;
/* Open LSM fd and send it to child. */ /* Open LSM fd and send it to child. */
if ((options->namespaces & CLONE_NEWNS) && if (attach_lsm(options) && ctx->lsm_label) {
(options->attach_flags & LXC_ATTACH_LSM) && ctx->lsm_label) {
__do_close int labelfd = -EBADF; __do_close int labelfd = -EBADF;
bool on_exec; bool on_exec;
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false; on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false;
labelfd = ctx->lsm_ops->process_label_fd_get(ctx->lsm_ops, labelfd = ctx->lsm_ops->process_label_fd_get(ctx->lsm_ops, attached_pid, on_exec);
attached_pid, on_exec);
if (labelfd < 0) if (labelfd < 0)
goto close_mainloop; goto close_mainloop;
......
...@@ -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