Skip to content

Commit ad39083

Browse files
author
Denis Aleksandrov
committed
tpm: Prevent local DOS via tpm/tpm0/ppi/*operations
JIRA: https://issues.redhat.com/browse/RHEL-62964 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> (cherry picked from commit a29ad21) Signed-off-by: Denis Aleksandrov <daleksan@redhat.com>
1 parent c3d5212 commit ad39083

File tree

1 file changed

+68
-25
lines changed

1 file changed

+68
-25
lines changed

drivers/char/tpm/tpm_ppi.c

Lines changed: 68 additions & 25 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;
@@ -279,66 +293,95 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
279293
return status;
280294
}
281295

282-
static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
283-
u32 end)
296+
static ssize_t cache_ppi_operations(acpi_handle dev_handle, char *buf)
284297
{
285298
int i;
286299
u32 ret;
287-
char *str = buf;
300+
int len = 0;
288301
union acpi_object *obj, tmp;
289302
union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
290303

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

303308
tmp.integer.type = ACPI_TYPE_INTEGER;
304-
for (i = start; i <= end; i++) {
309+
for (i = 0; i <= PPI_VS_REQ_END; i++) {
305310
tmp.integer.value = i;
306311
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
307312
ACPI_TYPE_INTEGER, &argv,
308313
TPM_PPI_REVISION_ID_1);
309-
if (!obj) {
314+
if (!obj)
310315
return -ENOMEM;
311-
} else {
312-
ret = obj->integer.value;
313-
ACPI_FREE(obj);
314-
}
315316

316-
if (ret > 0 && ret < ARRAY_SIZE(info))
317-
str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n",
318-
i, ret, info[ret]);
317+
ret = obj->integer.value;
318+
ppi_operations_cache[i] = ret;
319+
ACPI_FREE(obj);
319320
}
320321

321-
return str - buf;
322+
return len;
322323
}
323324

324325
static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
325326
struct device_attribute *attr,
326327
char *buf)
327328
{
328329
struct tpm_chip *chip = to_tpm_chip(dev);
330+
ssize_t len = 0;
331+
u32 ret;
332+
int i;
333+
334+
mutex_lock(&tpm_ppi_lock);
335+
if (!ppi_cache_populated) {
336+
len = cache_ppi_operations(chip->acpi_dev_handle, buf);
337+
if (len < 0) {
338+
mutex_unlock(&tpm_ppi_lock);
339+
return len;
340+
}
341+
342+
ppi_cache_populated = true;
343+
}
329344

330-
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
331-
PPI_TPM_REQ_MAX);
345+
for (i = 0; i <= PPI_TPM_REQ_MAX; i++) {
346+
ret = ppi_operations_cache[i];
347+
if (ret >= 0 && ret < ARRAY_SIZE(tpm_ppi_info))
348+
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
349+
i, ret, tpm_ppi_info[ret]);
350+
}
351+
mutex_unlock(&tpm_ppi_lock);
352+
353+
return len;
332354
}
333355

334356
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
335357
struct device_attribute *attr,
336358
char *buf)
337359
{
338360
struct tpm_chip *chip = to_tpm_chip(dev);
361+
ssize_t len = 0;
362+
u32 ret;
363+
int i;
364+
365+
mutex_lock(&tpm_ppi_lock);
366+
if (!ppi_cache_populated) {
367+
len = cache_ppi_operations(chip->acpi_dev_handle, buf);
368+
if (len < 0) {
369+
mutex_unlock(&tpm_ppi_lock);
370+
return len;
371+
}
372+
373+
ppi_cache_populated = true;
374+
}
375+
376+
for (i = PPI_VS_REQ_START; i <= PPI_VS_REQ_END; i++) {
377+
ret = ppi_operations_cache[i];
378+
if (ret >= 0 && ret < ARRAY_SIZE(tpm_ppi_info))
379+
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
380+
i, ret, tpm_ppi_info[ret]);
381+
}
382+
mutex_unlock(&tpm_ppi_lock);
339383

340-
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
341-
PPI_VS_REQ_END);
384+
return len;
342385
}
343386

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

0 commit comments

Comments
 (0)