linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Add session isolation and context saving to the space manager
@ 2017-01-18 15:08 James Bottomley
  2017-01-18 15:09 ` [PATCH 1/2] tpm2: add session handle isolation to tpm spaces James Bottomley
  2017-01-18 15:10 ` [PATCH 2/2] tpm2: context save and restore space managed sessions James Bottomley
  0 siblings, 2 replies; 11+ messages in thread
From: James Bottomley @ 2017-01-18 15:08 UTC (permalink / raw)
  To: tpmdd-devel; +Cc: open list, linux-security-module

As requested, the first patch adds isolation and the second does
context switching.  I've also removed the flush emulation which changed
transient object accounting from lazy to strict.  Note that session
tracking has to be strict because the TPM needs to manage these closely
to avoid running out of global session numbers.

James

---

James Bottomley (2):
  tpm2: add session handle isolation to tpm spaces
  tpm2: context save and restore space managed sessions

 drivers/char/tpm/tpm-chip.c   |   6 +
 drivers/char/tpm/tpm.h        |   3 +
 drivers/char/tpm/tpm2-space.c | 377 ++++++++++++++++++++++++++++++++++--------
 drivers/char/tpm/tpms-dev.c   |   8 +
 4 files changed, 325 insertions(+), 69 deletions(-)

-- 
2.6.6

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/2] tpm2: add session handle isolation to tpm spaces
  2017-01-18 15:08 [PATCH 0/2] Add session isolation and context saving to the space manager James Bottomley
@ 2017-01-18 15:09 ` James Bottomley
  2017-01-19 11:58   ` [tpmdd-devel] " Jarkko Sakkinen
  2017-01-18 15:10 ` [PATCH 2/2] tpm2: context save and restore space managed sessions James Bottomley
  1 sibling, 1 reply; 11+ messages in thread
From: James Bottomley @ 2017-01-18 15:09 UTC (permalink / raw)
  To: tpmdd-devel; +Cc: open list, linux-security-module

sessions should be isolated during each instance of a tpm space.  This
means that spaces shouldn't be able to see each other's sessions and
also when a space is closed, all the sessions belonging to it should
be flushed.

This is implemented by adding a session_tbl to the space to track the
created session handles.  Sessions can be flushed either by not
setting the continueSession attribute in the session table or by an
explicit flush.  In the first case we have to mark the session as
being ready to flush and explicitly forget it if the command completes
successfully and in the second case we have to intercept the flush
instruction and clear the session from our table.

Finally, when the device handling the space is closed, we have to send
explicit flushes to all the remaining sessions belonging to the space
to ensure they are cleared out.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
 drivers/char/tpm/tpm.h        |   2 +
 drivers/char/tpm/tpm2-space.c | 178 ++++++++++++++++++++++++++++++++++++++++--
 drivers/char/tpm/tpms-dev.c   |   1 +
 3 files changed, 173 insertions(+), 8 deletions(-)

diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 3346c48..265b7f5 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -158,6 +158,7 @@ enum tpm2_cc_attrs {
 struct tpm_space {
 	u32 context_tbl[14];
 	u8 *context_buf;
+	u32 session_tbl[6];
 };
 
 enum tpm_chip_flags {
@@ -584,4 +585,5 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space,
 		       u32 cc, u8 *buf, size_t bufsiz);
 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
 		      u32 cc, u8 *buf, size_t bufsiz);
+void tpm2_flush_space(struct tpm_chip *chip, struct tpm_space *space);
 #endif
diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
index 3708e70..49048af 100644
--- a/drivers/char/tpm/tpm2-space.c
+++ b/drivers/char/tpm/tpm2-space.c
@@ -25,15 +25,83 @@ enum tpm2_handle_types {
 	TPM2_HT_TRANSIENT	= 0x80000000,
 };
 
-static void tpm2_flush_space(struct tpm_chip *chip)
+#define TPM2_HT_TAG_FOR_FLUSH	0xF0000000
+
+static int tpm2_session_find(struct tpm_space *space, u32 handle)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
+		if (handle == space->session_tbl[i])
+			break;
+	if (i == ARRAY_SIZE(space->session_tbl))
+		return -1;
+	return i;
+}
+
+static int tpm2_session_add(struct tpm_chip *chip,
+			    struct tpm_space *space, u32 handle)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
+		if (space->session_tbl[i] == 0)
+			break;
+	if (i == ARRAY_SIZE(space->session_tbl)) {
+		dev_err(&chip->dev, "out of session slots\n");
+		tpm2_flush_context_cmd(chip, handle, TPM_TRANSMIT_UNLOCKED);
+		return -ENOMEM;
+	}
+
+	space->session_tbl[i] = handle;
+
+	return 0;
+}
+
+/* if a space is active, emulate some commands */
+static int tpm2_intercept(struct tpm_chip *chip, struct tpm_space *space,
+			  u32 cc, u8 *buf, size_t bufsiz)
+{
+	int j;
+	u32 handle, handle_type;
+
+	if (!space)
+		return 0;
+
+	if (cc != TPM2_CC_FLUSH_CONTEXT)
+		return 0;
+	handle = get_unaligned_be32((__be32 *)&buf[10]);
+	handle_type = (handle & 0xFF000000);
+
+	if (handle_type != TPM2_HT_HMAC_SESSION &&
+	    handle_type != TPM2_HT_POLICY_SESSION)
+		/* let the TPM figure out and return the error */
+		return 0;
+
+	j = tpm2_session_find(space, handle);
+	if (j < 0)
+		return -EINVAL;
+
+	space->session_tbl[j] |= TPM2_HT_TAG_FOR_FLUSH;
+
+	return 0;
+}
+
+void tpm2_flush_space(struct tpm_chip *chip, struct tpm_space *space)
 {
-	struct tpm_space *space = &chip->work_space;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
 		if (space->context_tbl[i] && ~space->context_tbl[i])
 			tpm2_flush_context_cmd(chip, space->context_tbl[i],
 					       TPM_TRANSMIT_UNLOCKED);
+
+	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+		space->session_tbl[i] &= ~TPM2_HT_TAG_FOR_FLUSH;
+		if (space->session_tbl[i])
+			tpm2_flush_context_cmd(chip, space->session_tbl[i],
+					       TPM_TRANSMIT_UNLOCKED);
+	}
 }
 
 struct tpm2_context {
@@ -94,10 +162,82 @@ static int tpm2_load_space(struct tpm_chip *chip)
 
 out_err:
 	tpm_buf_destroy(&buf);
-	tpm2_flush_space(chip);
+	tpm2_flush_space(chip, space);
 	return rc;
 }
 
+static void tpm2_unmap_sessions(struct tpm_chip *chip, u32 rc)
+{
+	struct tpm_space *space = &chip->work_space;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+		if ((space->session_tbl[i] & TPM2_HT_TAG_FOR_FLUSH) !=
+		    TPM2_HT_TAG_FOR_FLUSH)
+			continue;
+		if (rc == TPM2_RC_SUCCESS)
+			space->session_tbl[i] = 0;
+		else
+			/* for unsuccessful command, keep session */
+			space->session_tbl[i] &= ~TPM2_HT_TAG_FOR_FLUSH;
+	}
+}
+
+static int tpm2_map_sessions(struct tpm_chip *chip, u8 *buf, size_t len,
+			     size_t start)
+{
+	struct tpm_space *space = &chip->work_space;
+	u32 size = be32_to_cpup((__be32 *)&buf[start]);
+	int i;
+
+	/* skip over authorizationSize */
+	start += 4;
+
+	if (size > len - start) {
+		dev_err(&chip->dev, "Invalid authorization header size %u\n",
+			size);
+		return -EINVAL;
+	}
+
+	for (i = start; i < start+size; ) {
+		u16 skip;
+		u8 attr;
+		int j;
+		u32 handle, handle_type;
+
+		/* TPMI_SH_AUTH_SESSION */
+		handle = get_unaligned_be32((__be32 *)&buf[i]);
+		handle_type = handle & 0xFF000000;
+		i += 4;
+		/* TPM2B_DIGEST */
+		skip = get_unaligned_be16((__be16 *)&buf[i]);
+		i += skip + sizeof(skip);
+		/* TPMA_SESSION */
+		attr = buf[i++];
+		/* TPM2B_AUTH */
+		skip = get_unaligned_be16((__be16 *)&buf[i]);
+		i += skip + sizeof(skip);
+
+		if (handle_type != TPM2_HT_HMAC_SESSION &&
+		    handle_type != TPM2_HT_POLICY_SESSION)
+			continue;
+
+		j = tpm2_session_find(space, handle);
+		if (j < 0)
+			return -EINVAL;
+		if ((attr & 1) == 0)
+			/* session is flushed by the command */
+			space->session_tbl[j] |= TPM2_HT_TAG_FOR_FLUSH;
+	}
+
+	if (i != start+size) {
+		dev_err(&chip->dev, "Authorization session overflow\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd, size_t len)
 {
 	struct tpm_space *space = &chip->work_space;
@@ -105,6 +245,7 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd, size_t len)
 	u32 vhandle;
 	u32 phandle;
 	u32 attrs;
+	u16 tag = get_unaligned_be16((__be16 *)cmd);
 	int i;
 	int j;
 	int rc;
@@ -132,11 +273,14 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd, size_t len)
 		*((__be32 *)&cmd[TPM_HEADER_SIZE + 4 * i]) =
 			cpu_to_be32(phandle);
 	}
+	if (tag == TPM2_ST_SESSIONS)
+		tpm2_map_sessions(chip, cmd, len,
+				  TPM_HEADER_SIZE + 4*nr_handles);
 
 	return 0;
 
 out_err:
-	tpm2_flush_space(chip);
+	tpm2_flush_space(chip, space);
 	return rc;
 }
 
@@ -150,8 +294,14 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space,
 
 	memcpy(&chip->work_space.context_tbl, &space->context_tbl,
 	       sizeof(space->context_tbl));
+	memcpy(&chip->work_space.session_tbl, &space->session_tbl,
+	       sizeof(space->session_tbl));
 	memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE);
 
+	rc = tpm2_intercept(chip, space, cc, buf, bufsiz);
+	if (rc)
+		return rc;
+
 	rc = tpm2_load_space(chip);
 	if (rc)
 		return rc;
@@ -166,13 +316,17 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space,
 static int tpm2_map_response(struct tpm_chip *chip, u32 cc, u8 *rsp, size_t len)
 {
 	struct tpm_space *space = &chip->work_space;
-	u32 phandle;
+	u32 phandle, phandle_type;
 	u32 vhandle;
 	u32 attrs;
 	u32 return_code = get_unaligned_be32((__be32 *)&rsp[6]);
+	u16 tag = get_unaligned_be16((__be16 *)rsp);
 	int i;
 	int rc;
 
+	if (tag == TPM2_ST_SESSIONS)
+		tpm2_unmap_sessions(chip, return_code);
+
 	if (return_code != TPM2_RC_SUCCESS)
 		return 0;
 
@@ -188,9 +342,15 @@ static int tpm2_map_response(struct tpm_chip *chip, u32 cc, u8 *rsp, size_t len)
 		return 0;
 
 	phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]);
-	if ((phandle & 0xFF000000) != TPM2_HT_TRANSIENT)
+	phandle_type = (phandle & 0xFF000000);
+	if (phandle_type != TPM2_HT_TRANSIENT &&
+	    phandle_type != TPM2_HT_HMAC_SESSION &&
+	    phandle_type != TPM2_HT_POLICY_SESSION)
 		return 0;
 
+	if (phandle_type != TPM2_HT_TRANSIENT)
+		return tpm2_session_add(chip, space, phandle);
+
 	/* Garbage collect a dead context. */
 	for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
 		if (space->context_tbl[i] == phandle) {
@@ -217,7 +377,7 @@ static int tpm2_map_response(struct tpm_chip *chip, u32 cc, u8 *rsp, size_t len)
 	return 0;
 
 out_err:
-	tpm2_flush_space(chip);
+	tpm2_flush_space(chip, space);
 	return rc;
 }
 
@@ -277,7 +437,7 @@ static int tpm2_save_space(struct tpm_chip *chip)
 	return 0;
 out_err:
 	tpm_buf_destroy(&buf);
-	tpm2_flush_space(chip);
+	tpm2_flush_space(chip, space);
 	return rc;
 }
 
@@ -299,6 +459,8 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
 
 	memcpy(&space->context_tbl, &chip->work_space.context_tbl,
 	       sizeof(space->context_tbl));
+	memcpy(&space->session_tbl, &chip->work_space.session_tbl,
+	       sizeof(space->session_tbl));
 	memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE);
 
 	return 0;
diff --git a/drivers/char/tpm/tpms-dev.c b/drivers/char/tpm/tpms-dev.c
index 6bb687f..d6e3491 100644
--- a/drivers/char/tpm/tpms-dev.c
+++ b/drivers/char/tpm/tpms-dev.c
@@ -36,6 +36,7 @@ static int tpms_release(struct inode *inode, struct file *file)
 	struct file_priv *fpriv = file->private_data;
 	struct tpms_priv *priv = container_of(fpriv, struct tpms_priv, priv);
 
+	tpm2_flush_space(fpriv->chip, &priv->space);
 	tpm_common_release(file, fpriv);
 	kfree(priv->space.context_buf);
 	kfree(priv);
-- 
2.6.6

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/2] tpm2: context save and restore space managed sessions
  2017-01-18 15:08 [PATCH 0/2] Add session isolation and context saving to the space manager James Bottomley
  2017-01-18 15:09 ` [PATCH 1/2] tpm2: add session handle isolation to tpm spaces James Bottomley
@ 2017-01-18 15:10 ` James Bottomley
  2017-01-19 12:04   ` [tpmdd-devel] " Jarkko Sakkinen
  1 sibling, 1 reply; 11+ messages in thread
From: James Bottomley @ 2017-01-18 15:10 UTC (permalink / raw)
  To: tpmdd-devel; +Cc: open list, linux-security-module

Now that sessions are isolated, we can introduce a session_buf in the
tpm2 space to save and restore them.  This allows us to have many more
sessions active simultaneously (up to TPM_PT_MAX_SESSIONS).  As part
of this, we must intercept and manually remove contexts for flushed
sessions.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
 drivers/char/tpm/tpm-chip.c   |   6 ++
 drivers/char/tpm/tpm.h        |   1 +
 drivers/char/tpm/tpm2-space.c | 223 ++++++++++++++++++++++++++++--------------
 drivers/char/tpm/tpms-dev.c   |   7 ++
 4 files changed, 164 insertions(+), 73 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 96ea93e..a625884 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -130,6 +130,7 @@ static void tpm_dev_release(struct device *dev)
 
 	kfree(chip->log.bios_event_log);
 	kfree(chip->work_space.context_buf);
+	kfree(chip->work_space.session_buf);
 	kfree(chip);
 }
 
@@ -223,6 +224,11 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
 		rc = -ENOMEM;
 		goto out;
 	}
+	chip->work_space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!chip->work_space.session_buf) {
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	return chip;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 265b7f5..9923daa 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -159,6 +159,7 @@ struct tpm_space {
 	u32 context_tbl[14];
 	u8 *context_buf;
 	u32 session_tbl[6];
+	u8 *session_buf;
 };
 
 enum tpm_chip_flags {
diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
index 49048af..04c9431 100644
--- a/drivers/char/tpm/tpm2-space.c
+++ b/drivers/char/tpm/tpm2-space.c
@@ -27,6 +27,91 @@ enum tpm2_handle_types {
 
 #define TPM2_HT_TAG_FOR_FLUSH	0xF0000000
 
+struct tpm2_context {
+	__be64 sequence;
+	__be32 saved_handle;
+	__be32 hierarchy;
+	__be16 blob_size;
+} __packed;
+
+static int tpm2_context_save(struct tpm_chip *chip, u8 *area,
+			     int *offset, u32 handle)
+{
+	struct tpm_buf buf;
+	u32 s;
+	int rc;
+
+	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
+			  TPM2_CC_CONTEXT_SAVE);
+	if (rc)
+		return rc;
+
+	tpm_buf_append_u32(&buf, handle);
+
+	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
+			      TPM_HEADER_SIZE, TPM_TRANSMIT_UNLOCKED,
+			      NULL);
+	if ((rc & TPM2_RC_HANDLE) == TPM2_RC_HANDLE) {
+		/* no handle to save */
+		rc = 1;
+		goto out;
+	} else if (rc) {
+		dev_warn(&chip->dev, "%s: saving failed with %d\n",
+			 __func__, rc);
+		rc = -EFAULT;
+		goto out;
+	}
+
+	s = tpm_buf_length(&buf) - TPM_HEADER_SIZE;
+	if ((*offset + s) > PAGE_SIZE) {
+		dev_warn(&chip->dev, "out of context storage\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	memcpy(&area[*offset], &buf.data[TPM_HEADER_SIZE], s);
+	*offset += s;
+
+ out:
+	tpm_buf_destroy(&buf);
+	return rc;
+}
+
+static int tpm2_context_load(struct tpm_chip *chip, u8 *area,
+			     int *offset, u32 *handle)
+{
+	struct tpm_buf buf;
+	struct tpm2_context *ctx;
+	int rc;
+	u32 s;
+
+	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
+			  TPM2_CC_CONTEXT_LOAD);
+	if (rc)
+		return rc;
+
+	ctx = (struct tpm2_context *)&area[*offset];
+	s = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
+	tpm_buf_append(&buf, (const void *)ctx, s);
+
+	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
+			      TPM_HEADER_SIZE + 4,
+			      TPM_TRANSMIT_UNLOCKED, NULL);
+	if (rc) {
+		dev_warn(&chip->dev, "context loading failed with %d\n", rc);
+		rc = -EFAULT;
+		goto out;
+	}
+	*handle = get_unaligned_be32((__be32 *)&buf.data[TPM_HEADER_SIZE]);
+
+	*offset += s;
+
+ out:
+	tpm_buf_destroy(&buf);
+
+	return rc;
+}
+
 static int tpm2_session_find(struct tpm_space *space, u32 handle)
 {
 	int i;
@@ -58,11 +143,35 @@ static int tpm2_session_add(struct tpm_chip *chip,
 	return 0;
 }
 
+static int tpm2_session_forget(struct tpm_space *space, u32 handle)
+{
+	int i, j;
+	struct tpm2_context *ctx;
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+		if (space->session_tbl[i] == 0)
+			continue;
+
+		ctx = (struct tpm2_context *)&space->session_buf[j];
+		j += sizeof(*ctx) + get_unaligned_be16(&ctx->blob_size);
+
+		if (space->session_tbl[i] != handle)
+			continue;
+
+		/* forget the session context */
+		memcpy(ctx, &space->session_buf[j], PAGE_SIZE - j);
+		space->session_tbl[i] = 0;
+		break;
+	}
+	if (i == ARRAY_SIZE(space->session_tbl))
+		return -EINVAL;
+	return 0;
+}
+
 /* if a space is active, emulate some commands */
-static int tpm2_intercept(struct tpm_chip *chip, struct tpm_space *space,
-			  u32 cc, u8 *buf, size_t bufsiz)
+static int tpm2_intercept(struct tpm_chip *chip, u32 cc, u8 *buf, size_t bufsiz)
 {
-	int j;
+	struct tpm_space *space = &chip->work_space;
 	u32 handle, handle_type;
 
 	if (!space)
@@ -78,13 +187,7 @@ static int tpm2_intercept(struct tpm_chip *chip, struct tpm_space *space,
 		/* let the TPM figure out and return the error */
 		return 0;
 
-	j = tpm2_session_find(space, handle);
-	if (j < 0)
-		return -EINVAL;
-
-	space->session_tbl[j] |= TPM2_HT_TAG_FOR_FLUSH;
-
-	return 0;
+	return tpm2_session_forget(space, handle);
 }
 
 void tpm2_flush_space(struct tpm_chip *chip, struct tpm_space *space)
@@ -104,22 +207,12 @@ void tpm2_flush_space(struct tpm_chip *chip, struct tpm_space *space)
 	}
 }
 
-struct tpm2_context {
-	__be64 sequence;
-	__be32 saved_handle;
-	__be32 hierarchy;
-	__be16 blob_size;
-} __packed;
-
 static int tpm2_load_space(struct tpm_chip *chip)
 {
 	struct tpm_space *space = &chip->work_space;
-	struct tpm2_context *ctx;
-	struct tpm_buf buf;
 	int i;
 	int j;
 	int rc;
-	u32 s;
 
 	for (i = 0, j = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
 		if (!space->context_tbl[i])
@@ -131,37 +224,33 @@ static int tpm2_load_space(struct tpm_chip *chip)
 			return -EFAULT;
 		}
 
-		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
-				 TPM2_CC_CONTEXT_LOAD);
+		rc = tpm2_context_load(chip, space->context_buf,
+				       &j, &space->context_tbl[i]);
 		if (rc)
-			return rc;
-
-		ctx = (struct tpm2_context *)&space->context_buf[j];
-		s = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
-		tpm_buf_append(&buf, &space->context_buf[j], s);
-
-		rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
-				      TPM_HEADER_SIZE + 4,
-				      TPM_TRANSMIT_UNLOCKED, NULL);
-		if (rc) {
-			dev_warn(&chip->dev, "%s: loading failed with %d\n",
-				 __func__, rc);
-			rc = -EFAULT;
 			goto out_err;
-		}
 
-		space->context_tbl[i] =
-			be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE]);
+	}
 
-		j += s;
+	for (i = 0, j = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+		u32 handle;
 
-		tpm_buf_destroy(&buf);
+		if (!space->session_tbl[i])
+			continue;
+
+		rc = tpm2_context_load(chip, space->session_buf,
+				       &j, &handle);
+		if (rc)
+			goto out_err;
+		if (handle != (space->session_tbl[i] & ~TPM2_HT_TAG_FOR_FLUSH)) {
+			dev_warn(&chip->dev, "session restored to wrong handle\n");
+			rc = -EFAULT;
+			goto out_err;
+		}
 	}
 
 	return 0;
 
 out_err:
-	tpm_buf_destroy(&buf);
 	tpm2_flush_space(chip, space);
 	return rc;
 }
@@ -297,8 +386,9 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space,
 	memcpy(&chip->work_space.session_tbl, &space->session_tbl,
 	       sizeof(space->session_tbl));
 	memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE);
+	memcpy(chip->work_space.session_buf, space->session_buf, PAGE_SIZE);
 
-	rc = tpm2_intercept(chip, space, cc, buf, bufsiz);
+	rc = tpm2_intercept(chip, cc, buf, bufsiz);
 	if (rc)
 		return rc;
 
@@ -384,59 +474,45 @@ static int tpm2_map_response(struct tpm_chip *chip, u32 cc, u8 *rsp, size_t len)
 static int tpm2_save_space(struct tpm_chip *chip)
 {
 	struct tpm_space *space = &chip->work_space;
-	struct tpm_buf buf;
 	int i;
 	int j;
 	int rc;
-	u32 s;
 
 	for (i = 0, j = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
 		if (!(space->context_tbl[i] && ~space->context_tbl[i]))
 			continue;
 
-		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
-				  TPM2_CC_CONTEXT_SAVE);
-		if (rc)
-			return rc;
-
-		tpm_buf_append_u32(&buf, space->context_tbl[i]);
-
-		rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
-				      TPM_HEADER_SIZE, TPM_TRANSMIT_UNLOCKED,
-				      NULL);
-		if ((rc & TPM2_RC_HANDLE) == TPM2_RC_HANDLE) {
+		rc = tpm2_context_save(chip, space->context_buf, &j,
+				       space->context_tbl[i]);
+		if (rc < 0)
+			goto out_err;
+		if (rc > 0) {
 			space->context_tbl[i] = 0;
 			continue;
-		} else if (rc) {
-			dev_warn(&chip->dev, "%s: saving failed with %d\n",
-				 __func__, rc);
-			rc = -EFAULT;
-			goto out_err;
 		}
 
-		s = tpm_buf_length(&buf) - TPM_HEADER_SIZE;
-		if ((j + s) > PAGE_SIZE) {
-			dev_warn(&chip->dev, "%s: out of backing storage\n",
-				 __func__);
-			rc = -ENOMEM;
-			goto out_err;
-		}
-
-		memcpy(&space->context_buf[j], &buf.data[TPM_HEADER_SIZE], s);
-
 		tpm2_flush_context_cmd(chip, space->context_tbl[i],
 				       TPM_TRANSMIT_UNLOCKED);
 
 		space->context_tbl[i] = ~0;
+	}
 
-		j += s;
+	for (i = 0, j = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+		if (!space->session_tbl[i])
+			continue;
 
-		tpm_buf_destroy(&buf);
+		rc = tpm2_context_save(chip, space->session_buf, &j,
+				       space->session_tbl[i]);
+		if (rc < 0)
+			goto out_err;
+		if (rc > 0) {
+			space->context_tbl[i] = 0;
+			continue;
+		}
 	}
 
 	return 0;
 out_err:
-	tpm_buf_destroy(&buf);
 	tpm2_flush_space(chip, space);
 	return rc;
 }
@@ -462,6 +538,7 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
 	memcpy(&space->session_tbl, &chip->work_space.session_tbl,
 	       sizeof(space->session_tbl));
 	memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE);
+	memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE);
 
 	return 0;
 }
diff --git a/drivers/char/tpm/tpms-dev.c b/drivers/char/tpm/tpms-dev.c
index d6e3491..12b6e34 100644
--- a/drivers/char/tpm/tpms-dev.c
+++ b/drivers/char/tpm/tpms-dev.c
@@ -25,6 +25,12 @@ static int tpms_open(struct inode *inode, struct file *file)
 		kfree(priv);
 		return -ENOMEM;
 	}
+	priv->space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (priv->space.session_buf == NULL) {
+		kfree(priv->space.context_buf);
+		kfree(priv);
+		return -ENOMEM;
+	}
 
 	tpm_common_open(file, chip, &priv->priv);
 
@@ -39,6 +45,7 @@ static int tpms_release(struct inode *inode, struct file *file)
 	tpm2_flush_space(fpriv->chip, &priv->space);
 	tpm_common_release(file, fpriv);
 	kfree(priv->space.context_buf);
+	kfree(priv->space.session_buf);
 	kfree(priv);
 
 	return 0;
-- 
2.6.6

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 1/2] tpm2: add session handle isolation to tpm spaces
  2017-01-18 15:09 ` [PATCH 1/2] tpm2: add session handle isolation to tpm spaces James Bottomley
@ 2017-01-19 11:58   ` Jarkko Sakkinen
  2017-01-19 12:11     ` James Bottomley
  0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2017-01-19 11:58 UTC (permalink / raw)
  To: James Bottomley; +Cc: tpmdd-devel, linux-security-module, open list

On Wed, Jan 18, 2017 at 10:09:46AM -0500, James Bottomley wrote:
> sessions should be isolated during each instance of a tpm space.  This
> means that spaces shouldn't be able to see each other's sessions and
> also when a space is closed, all the sessions belonging to it should
> be flushed.
> 
> This is implemented by adding a session_tbl to the space to track the
> created session handles.  Sessions can be flushed either by not
> setting the continueSession attribute in the session table or by an
> explicit flush.  In the first case we have to mark the session as
> being ready to flush and explicitly forget it if the command completes
> successfully and in the second case we have to intercept the flush
> instruction and clear the session from our table.

You could do this without these nasty corner cases by arbage collecting
when a command emits a new session handle.

When a session handle is created check if any of the spaces contain it
and remove from the array. No special cases needed.

This will render the need to do any kind of interception whatsoever
unneeded.

/Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 2/2] tpm2: context save and restore space managed sessions
  2017-01-18 15:10 ` [PATCH 2/2] tpm2: context save and restore space managed sessions James Bottomley
@ 2017-01-19 12:04   ` Jarkko Sakkinen
  2017-01-19 12:13     ` James Bottomley
  0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2017-01-19 12:04 UTC (permalink / raw)
  To: James Bottomley; +Cc: tpmdd-devel, linux-security-module, open list

On Wed, Jan 18, 2017 at 10:10:42AM -0500, James Bottomley wrote:
> Now that sessions are isolated, we can introduce a session_buf in the
> tpm2 space to save and restore them.  This allows us to have many more
> sessions active simultaneously (up to TPM_PT_MAX_SESSIONS).  As part
> of this, we must intercept and manually remove contexts for flushed
> sessions.

Again I don't understand the interception part. Like with transient
objects I just catch TPM_RC_HANDLE error and forget them in the save
part.

PS. Do you mind if I take part of the patch that encapsulates a
single context save as of my patch that implements transient object
swapping? It merely moves the code in there to a different location.
Would just make the patch set cleaner. I would do this for v4 of the
patch set.

/Jarkko

> 
> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
> ---
>  drivers/char/tpm/tpm-chip.c   |   6 ++
>  drivers/char/tpm/tpm.h        |   1 +
>  drivers/char/tpm/tpm2-space.c | 223 ++++++++++++++++++++++++++++--------------
>  drivers/char/tpm/tpms-dev.c   |   7 ++
>  4 files changed, 164 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 96ea93e..a625884 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -130,6 +130,7 @@ static void tpm_dev_release(struct device *dev)
>  
>  	kfree(chip->log.bios_event_log);
>  	kfree(chip->work_space.context_buf);
> +	kfree(chip->work_space.session_buf);
>  	kfree(chip);
>  }
>  
> @@ -223,6 +224,11 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>  		rc = -ENOMEM;
>  		goto out;
>  	}
> +	chip->work_space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
> +	if (!chip->work_space.session_buf) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
>  
>  	return chip;
>  
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 265b7f5..9923daa 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -159,6 +159,7 @@ struct tpm_space {
>  	u32 context_tbl[14];
>  	u8 *context_buf;
>  	u32 session_tbl[6];
> +	u8 *session_buf;
>  };
>  
>  enum tpm_chip_flags {
> diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
> index 49048af..04c9431 100644
> --- a/drivers/char/tpm/tpm2-space.c
> +++ b/drivers/char/tpm/tpm2-space.c
> @@ -27,6 +27,91 @@ enum tpm2_handle_types {
>  
>  #define TPM2_HT_TAG_FOR_FLUSH	0xF0000000
>  
> +struct tpm2_context {
> +	__be64 sequence;
> +	__be32 saved_handle;
> +	__be32 hierarchy;
> +	__be16 blob_size;
> +} __packed;
> +
> +static int tpm2_context_save(struct tpm_chip *chip, u8 *area,
> +			     int *offset, u32 handle)
> +{
> +	struct tpm_buf buf;
> +	u32 s;
> +	int rc;
> +
> +	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
> +			  TPM2_CC_CONTEXT_SAVE);
> +	if (rc)
> +		return rc;
> +
> +	tpm_buf_append_u32(&buf, handle);
> +
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
> +			      TPM_HEADER_SIZE, TPM_TRANSMIT_UNLOCKED,
> +			      NULL);
> +	if ((rc & TPM2_RC_HANDLE) == TPM2_RC_HANDLE) {
> +		/* no handle to save */
> +		rc = 1;
> +		goto out;
> +	} else if (rc) {
> +		dev_warn(&chip->dev, "%s: saving failed with %d\n",
> +			 __func__, rc);
> +		rc = -EFAULT;
> +		goto out;
> +	}
> +
> +	s = tpm_buf_length(&buf) - TPM_HEADER_SIZE;
> +	if ((*offset + s) > PAGE_SIZE) {
> +		dev_warn(&chip->dev, "out of context storage\n");
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	memcpy(&area[*offset], &buf.data[TPM_HEADER_SIZE], s);
> +	*offset += s;
> +
> + out:
> +	tpm_buf_destroy(&buf);
> +	return rc;
> +}
> +
> +static int tpm2_context_load(struct tpm_chip *chip, u8 *area,
> +			     int *offset, u32 *handle)
> +{
> +	struct tpm_buf buf;
> +	struct tpm2_context *ctx;
> +	int rc;
> +	u32 s;
> +
> +	rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
> +			  TPM2_CC_CONTEXT_LOAD);
> +	if (rc)
> +		return rc;
> +
> +	ctx = (struct tpm2_context *)&area[*offset];
> +	s = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
> +	tpm_buf_append(&buf, (const void *)ctx, s);
> +
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
> +			      TPM_HEADER_SIZE + 4,
> +			      TPM_TRANSMIT_UNLOCKED, NULL);
> +	if (rc) {
> +		dev_warn(&chip->dev, "context loading failed with %d\n", rc);
> +		rc = -EFAULT;
> +		goto out;
> +	}
> +	*handle = get_unaligned_be32((__be32 *)&buf.data[TPM_HEADER_SIZE]);
> +
> +	*offset += s;
> +
> + out:
> +	tpm_buf_destroy(&buf);
> +
> +	return rc;
> +}
> +
>  static int tpm2_session_find(struct tpm_space *space, u32 handle)
>  {
>  	int i;
> @@ -58,11 +143,35 @@ static int tpm2_session_add(struct tpm_chip *chip,
>  	return 0;
>  }
>  
> +static int tpm2_session_forget(struct tpm_space *space, u32 handle)
> +{
> +	int i, j;
> +	struct tpm2_context *ctx;
> +
> +	for (i = 0, j = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
> +		if (space->session_tbl[i] == 0)
> +			continue;
> +
> +		ctx = (struct tpm2_context *)&space->session_buf[j];
> +		j += sizeof(*ctx) + get_unaligned_be16(&ctx->blob_size);
> +
> +		if (space->session_tbl[i] != handle)
> +			continue;
> +
> +		/* forget the session context */
> +		memcpy(ctx, &space->session_buf[j], PAGE_SIZE - j);
> +		space->session_tbl[i] = 0;
> +		break;
> +	}
> +	if (i == ARRAY_SIZE(space->session_tbl))
> +		return -EINVAL;
> +	return 0;
> +}
> +
>  /* if a space is active, emulate some commands */
> -static int tpm2_intercept(struct tpm_chip *chip, struct tpm_space *space,
> -			  u32 cc, u8 *buf, size_t bufsiz)
> +static int tpm2_intercept(struct tpm_chip *chip, u32 cc, u8 *buf, size_t bufsiz)
>  {
> -	int j;
> +	struct tpm_space *space = &chip->work_space;
>  	u32 handle, handle_type;
>  
>  	if (!space)
> @@ -78,13 +187,7 @@ static int tpm2_intercept(struct tpm_chip *chip, struct tpm_space *space,
>  		/* let the TPM figure out and return the error */
>  		return 0;
>  
> -	j = tpm2_session_find(space, handle);
> -	if (j < 0)
> -		return -EINVAL;
> -
> -	space->session_tbl[j] |= TPM2_HT_TAG_FOR_FLUSH;
> -
> -	return 0;
> +	return tpm2_session_forget(space, handle);
>  }
>  
>  void tpm2_flush_space(struct tpm_chip *chip, struct tpm_space *space)
> @@ -104,22 +207,12 @@ void tpm2_flush_space(struct tpm_chip *chip, struct tpm_space *space)
>  	}
>  }
>  
> -struct tpm2_context {
> -	__be64 sequence;
> -	__be32 saved_handle;
> -	__be32 hierarchy;
> -	__be16 blob_size;
> -} __packed;
> -
>  static int tpm2_load_space(struct tpm_chip *chip)
>  {
>  	struct tpm_space *space = &chip->work_space;
> -	struct tpm2_context *ctx;
> -	struct tpm_buf buf;
>  	int i;
>  	int j;
>  	int rc;
> -	u32 s;
>  
>  	for (i = 0, j = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
>  		if (!space->context_tbl[i])
> @@ -131,37 +224,33 @@ static int tpm2_load_space(struct tpm_chip *chip)
>  			return -EFAULT;
>  		}
>  
> -		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
> -				 TPM2_CC_CONTEXT_LOAD);
> +		rc = tpm2_context_load(chip, space->context_buf,
> +				       &j, &space->context_tbl[i]);
>  		if (rc)
> -			return rc;
> -
> -		ctx = (struct tpm2_context *)&space->context_buf[j];
> -		s = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
> -		tpm_buf_append(&buf, &space->context_buf[j], s);
> -
> -		rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
> -				      TPM_HEADER_SIZE + 4,
> -				      TPM_TRANSMIT_UNLOCKED, NULL);
> -		if (rc) {
> -			dev_warn(&chip->dev, "%s: loading failed with %d\n",
> -				 __func__, rc);
> -			rc = -EFAULT;
>  			goto out_err;
> -		}
>  
> -		space->context_tbl[i] =
> -			be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE]);
> +	}
>  
> -		j += s;
> +	for (i = 0, j = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
> +		u32 handle;
>  
> -		tpm_buf_destroy(&buf);
> +		if (!space->session_tbl[i])
> +			continue;
> +
> +		rc = tpm2_context_load(chip, space->session_buf,
> +				       &j, &handle);
> +		if (rc)
> +			goto out_err;
> +		if (handle != (space->session_tbl[i] & ~TPM2_HT_TAG_FOR_FLUSH)) {
> +			dev_warn(&chip->dev, "session restored to wrong handle\n");
> +			rc = -EFAULT;
> +			goto out_err;
> +		}
>  	}
>  
>  	return 0;
>  
>  out_err:
> -	tpm_buf_destroy(&buf);
>  	tpm2_flush_space(chip, space);
>  	return rc;
>  }
> @@ -297,8 +386,9 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space,
>  	memcpy(&chip->work_space.session_tbl, &space->session_tbl,
>  	       sizeof(space->session_tbl));
>  	memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE);
> +	memcpy(chip->work_space.session_buf, space->session_buf, PAGE_SIZE);
>  
> -	rc = tpm2_intercept(chip, space, cc, buf, bufsiz);
> +	rc = tpm2_intercept(chip, cc, buf, bufsiz);
>  	if (rc)
>  		return rc;
>  
> @@ -384,59 +474,45 @@ static int tpm2_map_response(struct tpm_chip *chip, u32 cc, u8 *rsp, size_t len)
>  static int tpm2_save_space(struct tpm_chip *chip)
>  {
>  	struct tpm_space *space = &chip->work_space;
> -	struct tpm_buf buf;
>  	int i;
>  	int j;
>  	int rc;
> -	u32 s;
>  
>  	for (i = 0, j = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
>  		if (!(space->context_tbl[i] && ~space->context_tbl[i]))
>  			continue;
>  
> -		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS,
> -				  TPM2_CC_CONTEXT_SAVE);
> -		if (rc)
> -			return rc;
> -
> -		tpm_buf_append_u32(&buf, space->context_tbl[i]);
> -
> -		rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
> -				      TPM_HEADER_SIZE, TPM_TRANSMIT_UNLOCKED,
> -				      NULL);
> -		if ((rc & TPM2_RC_HANDLE) == TPM2_RC_HANDLE) {
> +		rc = tpm2_context_save(chip, space->context_buf, &j,
> +				       space->context_tbl[i]);
> +		if (rc < 0)
> +			goto out_err;
> +		if (rc > 0) {
>  			space->context_tbl[i] = 0;
>  			continue;
> -		} else if (rc) {
> -			dev_warn(&chip->dev, "%s: saving failed with %d\n",
> -				 __func__, rc);
> -			rc = -EFAULT;
> -			goto out_err;
>  		}
>  
> -		s = tpm_buf_length(&buf) - TPM_HEADER_SIZE;
> -		if ((j + s) > PAGE_SIZE) {
> -			dev_warn(&chip->dev, "%s: out of backing storage\n",
> -				 __func__);
> -			rc = -ENOMEM;
> -			goto out_err;
> -		}
> -
> -		memcpy(&space->context_buf[j], &buf.data[TPM_HEADER_SIZE], s);
> -
>  		tpm2_flush_context_cmd(chip, space->context_tbl[i],
>  				       TPM_TRANSMIT_UNLOCKED);
>  
>  		space->context_tbl[i] = ~0;
> +	}
>  
> -		j += s;
> +	for (i = 0, j = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
> +		if (!space->session_tbl[i])
> +			continue;
>  
> -		tpm_buf_destroy(&buf);
> +		rc = tpm2_context_save(chip, space->session_buf, &j,
> +				       space->session_tbl[i]);
> +		if (rc < 0)
> +			goto out_err;
> +		if (rc > 0) {
> +			space->context_tbl[i] = 0;
> +			continue;
> +		}
>  	}
>  
>  	return 0;
>  out_err:
> -	tpm_buf_destroy(&buf);
>  	tpm2_flush_space(chip, space);
>  	return rc;
>  }
> @@ -462,6 +538,7 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
>  	memcpy(&space->session_tbl, &chip->work_space.session_tbl,
>  	       sizeof(space->session_tbl));
>  	memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE);
> +	memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE);
>  
>  	return 0;
>  }
> diff --git a/drivers/char/tpm/tpms-dev.c b/drivers/char/tpm/tpms-dev.c
> index d6e3491..12b6e34 100644
> --- a/drivers/char/tpm/tpms-dev.c
> +++ b/drivers/char/tpm/tpms-dev.c
> @@ -25,6 +25,12 @@ static int tpms_open(struct inode *inode, struct file *file)
>  		kfree(priv);
>  		return -ENOMEM;
>  	}
> +	priv->space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
> +	if (priv->space.session_buf == NULL) {
> +		kfree(priv->space.context_buf);
> +		kfree(priv);
> +		return -ENOMEM;
> +	}
>  
>  	tpm_common_open(file, chip, &priv->priv);
>  
> @@ -39,6 +45,7 @@ static int tpms_release(struct inode *inode, struct file *file)
>  	tpm2_flush_space(fpriv->chip, &priv->space);
>  	tpm_common_release(file, fpriv);
>  	kfree(priv->space.context_buf);
> +	kfree(priv->space.session_buf);
>  	kfree(priv);
>  
>  	return 0;
> -- 
> 2.6.6
> 
> 
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, SlashDot.org! http://sdm.link/slashdot
> _______________________________________________
> tpmdd-devel mailing list
> tpmdd-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/tpmdd-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 1/2] tpm2: add session handle isolation to tpm spaces
  2017-01-19 11:58   ` [tpmdd-devel] " Jarkko Sakkinen
@ 2017-01-19 12:11     ` James Bottomley
  2017-01-20 13:23       ` Jarkko Sakkinen
  0 siblings, 1 reply; 11+ messages in thread
From: James Bottomley @ 2017-01-19 12:11 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: tpmdd-devel, linux-security-module, open list

On Thu, 2017-01-19 at 13:58 +0200, Jarkko Sakkinen wrote:
> On Wed, Jan 18, 2017 at 10:09:46AM -0500, James Bottomley wrote:
> > sessions should be isolated during each instance of a tpm space. 
> >  This means that spaces shouldn't be able to see each other's 
> > sessions and also when a space is closed, all the sessions 
> > belonging to it should be flushed.
> > 
> > This is implemented by adding a session_tbl to the space to track 
> > the created session handles.  Sessions can be flushed either by not
> > setting the continueSession attribute in the session table or by an
> > explicit flush.  In the first case we have to mark the session as
> > being ready to flush and explicitly forget it if the command 
> > completes successfully and in the second case we have to intercept 
> > the flush instruction and clear the session from our table.
> 
> You could do this without these nasty corner cases by arbage 
> collecting when a command emits a new session handle.

I could for this patch set.  However, the global session accounting RFC
requires strict accounting, because it needs to know exactly when to
retry a command that failed because we were out of sessions and because
we don't want to needlessly evict a session if there was one available
which we didn't see because of lazy accounting.  It would be a lot of
churn to do it lazily in this patch set and then switch to strict in
that one, so I chose to account sessions strictly always.

> When a session handle is created check if any of the spaces contain 
> it and remove from the array. No special cases needed.
> 
> This will render the need to do any kind of interception whatsoever
> unneeded.

It can be done either way for these two patches, but I think, for the
reason above, it should begin life as it will go on (i.e. strict
accounting).  It's not that much extra code to do it and it's easier to
follow the flow of the three patches.

James

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 2/2] tpm2: context save and restore space managed sessions
  2017-01-19 12:04   ` [tpmdd-devel] " Jarkko Sakkinen
@ 2017-01-19 12:13     ` James Bottomley
  0 siblings, 0 replies; 11+ messages in thread
From: James Bottomley @ 2017-01-19 12:13 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: tpmdd-devel, linux-security-module, open list

On Thu, 2017-01-19 at 14:04 +0200, Jarkko Sakkinen wrote:
> On Wed, Jan 18, 2017 at 10:10:42AM -0500, James Bottomley wrote:
> > Now that sessions are isolated, we can introduce a session_buf in 
> > the tpm2 space to save and restore them.  This allows us to have 
> > many more sessions active simultaneously (up to 
> > TPM_PT_MAX_SESSIONS).  As part of this, we must intercept and 
> > manually remove contexts for flushed sessions.
> 
> Again I don't understand the interception part. Like with transient
> objects I just catch TPM_RC_HANDLE error and forget them in the save
> part.

it's for the global session tracking patch (see other email for
details)

> PS. Do you mind if I take part of the patch that encapsulates a
> single context save as of my patch that implements transient object
> swapping? It merely moves the code in there to a different location.
> Would just make the patch set cleaner. I would do this for v4 of the
> patch set.

Sure.  Rebase should be able to do this easily for me.

James

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 1/2] tpm2: add session handle isolation to tpm spaces
  2017-01-19 12:11     ` James Bottomley
@ 2017-01-20 13:23       ` Jarkko Sakkinen
  2017-01-20 14:39         ` James Bottomley
       [not found]         ` <o5t6ns$k6e$1@blaine.gmane.org>
  0 siblings, 2 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2017-01-20 13:23 UTC (permalink / raw)
  To: James Bottomley; +Cc: tpmdd-devel, linux-security-module, open list

On Thu, Jan 19, 2017 at 07:11:23AM -0500, James Bottomley wrote:
> On Thu, 2017-01-19 at 13:58 +0200, Jarkko Sakkinen wrote:
> > On Wed, Jan 18, 2017 at 10:09:46AM -0500, James Bottomley wrote:
> > > sessions should be isolated during each instance of a tpm space. 
> > >  This means that spaces shouldn't be able to see each other's 
> > > sessions and also when a space is closed, all the sessions 
> > > belonging to it should be flushed.
> > > 
> > > This is implemented by adding a session_tbl to the space to track 
> > > the created session handles.  Sessions can be flushed either by not
> > > setting the continueSession attribute in the session table or by an
> > > explicit flush.  In the first case we have to mark the session as
> > > being ready to flush and explicitly forget it if the command 
> > > completes successfully and in the second case we have to intercept 
> > > the flush instruction and clear the session from our table.
> > 
> > You could do this without these nasty corner cases by arbage 
> > collecting when a command emits a new session handle.
> 
> I could for this patch set.  However, the global session accounting RFC
> requires strict accounting, because it needs to know exactly when to
> retry a command that failed because we were out of sessions and because
> we don't want to needlessly evict a session if there was one available
> which we didn't see because of lazy accounting.  It would be a lot of
> churn to do it lazily in this patch set and then switch to strict in
> that one, so I chose to account sessions strictly always.

Lazy is kind of ambiguous word so I'll have to check that we have same
definition for it in this context.

I'm talking about not trying to detect if something gets deleted. When
something gets created you would go through the global list of sessions
and check if it is used. If so, it must be that the session was deleted
at some point.

Your argument is that in this scheme sometimes there might be a session
marked as "reserved" but it is in fact free. This might lead to useless
eviction. Am I correct?

My argument is that the lazy scheme is more generic (does not require
special cases). As a subsystem maintainer I tend to be more fond of that
kind of solutions. Having special cases raises questios like (for
example):

1. What if standard gets added something that does not fall into the
   current set of special cases? You never know.
2. What about vendor specific commands? The lazy scheme is compatible
   with them. The standard does not put any kind of constraints for
   vendor specific commands.

You could solve the problem you are stating by getting the full the
list of alive sessions with CAP_HANDLES and mark dangling sessions
as free.

PS. I've started to think that maybe also with sessions it is better
to have just one change that implements full eviction like we have
for transient objects after seeing your breakdown. I'm sorry about
putting you extra trouble doing the isolation only patch. It's better
to do this right once...

/Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 1/2] tpm2: add session handle isolation to tpm spaces
  2017-01-20 13:23       ` Jarkko Sakkinen
@ 2017-01-20 14:39         ` James Bottomley
  2017-01-20 17:57           ` Jarkko Sakkinen
       [not found]         ` <o5t6ns$k6e$1@blaine.gmane.org>
  1 sibling, 1 reply; 11+ messages in thread
From: James Bottomley @ 2017-01-20 14:39 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: tpmdd-devel, linux-security-module, open list

On Fri, 2017-01-20 at 15:23 +0200, Jarkko Sakkinen wrote:
> On Thu, Jan 19, 2017 at 07:11:23AM -0500, James Bottomley wrote:
> > On Thu, 2017-01-19 at 13:58 +0200, Jarkko Sakkinen wrote:
> > > On Wed, Jan 18, 2017 at 10:09:46AM -0500, James Bottomley wrote:
> > > > sessions should be isolated during each instance of a tpm 
> > > > space.  This means that spaces shouldn't be able to see each 
> > > > other's sessions and also when a space is closed, all the 
> > > > sessions belonging to it should be flushed.
> > > > 
> > > > This is implemented by adding a session_tbl to the space to 
> > > > track the created session handles.  Sessions can be flushed 
> > > > either by not setting the continueSession attribute in the 
> > > > session table or by an explicit flush.  In the first case we 
> > > > have to mark the session as being ready to flush and explicitly 
> > > > forget it if the command completes successfully and in the 
> > > > second case we have to intercept the flush instruction and
> > > > clear the session from our table.
> > > 
> > > You could do this without these nasty corner cases by arbage 
> > > collecting when a command emits a new session handle.
> > 
> > I could for this patch set.  However, the global session accounting 
> > RFC requires strict accounting, because it needs to know exactly 
> > when to retry a command that failed because we were out of sessions 
> > and because we don't want to needlessly evict a session if there 
> > was one available which we didn't see because of lazy accounting. 
> >  It would be a lot of churn to do it lazily in this patch set and 
> > then switch to strict in that one, so I chose to account sessions
> > strictly always.
> 
> Lazy is kind of ambiguous word so I'll have to check that we have 
> same definition for it in this context.
> 
> I'm talking about not trying to detect if something gets deleted. 
> When something gets created you would go through the global list of
> sessions and check if it is used. If so, it must be that the session 
> was deleted at some point.

That's my terminology too.  We're talking about lazy and strict
tracking of session flushing.

> Your argument is that in this scheme sometimes there might be a
> session marked as "reserved" but it is in fact free. This might lead
> to useless eviction. Am I correct?

Yes, but not just that, it will also lead to over long waits because we
can no longer wake the waiters the moment a session becomes free.

> My argument is that the lazy scheme is more generic (does not require
> special cases). As a subsystem maintainer I tend to be more fond of 
> that kind of solutions. Having special cases raises questios like 
> (for example):
> 
> 1. What if standard gets added something that does not fall into the
>    current set of special cases? You never know.
> 2. What about vendor specific commands? The lazy scheme is compatible
>    with them. The standard does not put any kind of constraints for
>    vendor specific commands.

We rely on the assertion in the Manual that sessions are only returned
in the handle area (as we do for objects).  We also rely on the
guarantee that they're only destroyed by flush or continueSession being
0 in the session attributes.

If some mad vendor introduces a command that creates an object and
doesn't return it in the handle area, we'll get screwed for both
transient objects and sessions.  Sessions also could have issues if
some mad vendor creates a command that flushes them outside of the
above description.  That's why the standard has all these caveats about
handle and session creation.  In theory the vendors are not allowed to
violate them in their own commands ...

> You could solve the problem you are stating by getting the full the
> list of alive sessions with CAP_HANDLES and mark dangling sessions
> as free.

That's a command which produces a huge output ... I'd have to do it at
the end of every input command to get the list of current handles ... I
don't really think it's a better solution.

Let me describe the failure case with strict destruction accounting:
supposing a mad vendor does introduce a command that flushes a session
outside the standards prescribed way.  What happens is that it gets re
-used before the TPM exhausts handles, and tpm2_session_chip_add will
simply to replace what it currently has.  The only consequence is a
single missed wakeup.  So even in the face of vendor failure, this
scheme will work almost all of the time and it will always work better
than a lazy scheme because the failure case gives us properties
identical to the lazy case.  To make this case iron, we should get a
failure on context save, so I can use that failure to drop the handle
and I think the strict scheme will then always perform better than the
lazy scheme (let's call it strict with lazy backup) will that suffice?

> PS. I've started to think that maybe also with sessions it is better
> to have just one change that implements full eviction like we have
> for transient objects after seeing your breakdown. I'm sorry about
> putting you extra trouble doing the isolation only patch. It's better
> to do this right once...

Well, I can put them back together again, but you could just apply them
together as two patches ... they are now bisectable.

James


> /Jarkko
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 1/2] tpm2: add session handle isolation to tpm spaces
  2017-01-20 14:39         ` James Bottomley
@ 2017-01-20 17:57           ` Jarkko Sakkinen
  0 siblings, 0 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2017-01-20 17:57 UTC (permalink / raw)
  To: James Bottomley; +Cc: tpmdd-devel, linux-security-module, open list

On Fri, Jan 20, 2017 at 09:39:13AM -0500, James Bottomley wrote:
> On Fri, 2017-01-20 at 15:23 +0200, Jarkko Sakkinen wrote:
> > On Thu, Jan 19, 2017 at 07:11:23AM -0500, James Bottomley wrote:
> > > On Thu, 2017-01-19 at 13:58 +0200, Jarkko Sakkinen wrote:
> > > > On Wed, Jan 18, 2017 at 10:09:46AM -0500, James Bottomley wrote:
> > > > > sessions should be isolated during each instance of a tpm 
> > > > > space.  This means that spaces shouldn't be able to see each 
> > > > > other's sessions and also when a space is closed, all the 
> > > > > sessions belonging to it should be flushed.
> > > > > 
> > > > > This is implemented by adding a session_tbl to the space to 
> > > > > track the created session handles.  Sessions can be flushed 
> > > > > either by not setting the continueSession attribute in the 
> > > > > session table or by an explicit flush.  In the first case we 
> > > > > have to mark the session as being ready to flush and explicitly 
> > > > > forget it if the command completes successfully and in the 
> > > > > second case we have to intercept the flush instruction and
> > > > > clear the session from our table.
> > > > 
> > > > You could do this without these nasty corner cases by arbage 
> > > > collecting when a command emits a new session handle.
> > > 
> > > I could for this patch set.  However, the global session accounting 
> > > RFC requires strict accounting, because it needs to know exactly 
> > > when to retry a command that failed because we were out of sessions 
> > > and because we don't want to needlessly evict a session if there 
> > > was one available which we didn't see because of lazy accounting. 
> > >  It would be a lot of churn to do it lazily in this patch set and 
> > > then switch to strict in that one, so I chose to account sessions
> > > strictly always.
> > 
> > Lazy is kind of ambiguous word so I'll have to check that we have 
> > same definition for it in this context.
> > 
> > I'm talking about not trying to detect if something gets deleted. 
> > When something gets created you would go through the global list of
> > sessions and check if it is used. If so, it must be that the session 
> > was deleted at some point.
> 
> That's my terminology too.  We're talking about lazy and strict
> tracking of session flushing.
> 
> > Your argument is that in this scheme sometimes there might be a
> > session marked as "reserved" but it is in fact free. This might lead
> > to useless eviction. Am I correct?
> 
> Yes, but not just that, it will also lead to over long waits because we
> can no longer wake the waiters the moment a session becomes free.
> 
> > My argument is that the lazy scheme is more generic (does not require
> > special cases). As a subsystem maintainer I tend to be more fond of 
> > that kind of solutions. Having special cases raises questios like 
> > (for example):
> > 
> > 1. What if standard gets added something that does not fall into the
> >    current set of special cases? You never know.
> > 2. What about vendor specific commands? The lazy scheme is compatible
> >    with them. The standard does not put any kind of constraints for
> >    vendor specific commands.
> 
> We rely on the assertion in the Manual that sessions are only returned
> in the handle area (as we do for objects).  We also rely on the
> guarantee that they're only destroyed by flush or continueSession being
> 0 in the session attributes.
> 
> If some mad vendor introduces a command that creates an object and
> doesn't return it in the handle area, we'll get screwed for both
> transient objects and sessions.  Sessions also could have issues if
> some mad vendor creates a command that flushes them outside of the
> above description.  That's why the standard has all these caveats about
> handle and session creation.  In theory the vendors are not allowed to
> violate them in their own commands ...
> 
> > You could solve the problem you are stating by getting the full the
> > list of alive sessions with CAP_HANDLES and mark dangling sessions
> > as free.
> 
> That's a command which produces a huge output ... I'd have to do it at
> the end of every input command to get the list of current handles ... I
> don't really think it's a better solution.
> 
> Let me describe the failure case with strict destruction accounting:
> supposing a mad vendor does introduce a command that flushes a session
> outside the standards prescribed way.  What happens is that it gets re
> -used before the TPM exhausts handles, and tpm2_session_chip_add will
> simply to replace what it currently has.  The only consequence is a
> single missed wakeup.  So even in the face of vendor failure, this
> scheme will work almost all of the time and it will always work better
> than a lazy scheme because the failure case gives us properties
> identical to the lazy case.  To make this case iron, we should get a
> failure on context save, so I can use that failure to drop the handle
> and I think the strict scheme will then always perform better than the
> lazy scheme (let's call it strict with lazy backup) will that suffice?
> 
> > PS. I've started to think that maybe also with sessions it is better
> > to have just one change that implements full eviction like we have
> > for transient objects after seeing your breakdown. I'm sorry about
> > putting you extra trouble doing the isolation only patch. It's better
> > to do this right once...
> 
> Well, I can put them back together again, but you could just apply them
> together as two patches ... they are now bisectable.

Sure forgot this last comment. It's really irrelevant. I'll reply
properly later on.

> James

/Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [tpmdd-devel] [PATCH 1/2] tpm2: add session handle isolation to tpm spaces
       [not found]         ` <o5t6ns$k6e$1@blaine.gmane.org>
@ 2017-01-20 20:51           ` Jarkko Sakkinen
  0 siblings, 0 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2017-01-20 20:51 UTC (permalink / raw)
  To: Ken Goldman; +Cc: tpmdd-devel, linux-security-module, linux-kernel

On Fri, Jan 20, 2017 at 09:27:25AM -0500, Ken Goldman wrote:
> On 1/20/2017 8:23 AM, Jarkko Sakkinen wrote:
> >
> > I'm talking about not trying to detect if something gets deleted. When
> > something gets created you would go through the global list of sessions
> > and check if it is used. If so, it must be that the session was deleted
> > at some point.
> 
> Are you saying that, when a process flushes (or continue = false) a 
> session, this code won't actually flush the context?  You'll wait until 
> another startauthsession creates a handle, and then delete other 
> occurrences of it?

I just wouldn't get care if a session gets deleted. You can detect it
postmortem when something gets created with the same handle.

/Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2017-01-20 20:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-18 15:08 [PATCH 0/2] Add session isolation and context saving to the space manager James Bottomley
2017-01-18 15:09 ` [PATCH 1/2] tpm2: add session handle isolation to tpm spaces James Bottomley
2017-01-19 11:58   ` [tpmdd-devel] " Jarkko Sakkinen
2017-01-19 12:11     ` James Bottomley
2017-01-20 13:23       ` Jarkko Sakkinen
2017-01-20 14:39         ` James Bottomley
2017-01-20 17:57           ` Jarkko Sakkinen
     [not found]         ` <o5t6ns$k6e$1@blaine.gmane.org>
2017-01-20 20:51           ` Jarkko Sakkinen
2017-01-18 15:10 ` [PATCH 2/2] tpm2: context save and restore space managed sessions James Bottomley
2017-01-19 12:04   ` [tpmdd-devel] " Jarkko Sakkinen
2017-01-19 12:13     ` James Bottomley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).