Skip to content

Commit a29ad21

Browse files
Denis Aleksandrovjarkkojs
authored andcommitted
tpm: Prevent local DOS via tpm/tpm0/ppi/*operations
Reads on tpm/tpm0/ppi/*operations can become very long on misconfigured systems. Reading the TPM is a blocking operation, thus a user could effectively trigger a DOS. Resolve this by caching the results and avoiding the blocking operations after the first read. [ jarkko: fixed atomic sleep: sed -i 's/spin_/mutex_/g' drivers/char/tpm/tpm_ppi.c sed -i 's/DEFINE_SPINLOCK/DEFINE_MUTEX/g' drivers/char/tpm/tpm_ppi.c ] Signed-off-by: Denis Aleksandrov <daleksan@redhat.com> Reported-by: Jan Stancek <jstancek@redhat.com> Closes: https://lore.kernel.org/linux-integrity/20250915210829.6661-1-daleksan@redhat.com/T/#u Suggested-by: Jarkko Sakkinen <jarkko@kernel.org> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de> Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
1 parent 207696b commit a29ad21

File tree

1 file changed

+66
-23
lines changed

1 file changed

+66
-23
lines changed

drivers/char/tpm/tpm_ppi.c

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ static const guid_t tpm_ppi_guid =
3333
GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
3434
0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
3535

36+
static const char * const tpm_ppi_info[] = {
37+
"Not implemented",
38+
"BIOS only",
39+
"Blocked for OS by system firmware",
40+
"User required",
41+
"User not required",
42+
};
43+
44+
/* A spinlock to protect access to the cache from concurrent reads */
45+
static DEFINE_MUTEX(tpm_ppi_lock);
46+
47+
static u32 ppi_operations_cache[PPI_VS_REQ_END + 1];
48+
static bool ppi_cache_populated;
49+
3650
static bool tpm_ppi_req_has_parameter(u64 req)
3751
{
3852
return req == 23;
@@ -277,43 +291,30 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
277291
return status;
278292
}
279293

280-
static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
281-
u32 end)
294+
static ssize_t cache_ppi_operations(acpi_handle dev_handle, char *buf)
282295
{
283296
int i;
284297
u32 ret;
285298
int len = 0;
286299
union acpi_object *obj, tmp;
287300
union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
288301

289-
static char *info[] = {
290-
"Not implemented",
291-
"BIOS only",
292-
"Blocked for OS by BIOS",
293-
"User required",
294-
"User not required",
295-
};
296-
297302
if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1,
298303
1 << TPM_PPI_FN_GETOPR))
299304
return -EPERM;
300305

301306
tmp.integer.type = ACPI_TYPE_INTEGER;
302-
for (i = start; i <= end; i++) {
307+
for (i = 0; i <= PPI_VS_REQ_END; i++) {
303308
tmp.integer.value = i;
304309
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
305310
ACPI_TYPE_INTEGER, &argv,
306311
TPM_PPI_REVISION_ID_1);
307-
if (!obj) {
312+
if (!obj)
308313
return -ENOMEM;
309-
} else {
310-
ret = obj->integer.value;
311-
ACPI_FREE(obj);
312-
}
313314

314-
if (ret > 0 && ret < ARRAY_SIZE(info))
315-
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
316-
i, ret, info[ret]);
315+
ret = obj->integer.value;
316+
ppi_operations_cache[i] = ret;
317+
ACPI_FREE(obj);
317318
}
318319

319320
return len;
@@ -324,19 +325,61 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
324325
char *buf)
325326
{
326327
struct tpm_chip *chip = to_tpm_chip(dev);
328+
ssize_t len = 0;
329+
u32 ret;
330+
int i;
331+
332+
mutex_lock(&tpm_ppi_lock);
333+
if (!ppi_cache_populated) {
334+
len = cache_ppi_operations(chip->acpi_dev_handle, buf);
335+
if (len < 0) {
336+
mutex_unlock(&tpm_ppi_lock);
337+
return len;
338+
}
327339

328-
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
329-
PPI_TPM_REQ_MAX);
340+
ppi_cache_populated = true;
341+
}
342+
343+
for (i = 0; i <= PPI_TPM_REQ_MAX; i++) {
344+
ret = ppi_operations_cache[i];
345+
if (ret >= 0 && ret < ARRAY_SIZE(tpm_ppi_info))
346+
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
347+
i, ret, tpm_ppi_info[ret]);
348+
}
349+
mutex_unlock(&tpm_ppi_lock);
350+
351+
return len;
330352
}
331353

332354
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
333355
struct device_attribute *attr,
334356
char *buf)
335357
{
336358
struct tpm_chip *chip = to_tpm_chip(dev);
359+
ssize_t len = 0;
360+
u32 ret;
361+
int i;
337362

338-
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
339-
PPI_VS_REQ_END);
363+
mutex_lock(&tpm_ppi_lock);
364+
if (!ppi_cache_populated) {
365+
len = cache_ppi_operations(chip->acpi_dev_handle, buf);
366+
if (len < 0) {
367+
mutex_unlock(&tpm_ppi_lock);
368+
return len;
369+
}
370+
371+
ppi_cache_populated = true;
372+
}
373+
374+
for (i = PPI_VS_REQ_START; i <= PPI_VS_REQ_END; i++) {
375+
ret = ppi_operations_cache[i];
376+
if (ret >= 0 && ret < ARRAY_SIZE(tpm_ppi_info))
377+
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
378+
i, ret, tpm_ppi_info[ret]);
379+
}
380+
mutex_unlock(&tpm_ppi_lock);
381+
382+
return len;
340383
}
341384

342385
static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);

0 commit comments

Comments
 (0)