[Devel] [RFC PATCH 1/2] cr: lsm: provide hooks for an LSM to track policy changes
Serge E. Hallyn
serue at us.ibm.com
Thu Sep 3 15:28:24 PDT 2009
[ This applies on top of the previous LSM c/r patchset. A corresponding
patch against mktree is needed as well. ]
Provide two new security_ hooks:
security_checkpoint_header:
Gives the LSM a chance to write a checkpoint
header object of type CKPT_HDR_LSM_INFO. This
can be any data the LSM deems fit, and can be
written out using
ckpt_write_obj_type(ctx, data, datalen, CKPT_HDR_LSM_INFO);
security_may_restart:
Give the LSM an extra chance to refuse restart. In
particular the LSM may want to do this if the poicy has
changed since checkpoint. The checkpoint per-lsm data can
be retrieved using
ckpt_read_buf_type(ctx, MAX_INFO_LEN, CKPT_HDR_LSM_INFO);
Note that the LSM should only look at that data if
ctx->lsm_name is the current LSM's name. Otherwise the
info will be for another LSM (or the string "dummy").
The hook will still be called, even if ctx->flags
does not have RESTART_KEEP_LSM (meaning we do not restore
checkpointed security labels) since the LSM may have other
reasons to want to refuse restart.
Signed-off-by: Serge E. Hallyn <serue at us.ibm.com>
---
checkpoint/checkpoint.c | 4 +++
checkpoint/restart.c | 4 +++
checkpoint/sys.c | 22 +++++++++++++++++
include/linux/checkpoint.h | 3 ++
include/linux/checkpoint_hdr.h | 1 +
include/linux/security.h | 50 ++++++++++++++++++++++++++++++++++++++++
security/capability.c | 26 ++++++++++++++++++++
security/security.c | 14 +++++++++++
8 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/checkpoint/checkpoint.c b/checkpoint/checkpoint.c
index 9dbb33c..a8e7483 100644
--- a/checkpoint/checkpoint.c
+++ b/checkpoint/checkpoint.c
@@ -257,6 +257,10 @@ static int checkpoint_write_header(struct ckpt_ctx *ctx)
if (ret < 0)
return ret;
+ ret = security_checkpoint_header(ctx);
+ if (ret < 0)
+ return ret;
+
return checkpoint_write_header_arch(ctx);
}
diff --git a/checkpoint/restart.c b/checkpoint/restart.c
index f51838b..3c248c4 100644
--- a/checkpoint/restart.c
+++ b/checkpoint/restart.c
@@ -446,6 +446,10 @@ static int restore_read_header(struct ckpt_ctx *ctx)
}
}
+ ret = security_may_restart(ctx);
+ if (ret < 0)
+ goto out;
+
ret = restore_read_header_arch(ctx);
out:
kfree(uts);
diff --git a/checkpoint/sys.c b/checkpoint/sys.c
index 525182a..a510138 100644
--- a/checkpoint/sys.c
+++ b/checkpoint/sys.c
@@ -169,6 +169,28 @@ 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 3a800a6..bc96fcd 100644
--- a/include/linux/checkpoint.h
+++ b/include/linux/checkpoint.h
@@ -47,6 +47,7 @@
#define CHECKPOINT_USER_FLAGS CHECKPOINT_SUBTREE
#define RESTART_USER_FLAGS (RESTART_TASKSELF | RESTART_FROZEN | \
RESTART_KEEP_LSM)
+#define CKPT_LSM_INFO_LEN 200
extern void exit_checkpoint(struct task_struct *tsk);
@@ -57,6 +58,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 729ca33..78afcec 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -54,6 +54,7 @@ enum {
CKPT_HDR_STRING,
CKPT_HDR_OBJREF,
CKPT_HDR_SEC,
+ CKPT_HDR_LSM_INFO,
CKPT_HDR_TREE = 101,
CKPT_HDR_TASK,
diff --git a/include/linux/security.h b/include/linux/security.h
index 61f224f..d5b18c7 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -45,6 +45,10 @@
struct ctl_table;
struct audit_krule;
+#ifdef CONFIG_CHECKPOINT
+struct ckpt_ctx;
+#endif
+
/*
* These functions are in security/capability.c and are used
* as the default capabilities functions
@@ -1342,6 +1346,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 *_get_ctx 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:
@@ -1586,6 +1612,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);
@@ -1833,6 +1864,10 @@ int security_netlink_recv(struct sk_buff *skb, int cap);
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);
@@ -2637,6 +2672,21 @@ static inline int security_secctx_to_secid(const char *secdata,
static inline void security_release_secctx(char *secdata, u32 seclen)
{
}
+
+#ifdef CONFIG_CHECKPOINT
+void ckpt_snarf_lsm_info(struct ckpt_ctx *ctx);
+int ckpt_write_dummy_lsm_info(struct ckpt_ctx *ctx);
+
+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 28e6495..2577a3c 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -841,6 +841,28 @@ static void cap_release_secctx(char *secdata, u32 seclen)
{
}
+#ifdef CONFIG_CHECKPOINT
+void ckpt_snarf_lsm_info(struct ckpt_ctx *ctx);
+int ckpt_write_dummy_lsm_info(struct ckpt_ctx *ctx);
+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)
@@ -1049,6 +1071,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 d198d0c..2a182d5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1004,6 +1004,20 @@ void security_release_secctx(char *secdata, u32 seclen)
}
EXPORT_SYMBOL(security_release_secctx);
+#ifdef CONFIG_CHECKPOINT
+int security_may_restart(struct ckpt_ctx *ctx)
+{
+ return security_ops->may_restart(ctx);
+}
+EXPORT_SYMBOL(security_may_restart);
+
+int security_checkpoint_header(struct ckpt_ctx *ctx)
+{
+ return security_ops->checkpoint_header(ctx);
+}
+EXPORT_SYMBOL(security_checkpoint_header);
+#endif
+
#ifdef CONFIG_SECURITY_NETWORK
int security_unix_stream_connect(struct socket *sock, struct socket *other,
--
1.6.1
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
More information about the Devel
mailing list