* [PATCH] add lsm name and lsm_info (policy header) to container info
@ 2009-10-15 20:37 Serge E. Hallyn
[not found] ` <20091015203721.GA5030-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 2+ messages in thread
From: Serge E. Hallyn @ 2009-10-15 20:37 UTC (permalink / raw)
To: Oren Laadan; +Cc: Linux Containers
The LSM name is 'selinux', 'smack', 'tomoyo', or 'dummy'. We
add that to the container configuration section. We also add
a LSM policy configuration section. That is placed after the LSM
name. It is written by the LSM in security_checkpoint_header(),
called during checkpoint container(), and read by the LSM during
security_may_restart(), which is called from restore_lsm() in
restore_container().
Signed-off-by: Serge E. Hallyn <serue-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
---
checkpoint/checkpoint.c | 13 ++++++++-
checkpoint/restart.c | 41 ++++++++++++++++++++++++++
checkpoint/sys.c | 21 +++++++++++++
include/linux/checkpoint.h | 7 ++++-
include/linux/checkpoint_hdr.h | 16 ++++++++++
include/linux/checkpoint_types.h | 2 +
include/linux/security.h | 58 ++++++++++++++++++++++++++++++++++++++
security/capability.c | 24 +++++++++++++++
security/security.c | 26 +++++++++++++++++
9 files changed, 206 insertions(+), 2 deletions(-)
diff --git a/checkpoint/checkpoint.c b/checkpoint/checkpoint.c
index 6eb8f3b..b8c323c 100644
--- a/checkpoint/checkpoint.c
+++ b/checkpoint/checkpoint.c
@@ -366,7 +366,18 @@ static int checkpoint_container(struct ckpt_ctx *ctx)
ret = ckpt_write_obj(ctx, &h->h);
ckpt_hdr_put(ctx, h);
- return ret;
+ if (ret < 0)
+ return ret;
+
+ memset(ctx->lsm_name, 0, CHECKPOINT_LSM_NAME_MAX + 1);
+ strlcpy(ctx->lsm_name, security_get_lsm_name(),
+ CHECKPOINT_LSM_NAME_MAX + 1);
+ ret = ckpt_write_buffer(ctx, ctx->lsm_name,
+ CHECKPOINT_LSM_NAME_MAX + 1);
+ if (ret < 0)
+ return ret;
+
+ return security_checkpoint_header(ctx);
}
/* write the checkpoint trailer */
diff --git a/checkpoint/restart.c b/checkpoint/restart.c
index 32a9fc5..0cd721c 100644
--- a/checkpoint/restart.c
+++ b/checkpoint/restart.c
@@ -624,6 +624,42 @@ static int restore_read_header(struct ckpt_ctx *ctx)
return ret;
}
+/* read the LSM configuration section */
+static int restore_lsm(struct ckpt_ctx *ctx)
+{
+ int ret;
+ char *cur_lsm = security_get_lsm_name();
+
+ ret = _ckpt_read_buffer(ctx, ctx->lsm_name,
+ CHECKPOINT_LSM_NAME_MAX + 1);
+ if (ret < 0) {
+ ckpt_debug("Error %d reading lsm name\n", ret);
+ return ret;
+ }
+
+ if (!(ctx->uflags & RESTART_KEEP_LSM))
+ goto skip_lsm;
+
+ if (strncmp(cur_lsm, ctx->lsm_name, CHECKPOINT_LSM_NAME_MAX + 1) != 0) {
+ ckpt_debug("c/r: checkpointed LSM %s, current is %s.\n",
+ ctx->lsm_name, cur_lsm);
+ return -EPERM;
+ }
+
+ if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
+ strcmp(ctx->lsm_name, "default") != 0) {
+ ckpt_debug("c/r: RESTART_KEEP_LSM unsupported for %s\n",
+ ctx->lsm_name);
+ return -ENOSYS;
+ }
+
+skip_lsm:
+ ret = security_may_restart(ctx);
+ if (ret < 0)
+ ckpt_debug("security_may_restart returned %d\n", ret);
+ return ret;
+}
+
/* read the container configuration section */
static int restore_container(struct ckpt_ctx *ctx)
{
@@ -635,6 +671,11 @@ static int restore_container(struct ckpt_ctx *ctx)
return PTR_ERR(h);
ckpt_hdr_put(ctx, h);
+ /* read the LSM name and info which follow ("are a part of")
+ * the ckpt_hdr_container */
+ ret = restore_lsm(ctx);
+ if (ret < 0)
+ ckpt_debug("Error %d on LSM configuration\n", ret);
return ret;
}
diff --git a/checkpoint/sys.c b/checkpoint/sys.c
index 260a1ee..5b65eb0 100644
--- a/checkpoint/sys.c
+++ b/checkpoint/sys.c
@@ -169,6 +169,27 @@ void *ckpt_hdr_get_type(struct ckpt_ctx *ctx, int len, int type)
return h;
}
+#define DUMMY_LSM_INFO "dummy"
+
+int ckpt_write_dummy_lsm_info(struct ckpt_ctx *ctx)
+{
+ return ckpt_write_obj_type(ctx, DUMMY_LSM_INFO,
+ strlen(DUMMY_LSM_INFO), CKPT_HDR_LSM_INFO);
+}
+
+/*
+ * ckpt_snarf_lsm_info
+ * If there is a CKPT_HDR_LSM_INFO field, toss it.
+ * Used when the current LSM doesn't care about this field.
+ */
+void ckpt_snarf_lsm_info(struct ckpt_ctx *ctx)
+{
+ struct ckpt_hdr *h;
+
+ h = ckpt_read_buf_type(ctx, CKPT_LSM_INFO_LEN, CKPT_HDR_LSM_INFO);
+ if (!IS_ERR(h))
+ ckpt_hdr_put(ctx, h);
+}
/*
* Helpers to manage c/r contexts: allocated for each checkpoint and/or
diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
index 914176c..d62631a 100644
--- a/include/linux/checkpoint.h
+++ b/include/linux/checkpoint.h
@@ -10,7 +10,7 @@
* distribution for more details.
*/
-#define CHECKPOINT_VERSION 3
+#define CHECKPOINT_VERSION 4
/* checkpoint user flags */
#define CHECKPOINT_SUBTREE 0x1
@@ -19,6 +19,7 @@
#define RESTART_TASKSELF 0x1
#define RESTART_FROZEN 0x2
#define RESTART_GHOST 0x4
+#define RESTART_KEEP_LSM 0x8
#ifdef __KERNEL__
#ifdef CONFIG_CHECKPOINT
@@ -48,7 +49,9 @@
#define RESTART_USER_FLAGS \
(RESTART_TASKSELF | \
RESTART_FROZEN | \
+ RESTART_KEEP_LSM | \
RESTART_GHOST)
+#define CKPT_LSM_INFO_LEN 200
extern int walk_task_subtree(struct task_struct *task,
int (*func)(struct task_struct *, void *),
@@ -62,6 +65,8 @@ extern void _ckpt_hdr_put(struct ckpt_ctx *ctx, void *ptr, int n);
extern void ckpt_hdr_put(struct ckpt_ctx *ctx, void *ptr);
extern void *ckpt_hdr_get(struct ckpt_ctx *ctx, int n);
extern void *ckpt_hdr_get_type(struct ckpt_ctx *ctx, int n, int type);
+extern int ckpt_write_dummy_lsm_info(struct ckpt_ctx *ctx);
+extern void ckpt_snarf_lsm_info(struct ckpt_ctx *ctx);
extern int ckpt_write_obj(struct ckpt_ctx *ctx, struct ckpt_hdr *h);
extern int ckpt_write_obj_type(struct ckpt_ctx *ctx,
diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
index ff2e4aa..636e189 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -27,6 +27,15 @@
#endif
/*
+ * /usr/include/linux/security.h is not exported to userspace, so
+ * we need this value here for userspace restart.c to read.
+ *
+ * CHECKPOINT_LSM_NAME_MAX should be SECURITY_NAME_MAX
+ * security_may_restart() has a BUILD_BUG_ON to enforce that.
+ */
+#define CHECKPOINT_LSM_NAME_MAX 10
+
+/*
* To maintain compatibility between 32-bit and 64-bit architecture flavors,
* keep data 64-bit aligned: use padding for structure members, and use
* __attribute__((aligned (8))) for the entire structure.
@@ -71,6 +80,8 @@ enum {
#define CKPT_HDR_STRING CKPT_HDR_STRING
CKPT_HDR_OBJREF,
#define CKPT_HDR_OBJREF CKPT_HDR_OBJREF
+ CKPT_HDR_LSM_INFO,
+#define CKPT_HDR_LSM_INFO CKPT_HDR_LSM_INFO
CKPT_HDR_TREE = 101,
#define CKPT_HDR_TREE CKPT_HDR_TREE
@@ -252,6 +263,11 @@ struct ckpt_const {
/* container configuration section header */
struct ckpt_hdr_container {
struct ckpt_hdr h;
+ /*
+ * the header is followed by the string:
+ * char lsm_name[SECURITY_NAME_MAX + 1]
+ * plus the CKPT_HDR_LSM_INFO section
+ */
};
/* checkpoint image header */
diff --git a/include/linux/checkpoint_types.h b/include/linux/checkpoint_types.h
index fa57cdc..b7d3053 100644
--- a/include/linux/checkpoint_types.h
+++ b/include/linux/checkpoint_types.h
@@ -21,6 +21,7 @@
#include <linux/fs.h>
#include <linux/ktime.h>
#include <linux/wait.h>
+#include <linux/security.h>
struct ckpt_stats {
int uts_ns;
@@ -42,6 +43,7 @@ struct ckpt_ctx {
struct task_struct *root_task; /* [container] root task */
struct nsproxy *root_nsproxy; /* [container] root nsproxy */
struct task_struct *root_freezer; /* [container] root task */
+ char lsm_name[SECURITY_NAME_MAX + 1]; /* security module at ckpt */
unsigned long kflags; /* kerenl flags */
unsigned long uflags; /* user flags */
diff --git a/include/linux/security.h b/include/linux/security.h
index 1f16eea..99e4ebc 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -136,6 +136,13 @@ static inline unsigned long round_hint_to_min(unsigned long hint)
extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
+#ifdef CONFIG_CHECKPOINT
+struct ckpt_ctx;
+
+void ckpt_snarf_lsm_info(struct ckpt_ctx *ctx);
+int ckpt_write_dummy_lsm_info(struct ckpt_ctx *ctx);
+#endif
+
#ifdef CONFIG_SECURITY
struct security_mnt_opts {
@@ -1320,6 +1327,28 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @secdata contains the security context.
* @seclen contains the length of the security context.
*
+ * Security hooks for Checkpoint/restart
+ * (In addition to *_checkpoint and *_restore)
+ *
+ * @may_restart:
+ * Authorize sys_restart().
+ * Note that all construction of kernel resources, credentials,
+ * etc is already authorized per the caller's credentials. This
+ * hook is intended for the LSM to make further decisions about
+ * a task not being allowed to restart at all, for instance if
+ * the policy has changed since checkpoint.
+ * @ctx is the checkpoint/restart context (see <linux/checkpoint_types.h>)
+ * Return 0 if allowed, <0 on error.
+ *
+ * @checkpoint_header:
+ * Optionally write out a LSM-specific checkpoint header. This is
+ * a chance to write out policy information, for instance. The same
+ * LSM on restart can then use the info in security_may_restart() to
+ * refuse restart (for instance) across policy changes.
+ * The info is to be written as a an object of type CKPT_HDR_LSM_INFO.
+ * @ctx is the checkpoint/restart context (see <linux/checkpoint_types.h>)
+ * Return 0 on success, <0 on error.
+ *
* Security hooks for Audit
*
* @audit_rule_init:
@@ -1556,6 +1585,11 @@ struct security_operations {
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx) (char *secdata, u32 seclen);
+#ifdef CONFIG_CHECKPOINT
+ int (*may_restart) (struct ckpt_ctx *ctx);
+ int (*checkpoint_header) (struct ckpt_ctx *ctx);
+#endif
+
#ifdef CONFIG_SECURITY_NETWORK
int (*unix_stream_connect) (struct socket *sock,
struct socket *other, struct sock *newsk);
@@ -1796,6 +1830,12 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
+#ifdef CONFIG_CHECKPOINT
+int security_may_restart(struct ckpt_ctx *ctx);
+int security_checkpoint_header(struct ckpt_ctx *ctx);
+#endif /* CONFIG_CHECKPOINT */
+
+char *security_get_lsm_name(void);
#else /* CONFIG_SECURITY */
struct security_mnt_opts {
};
@@ -1818,6 +1858,12 @@ static inline int security_init(void)
return 0;
}
+#define DEFAULT_LSM_NAME "lsm_none"
+static inline char *security_get_lsm_name(void)
+{
+ return DEFAULT_LSM_NAME;
+}
+
static inline int security_ptrace_may_access(struct task_struct *child,
unsigned int mode)
{
@@ -2537,6 +2583,18 @@ static inline int security_secctx_to_secid(const char *secdata,
static inline void security_release_secctx(char *secdata, u32 seclen)
{
}
+
+#ifdef CONFIG_CHECKPOINT
+static inline int security_may_restart(struct ckpt_ctx *ctx)
+{
+ ckpt_snarf_lsm_info(ctx);
+ return 0;
+}
+static inline int security_checkpoint_header(struct ckpt_ctx *ctx)
+{
+ return ckpt_write_dummy_lsm_info(ctx);
+}
+#endif /* CONFIG_CHECKPOINT */
#endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_NETWORK
diff --git a/security/capability.c b/security/capability.c
index 88f752e..23026e2 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -792,6 +792,26 @@ static void cap_release_secctx(char *secdata, u32 seclen)
{
}
+#ifdef CONFIG_CHECKPOINT
+static int cap_may_restart(struct ckpt_ctx *ctx)
+{
+ /*
+ * Note that all construction of kernel resources, credentials,
+ * etc is already authorized per the caller's credentials. This
+ * hook is intended for the LSM to make further decisions about
+ * a task not being allowed to restart at all, for instance if
+ * the policy has changed since checkpoint.
+ */
+ ckpt_snarf_lsm_info(ctx);
+ return 0;
+}
+
+static int cap_checkpoint_header(struct ckpt_ctx *ctx)
+{
+ return ckpt_write_dummy_lsm_info(ctx);
+}
+#endif
+
#ifdef CONFIG_KEYS
static int cap_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
@@ -992,6 +1012,10 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, secid_to_secctx);
set_to_cap_if_null(ops, secctx_to_secid);
set_to_cap_if_null(ops, release_secctx);
+#ifdef CONFIG_CHECKPOINT
+ set_to_cap_if_null(ops, may_restart);
+ set_to_cap_if_null(ops, checkpoint_header);
+#endif
#ifdef CONFIG_SECURITY_NETWORK
set_to_cap_if_null(ops, unix_stream_connect);
set_to_cap_if_null(ops, unix_may_send);
diff --git a/security/security.c b/security/security.c
index dc7674f..e4fa91a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -16,6 +16,9 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/security.h>
+#ifdef CONFIG_CHECKPOINT
+#include <linux/checkpoint.h>
+#endif
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
@@ -122,6 +125,11 @@ int register_security(struct security_operations *ops)
return 0;
}
+char *security_get_lsm_name(void)
+{
+ return security_ops->name;
+}
+
/* Security operations */
int security_ptrace_may_access(struct task_struct *child, unsigned int mode)
@@ -959,6 +967,24 @@ void security_release_secctx(char *secdata, u32 seclen)
}
EXPORT_SYMBOL(security_release_secctx);
+#ifdef CONFIG_CHECKPOINT
+int security_may_restart(struct ckpt_ctx *ctx)
+{
+ /*
+ * SECURITY_NAME_MAX is defined in linux/security.h,
+ * CHECKPOINT_LSM_NAME_MAX in linux/checkpoint_hdr.h
+ */
+ BUILD_BUG_ON(CHECKPOINT_LSM_NAME_MAX != SECURITY_NAME_MAX);
+
+ return security_ops->may_restart(ctx);
+}
+
+int security_checkpoint_header(struct ckpt_ctx *ctx)
+{
+ return security_ops->checkpoint_header(ctx);
+}
+#endif
+
#ifdef CONFIG_SECURITY_NETWORK
int security_unix_stream_connect(struct socket *sock, struct socket *other,
--
1.6.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH user-cr] restart: accept the lsm_name field in header and add -k flag (v2)
[not found] ` <20091015203721.GA5030-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
@ 2009-10-15 20:38 ` Serge E. Hallyn
0 siblings, 0 replies; 2+ messages in thread
From: Serge E. Hallyn @ 2009-10-15 20:38 UTC (permalink / raw)
To: Oren Laadan; +Cc: Linux Containers
The checkpoint file header now has an 11-character string
containing the name of the active LSM, following the uts
info, and a variable length buffer type conaining LSM-specific
version information (for instance a sha1sum of policy).
Handle these.
Also add a -k (--keeplsm) flag to tell restart to set the
RESTART_KEEP_LSM flag to sys_restart().
Changelog:
oct 15: separate out from container config section patch
oct 05: 1. move keep_lsm into arg struct
2. read a separate container config section
3. use CHECKPOINT_LSM_NAME_MAX
Signed-off-by: Serge E. Hallyn <serue-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
---
restart.c | 39 +++++++++++++++++++++++++++++++++++++--
1 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/restart.c b/restart.c
index fa786ef..588ab97 100644
--- a/restart.c
+++ b/restart.c
@@ -68,6 +68,7 @@ static char usage_str[] =
" --signal=SIG send SIG to root task on SIGINT (default: SIGKILL\n"
" to container root, SIGINT otherwise)\n"
" -w,--wait wait for root task to termiate (default)\n"
+" -k,--keeplsm Try to recreate original LSM labels on all objects\n"
" --show-status show exit status of root task (implies -w)\n"
" --copy-status imitate exit status of root task (implies -w)\n"
" -W,--no-wait do not wait for root task to terminate\n"
@@ -350,6 +351,7 @@ struct args {
int copy_status;
char *freezer;
char *input;
+ int keep_lsm;
};
static void usage(char *str)
@@ -380,6 +382,7 @@ static void parse_args(struct args *args, int argc, char *argv[])
{ "self", no_argument, NULL, 6},
{ "signal", required_argument, NULL, 4 },
{ "inspect", no_argument, NULL, 5 },
+ { "keeplsm", no_argument, NULL, 'k' },
{ "input", required_argument, NULL, 'i' },
{ "root", required_argument, NULL, 'r' },
{ "wait", no_argument, NULL, 'w' },
@@ -391,7 +394,7 @@ static void parse_args(struct args *args, int argc, char *argv[])
{ "debug", no_argument, NULL, 'd' },
{ NULL, 0, NULL, 0 }
};
- static char optc[] = "hdvpPwWF:r:i:";
+ static char optc[] = "hdvpkPwWF:r:i:";
int sig;
@@ -446,6 +449,9 @@ static void parse_args(struct args *args, int argc, char *argv[])
case 'w':
args->wait = 1;
break;
+ case 'k':
+ args->keep_lsm = RESTART_KEEP_LSM;
+ break;
case 'W':
args->wait = 0;
break;
@@ -936,6 +942,7 @@ static int ckpt_coordinator(struct ckpt_ctx *ctx)
if (ctx->args->freezer)
flags |= RESTART_FROZEN;
+ flags |= ctx->args->keep_lsm;
ret = restart(root_pid, STDIN_FILENO, flags);
if (ret < 0) {
@@ -1584,6 +1591,8 @@ static int ckpt_make_tree(struct ckpt_ctx *ctx, struct task *task)
if (task->flags & (TASK_GHOST | TASK_DEAD))
flags |= RESTART_GHOST;
+ flags |= ctx->args->keep_lsm;
+
/* on success this doesn't return */
ckpt_dbg("about to call sys_restart(), flags %#lx\n", flags);
ret = restart(0, STDIN_FILENO, flags);
@@ -2116,10 +2125,23 @@ static int ckpt_read_header_arch(struct ckpt_ctx *ctx)
static int ckpt_read_container(struct ckpt_ctx *ctx)
{
+ int ret;
struct ckpt_hdr_container *h;
+ char *ptr;
h = (struct ckpt_hdr_container *) ctx->container;
- return ckpt_read_obj_type(ctx, h, sizeof(*h), CKPT_HDR_CONTAINER);
+ ret = ckpt_read_obj_type(ctx, h, sizeof(*h), CKPT_HDR_CONTAINER);
+ if (ret < 0)
+ return ret;
+
+ ptr = (char *) h;
+ ptr += ((struct ckpt_hdr *) ptr)->len;
+ ret = ckpt_read_obj_buffer(ctx, ptr, CHECKPOINT_LSM_NAME_MAX + 1);
+ if (ret < 0)
+ return ret;
+
+ ptr += ((struct ckpt_hdr *) ptr)->len;
+ return ckpt_read_obj_type(ctx, ptr, 200, CKPT_HDR_LSM_INFO);
}
static int ckpt_read_tree(struct ckpt_ctx *ctx)
@@ -2197,9 +2219,22 @@ static int ckpt_write_header_arch(struct ckpt_ctx *ctx)
static int ckpt_write_container(struct ckpt_ctx *ctx)
{
char *ptr;
+ int ret;
ptr = (char *) ctx->container;
/* write the container info section */
+ ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+ if (ret < 0)
+ return ret;
+
+ /* write the lsm name buffer */
+ ptr += ((struct ckpt_hdr *) ptr)->len;
+ ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+ if (ret < 0)
+ return ret;
+
+ /* write the lsm policy section */
+ ptr += ((struct ckpt_hdr *) ptr)->len;
return ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
}
--
1.6.1.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2009-10-15 20:38 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-15 20:37 [PATCH] add lsm name and lsm_info (policy header) to container info Serge E. Hallyn
[not found] ` <20091015203721.GA5030-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2009-10-15 20:38 ` [PATCH user-cr] restart: accept the lsm_name field in header and add -k flag (v2) Serge E. Hallyn
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.