Skip to content

Commit fdc915f

Browse files
James BottomleyJarkko Sakkinen
James Bottomley
authored and
Jarkko Sakkinen
committed
tpm: expose spaces via a device link /dev/tpmrm<n>
Currently the tpm spaces are not exposed to userspace. Make this exposure via a separate device, which can now be opened multiple times because each read/write transaction goes separately via the space. Concurrency is protected by the chip->tpm_mutex for each read/write transaction separately. The TPM is cleared of all transient objects by the time the mutex is dropped, so there should be no interference between the kernel and userspace. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
1 parent ecb38e2 commit fdc915f

File tree

5 files changed

+139
-4
lines changed

5 files changed

+139
-4
lines changed

drivers/char/tpm/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
#
44
obj-$(CONFIG_TCG_TPM) += tpm.o
55
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
6-
tpm-dev-common.o tpm1_eventlog.o tpm2_eventlog.o tpm2-space.o
6+
tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \
7+
tpm2-space.o
78
tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
89
tpm-$(CONFIG_OF) += tpm_of.o
910
obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o

drivers/char/tpm/tpm-chip.c

+57-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ DEFINE_IDR(dev_nums_idr);
3333
static DEFINE_MUTEX(idr_lock);
3434

3535
struct class *tpm_class;
36+
struct class *tpmrm_class;
3637
dev_t tpm_devt;
3738

3839
/**
@@ -132,6 +133,14 @@ static void tpm_dev_release(struct device *dev)
132133
kfree(chip);
133134
}
134135

136+
static void tpm_devs_release(struct device *dev)
137+
{
138+
struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
139+
140+
/* release the master device reference */
141+
put_device(&chip->dev);
142+
}
143+
135144
/**
136145
* tpm_chip_alloc() - allocate a new struct tpm_chip instance
137146
* @pdev: device to which the chip is associated
@@ -168,27 +177,47 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
168177
chip->dev_num = rc;
169178

170179
device_initialize(&chip->dev);
180+
device_initialize(&chip->devs);
171181

172182
chip->dev.class = tpm_class;
173183
chip->dev.release = tpm_dev_release;
174184
chip->dev.parent = pdev;
175185
chip->dev.groups = chip->groups;
176186

187+
chip->devs.parent = pdev;
188+
chip->devs.class = tpmrm_class;
189+
chip->devs.release = tpm_devs_release;
190+
/* get extra reference on main device to hold on
191+
* behalf of devs. This holds the chip structure
192+
* while cdevs is in use. The corresponding put
193+
* is in the tpm_devs_release
194+
*/
195+
get_device(&chip->dev);
196+
177197
if (chip->dev_num == 0)
178198
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
179199
else
180200
chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
181201

202+
chip->devs.devt =
203+
MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
204+
182205
rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num);
206+
if (rc)
207+
goto out;
208+
rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
183209
if (rc)
184210
goto out;
185211

186212
if (!pdev)
187213
chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
188214

189215
cdev_init(&chip->cdev, &tpm_fops);
216+
cdev_init(&chip->cdevs, &tpmrm_fops);
190217
chip->cdev.owner = THIS_MODULE;
218+
chip->cdevs.owner = THIS_MODULE;
191219
chip->cdev.kobj.parent = &chip->dev.kobj;
220+
chip->cdevs.kobj.parent = &chip->devs.kobj;
192221

193222
chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
194223
if (!chip->work_space.context_buf) {
@@ -199,6 +228,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
199228
return chip;
200229

201230
out:
231+
put_device(&chip->devs);
202232
put_device(&chip->dev);
203233
return ERR_PTR(rc);
204234
}
@@ -243,7 +273,6 @@ static int tpm_add_char_device(struct tpm_chip *chip)
243273
"unable to cdev_add() %s, major %d, minor %d, err=%d\n",
244274
dev_name(&chip->dev), MAJOR(chip->dev.devt),
245275
MINOR(chip->dev.devt), rc);
246-
247276
return rc;
248277
}
249278

@@ -258,6 +287,29 @@ static int tpm_add_char_device(struct tpm_chip *chip)
258287
return rc;
259288
}
260289

290+
if (chip->flags & TPM_CHIP_FLAG_TPM2)
291+
rc = cdev_add(&chip->cdevs, chip->devs.devt, 1);
292+
if (rc) {
293+
dev_err(&chip->dev,
294+
"unable to cdev_add() %s, major %d, minor %d, err=%d\n",
295+
dev_name(&chip->devs), MAJOR(chip->devs.devt),
296+
MINOR(chip->devs.devt), rc);
297+
tpm_del_char_device(chip, true);
298+
return rc;
299+
}
300+
301+
if (chip->flags & TPM_CHIP_FLAG_TPM2)
302+
rc = device_add(&chip->devs);
303+
if (rc) {
304+
dev_err(&chip->dev,
305+
"unable to device_register() %s, major %d, minor %d, err=%d\n",
306+
dev_name(&chip->devs), MAJOR(chip->devs.devt),
307+
MINOR(chip->devs.devt), rc);
308+
cdev_del(&chip->cdevs);
309+
tpm_del_char_device(chip, true);
310+
return rc;
311+
}
312+
261313
/* Make the chip available. */
262314
mutex_lock(&idr_lock);
263315
idr_replace(&dev_nums_idr, chip, chip->dev_num);
@@ -391,6 +443,10 @@ void tpm_chip_unregister(struct tpm_chip *chip)
391443
{
392444
tpm_del_legacy_sysfs(chip);
393445
tpm_bios_log_teardown(chip);
446+
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
447+
cdev_del(&chip->cdevs);
448+
device_del(&chip->devs);
449+
}
394450
tpm_del_char_device(chip);
395451
}
396452
EXPORT_SYMBOL_GPL(tpm_chip_unregister);

drivers/char/tpm/tpm-interface.c

+11-2
Original file line numberDiff line numberDiff line change
@@ -1262,9 +1262,17 @@ static int __init tpm_init(void)
12621262
return PTR_ERR(tpm_class);
12631263
}
12641264

1265-
rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
1265+
tpmrm_class = class_create(THIS_MODULE, "tpmrm");
1266+
if (IS_ERR(tpmrm_class)) {
1267+
pr_err("couldn't create tpmrm class\n");
1268+
class_destroy(tpm_class);
1269+
return PTR_ERR(tpmrm_class);
1270+
}
1271+
1272+
rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm");
12661273
if (rc < 0) {
12671274
pr_err("tpm: failed to allocate char dev region\n");
1275+
class_destroy(tpmrm_class);
12681276
class_destroy(tpm_class);
12691277
return rc;
12701278
}
@@ -1276,7 +1284,8 @@ static void __exit tpm_exit(void)
12761284
{
12771285
idr_destroy(&dev_nums_idr);
12781286
class_destroy(tpm_class);
1279-
unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
1287+
class_destroy(tpmrm_class);
1288+
unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
12801289
}
12811290

12821291
subsys_initcall(tpm_init);

drivers/char/tpm/tpm.h

+4
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ struct tpm_chip_seqops {
182182

183183
struct tpm_chip {
184184
struct device dev;
185+
struct device devs;
185186
struct cdev cdev;
187+
struct cdev cdevs;
186188

187189
/* A driver callback under ops cannot be run unless ops_sem is held
188190
* (sometimes implicitly, eg for the sysfs code). ops becomes null
@@ -510,8 +512,10 @@ static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
510512
}
511513

512514
extern struct class *tpm_class;
515+
extern struct class *tpmrm_class;
513516
extern dev_t tpm_devt;
514517
extern const struct file_operations tpm_fops;
518+
extern const struct file_operations tpmrm_fops;
515519
extern struct idr dev_nums_idr;
516520

517521
enum tpm_transmit_flags {

drivers/char/tpm/tpmrm-dev.c

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (C) 2017 James.Bottomley@HansenPartnership.com
3+
*
4+
* GPLv2
5+
*/
6+
#include <linux/slab.h>
7+
#include "tpm-dev.h"
8+
9+
struct tpmrm_priv {
10+
struct file_priv priv;
11+
struct tpm_space space;
12+
};
13+
14+
static int tpmrm_open(struct inode *inode, struct file *file)
15+
{
16+
struct tpm_chip *chip;
17+
struct tpmrm_priv *priv;
18+
int rc;
19+
20+
chip = container_of(inode->i_cdev, struct tpm_chip, cdevs);
21+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
22+
if (priv == NULL)
23+
return -ENOMEM;
24+
25+
rc = tpm2_init_space(&priv->space);
26+
if (rc) {
27+
kfree(priv);
28+
return -ENOMEM;
29+
}
30+
31+
tpm_common_open(file, chip, &priv->priv);
32+
33+
return 0;
34+
}
35+
36+
static int tpmrm_release(struct inode *inode, struct file *file)
37+
{
38+
struct file_priv *fpriv = file->private_data;
39+
struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv);
40+
41+
tpm_common_release(file, fpriv);
42+
tpm2_del_space(&priv->space);
43+
kfree(priv);
44+
45+
return 0;
46+
}
47+
48+
ssize_t tpmrm_write(struct file *file, const char __user *buf,
49+
size_t size, loff_t *off)
50+
{
51+
struct file_priv *fpriv = file->private_data;
52+
struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv);
53+
54+
return tpm_common_write(file, buf, size, off, &priv->space);
55+
}
56+
57+
const struct file_operations tpmrm_fops = {
58+
.owner = THIS_MODULE,
59+
.llseek = no_llseek,
60+
.open = tpmrm_open,
61+
.read = tpm_common_read,
62+
.write = tpmrm_write,
63+
.release = tpmrm_release,
64+
};
65+

0 commit comments

Comments
 (0)