From 6af96c8404181e63d2424d1695fd7f8a42a291bf Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Fri, 4 Dec 2015 18:55:00 +0300 Subject: [PATCH] lsm: add a --lsm-profile flag In LXD, we use the container name in the LSM profile. If the container name is changed on migrate (on the host side), we want to use a different LSM profile name (a. la. --cgroup-root). This flag adds that support. v2: remove unused field, add comment about double detection in kerndat_lsm() Signed-off-by: Tycho Andersen Signed-off-by: Pavel Emelyanov --- cr-restore.c | 36 +++++++++++++++++------------ crtools.c | 6 +++++ include/cr_options.h | 2 ++ include/lsm.h | 3 ++- lsm.c | 54 ++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 83 insertions(+), 18 deletions(-) diff --git a/cr-restore.c b/cr-restore.c index 1c0c64135..3c636b9ab 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -2827,29 +2827,35 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core) if (!creds) goto err; - if (creds->lsm_profile) { - char *rendered; + if (creds->lsm_profile || opts.lsm_supplied) { + char *rendered, *profile; int ret; - if (validate_lsm(creds) < 0) + profile = creds->lsm_profile; + if (opts.lsm_supplied) + profile = opts.lsm_profile; + + if (validate_lsm(profile) < 0) return -1; - ret = render_lsm_profile(creds->lsm_profile, &rendered); - if (ret < 0) { - goto err_nv; - } + if (profile) { + ret = render_lsm_profile(profile, &rendered); + if (ret < 0) { + goto err_nv; + } - lsm_pos = rst_mem_cpos(RM_PRIVATE); - lsm_profile_len = strlen(rendered); - lsm = rst_mem_alloc(lsm_profile_len + 1, RM_PRIVATE); - if (!lsm) { + lsm_pos = rst_mem_cpos(RM_PRIVATE); + lsm_profile_len = strlen(rendered); + lsm = rst_mem_alloc(lsm_profile_len + 1, RM_PRIVATE); + if (!lsm) { + xfree(rendered); + goto err_nv; + } + + strncpy(lsm, rendered, lsm_profile_len); xfree(rendered); - goto err_nv; } - strncpy(lsm, rendered, lsm_profile_len); - xfree(rendered); - } if (seccomp_filters_get_rst_pos(core, &n_seccomp_filters, &seccomp_filter_pos) < 0) diff --git a/crtools.c b/crtools.c index d3812a18f..68756a090 100644 --- a/crtools.c +++ b/crtools.c @@ -41,6 +41,7 @@ #include "security.h" #include "irmap.h" #include "fault-injection.h" +#include "lsm.h" #include "setproctitle.h" @@ -253,6 +254,7 @@ int main(int argc, char *argv[], char *envp[]) { "freeze-cgroup", required_argument, 0, 1068 }, { "ghost-limit", required_argument, 0, 1069 }, { "irmap-scan-path", required_argument, 0, 1070 }, + { "lsm-profile", required_argument, 0, 1071 }, { }, }; @@ -498,6 +500,10 @@ int main(int argc, char *argv[], char *envp[]) if (irmap_scan_path_add(optarg)) return -1; break; + case 1071: + if (parse_lsm_arg(optarg) < 0) + return -1; + break; case 'M': { char *aux; diff --git a/include/cr_options.h b/include/cr_options.h index eac7283a4..d0c74fe26 100644 --- a/include/cr_options.h +++ b/include/cr_options.h @@ -95,6 +95,8 @@ struct cr_options { bool overlayfs; size_t ghost_limit; struct list_head irmap_scan_paths; + bool lsm_supplied; + char *lsm_profile; }; extern struct cr_options opts; diff --git a/include/lsm.h b/include/lsm.h index 1409acd1f..bd13ef70b 100644 --- a/include/lsm.h +++ b/include/lsm.h @@ -23,7 +23,7 @@ extern int collect_lsm_profile(pid_t, CredsEntry *); * Validate that the LSM profiles can be correctly applied (must happen after * pstree is set up). */ -int validate_lsm(CredsEntry *ce); +int validate_lsm(char *profile); /* * Render the profile name in the way that the LSM wants it written to @@ -31,4 +31,5 @@ int validate_lsm(CredsEntry *ce); */ int render_lsm_profile(char *profile, char **val); +extern int parse_lsm_arg(char *arg); #endif /* __CR_LSM_H__ */ diff --git a/lsm.c b/lsm.c index c960611dd..de40c7be7 100644 --- a/lsm.c +++ b/lsm.c @@ -7,6 +7,7 @@ #include "config.h" #include "pstree.h" #include "util.h" +#include "cr_options.h" #include "protobuf.h" #include "protobuf/inventory.pb-c.h" @@ -106,6 +107,14 @@ static int selinux_get_label(pid_t pid, char **output) void kerndat_lsm(void) { + /* On restore, if someone passes --lsm-profile, we might end up doing + * detection twice, once during flag parsing and once for + * kerndat_init_rst(). Let's detect when we've already done detection + * and not do it again. + */ + if (name) + return; + if (access("/sys/kernel/security/apparmor", F_OK) == 0) { get_label = apparmor_get_label; lsmtype = LSMTYPE__APPARMOR; @@ -156,7 +165,7 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce) // in inventory.c extern Lsmtype image_lsm; -int validate_lsm(CredsEntry *ce) +int validate_lsm(char *lsm_profile) { if (image_lsm == LSMTYPE__NO_LSM || image_lsm == lsmtype) return 0; @@ -166,7 +175,7 @@ int validate_lsm(CredsEntry *ce) * specified an LSM profile. If not, we won't restore anything anyway, * so it's fine. */ - if (ce->lsm_profile) { + if (lsm_profile) { pr_err("mismatched lsm types and lsm profile specified\n"); return -1; } @@ -197,3 +206,44 @@ int render_lsm_profile(char *profile, char **val) return 0; } + +int parse_lsm_arg(char *arg) +{ + char *aux; + + kerndat_lsm(); + + aux = strchr(arg, ':'); + if (aux == NULL) { + pr_err("invalid argument %s for --lsm-profile", arg); + return -1; + } + + *aux = '\0'; + aux++; + + if (strcmp(arg, "apparmor") == 0) { + if (lsmtype != LSMTYPE__APPARMOR) { + pr_err("apparmor LSM specified but apparmor not supported by kernel\n"); + return -1; + } + + opts.lsm_profile = aux; + } else if (strcmp(arg, "selinux") == 0) { + if (lsmtype != LSMTYPE__SELINUX) { + pr_err("selinux LSM specified but selinux not supported by kernel\n"); + return -1; + } + + opts.lsm_profile = aux; + } else if (strcmp(arg, "none") == 0) { + opts.lsm_profile = NULL; + } else { + pr_err("unknown lsm %s\n", arg); + return -1; + } + + opts.lsm_supplied = true; + + return 0; +}