SHA256
8
0
forked from pool/librtas
Files
librtas/0009-librtas-Use-kernel-interface-when-available-for-ibm-.patch

256 lines
7.4 KiB
Diff
Raw Permalink Normal View History

From edd705db27f14c393618ddd68c1b41c43985726a Mon Sep 17 00:00:00 2001
From: Haren Myneni <haren@linux.ibm.com>
Date: Sun, 9 Mar 2025 16:29:15 -0700
Subject: [PATCH 9/9] librtas: Use kernel interface when available for
ibm,physical-attestation
rtas_physical_attestation() uses sys_rtas() to obtain response
buffer for each attestation command. This RTAS function passes
RTAS work area to send input attestation command and to retrieve
response buffer. But the allocation of work area is prohibited
under system lockdown.
This patch adds changes to use new kernel ABI if
/dev/papr-physical-attestation is available. First execution of
rtas_physical_attestation() sets the new API if the device node
is available, otherise execute user space interface.
Open /dev/papr-physical-attestation and obtain FD with
PAPR_PHY_ATTEST_IOC_HANDLE ioctl. The kernel completes the RTAS
sequence in this ioctl and exposes the reponse buffer with this
FD. The user space reads the complete buffer with read() calls.
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
Makefile.am | 3 +-
librtas_src/papr-physical-attestation.h | 31 ++++++
librtas_src/physical-attestation.c | 137 +++++++++++++++++++++++-
3 files changed, 166 insertions(+), 5 deletions(-)
create mode 100644 librtas_src/papr-physical-attestation.h
diff --git a/Makefile.am b/Makefile.am
index e605d98..ccd7ee7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -44,7 +44,8 @@ noinst_HEADERS += \
librtas_src/papr-sysparm.h \
librtas_src/papr-vpd.h \
librtas_src/papr-platform-dump.h \
- librtas_src/papr-indices.h
+ librtas_src/papr-indices.h \
+ librtas_src/papr-physical-attestation.h
# See "Updating library version information" in the libtool manual for
# how to maintain these values. They are *not* tied to the release
diff --git a/librtas_src/papr-physical-attestation.h b/librtas_src/papr-physical-attestation.h
new file mode 100644
index 0000000..32b4bae
--- /dev/null
+++ b/librtas_src/papr-physical-attestation.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_PAPR_PHYSICAL_ATTESTATION_H_
+#define _UAPI_PAPR_PHYSICAL_ATTESTATION_H_
+
+#include <linux/types.h>
+#include <asm/ioctl.h>
+#include "papr-miscdev.h"
+
+#define PAPR_PHYATTEST_MAX_INPUT 4084 /* Max 4K buffer: 4K-12 */
+
+/*
+ * Defined in PAPR 2.13+ 21.6 Attestation Command Structures.
+ * User space pass this struct and the max size should be 4K.
+ */
+struct papr_phy_attest_io_block {
+ __u8 version;
+ __u8 command;
+ __u8 TCG_major_ver;
+ __u8 TCG_minor_ver;
+ __be32 length;
+ __be32 correlator;
+ __u8 payload[PAPR_PHYATTEST_MAX_INPUT];
+};
+
+/*
+ * ioctl for /dev/papr-physical-attestation. Returns a attestation
+ * command fd handle
+ */
+#define PAPR_PHY_ATTEST_IOC_HANDLE _IOW(PAPR_MISCDEV_IOC_ID, 8, struct papr_phy_attest_io_block)
+
+#endif /* _UAPI_PAPR_PHYSICAL_ATTESTATION_H_ */
diff --git a/librtas_src/physical-attestation.c b/librtas_src/physical-attestation.c
index 3e36af3..48108a0 100644
--- a/librtas_src/physical-attestation.c
+++ b/librtas_src/physical-attestation.c
@@ -1,21 +1,27 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
-
+
// Support for accessing ibm,physical-attestation data
// via /dev/papr-phy-attestation or the legacy rtas() syscall.
#include <stdarg.h>
#include <string.h>
#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include "internal.h"
#include "librtas.h"
+#include "papr-physical-attestation.h"
/**
- * rtas_physical_attestation
- * @brief Interface for ibm,physical-attestation rtas call.
+ * ibm,physical-attestation RTAS call from user space
*
* @param workarea input/output work area for rtas call
* @param seq_num sequence number of the rtas call
@@ -23,7 +29,7 @@
* @param work_area_bytes size of work area
* @return 0 on success, !0 on failure
*/
-int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num,
+int phy_attestation_user(char *workarea, int seq_num, int *next_seq_num,
int *work_area_bytes)
{
uint32_t workarea_pa;
@@ -76,3 +82,126 @@ int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num,
return rc ? rc : status;
}
+static bool phy_attest_can_use_chardev(void)
+{
+ struct stat statbuf;
+
+ if (stat("/dev/papr-physical-attestation", &statbuf))
+ return false;
+
+ if (!S_ISCHR(statbuf.st_mode))
+ return false;
+
+ if (close(open("/dev/papr-physical-attestation", O_RDONLY)))
+ return false;
+
+ return true;
+}
+
+#define DEVPATH "/dev/papr-physical-attestation"
+
+static int phy_attest_fd_new(const char *attest_cmd, unsigned int size)
+{
+ const int devfd = open(DEVPATH, O_WRONLY);
+ struct papr_phy_attest_io_block cmd = {};
+ int fd = -1;
+
+ if (devfd < 0)
+ return -1;
+
+ /*
+ * Size of each command struct has to be the buffer size
+ * (WORK_AREA_SIZE - 4K) passed by the user.
+ */
+ if (size != sizeof(struct papr_phy_attest_io_block)) {
+ fd = RTAS_IO_ASSERT;
+ goto close_devfd;
+ }
+
+ memcpy(&cmd, attest_cmd, sizeof(struct papr_phy_attest_io_block));
+ fd = ioctl(devfd, PAPR_PHY_ATTEST_IOC_HANDLE, &cmd);
+
+close_devfd:
+ close(devfd);
+ return fd;
+}
+
+static int
+phy_attestation_kernel(char *workarea, int seq_num, int *next_seq_num,
+ int *work_area_bytes)
+{
+ int size = *work_area_bytes;
+ int fd = (seq_num == 1) ? phy_attest_fd_new(workarea, size)
+ : (int)seq_num;
+
+ /*
+ * Ensure we return a fd > 0 in next_seq_num.
+ */
+ if (fd == 1) {
+ int newfd = dup(fd);
+ close(fd);
+ fd = newfd;
+ }
+
+ if (fd < 0)
+ return -3; /* Synthesize ibm,get-vpd "parameter error" */
+
+ /* Caller provided more data than FW can handle */
+ if (size == 0 || size > WORK_AREA_SIZE) {
+ close(fd);
+ return RTAS_IO_ASSERT;
+ }
+
+
+ int rtas_status = 0;
+ ssize_t res = read(fd, workarea, *work_area_bytes);
+ if (res < 0) {
+ rtas_status = -1; /* Synthesize ibm,get-vpd "hardware error" */
+ close(fd);
+ } else if (res == 0 || res < (ssize_t)size) {
+ rtas_status = 0; /* Done with sequence, no more data */
+ close(fd);
+ if (next_seq_num)
+ *next_seq_num = 1;
+ if (work_area_bytes)
+ *work_area_bytes = res;
+ } else {
+ rtas_status = 1; /* More data available, call again */
+ if (next_seq_num)
+ *next_seq_num = fd;
+ if (work_area_bytes)
+ *work_area_bytes = res;
+ }
+
+ return rtas_status;
+}
+
+static int (*phy_attestation_fn)(char *workarea, int seq_num,
+ int *next_seq_num, int *work_area_bytes);
+
+static void phy_attestation_fn_setup(void)
+{
+ phy_attestation_fn = phy_attest_can_use_chardev() ?
+ phy_attestation_kernel : phy_attestation_user;
+}
+
+/**
+ * rtas_physical_attestation
+ * @brief Interface for ibm,physical-attestation rtas call.
+ *
+ * @param workarea input/output work area for rtas call
+ * @param seq_num sequence number of the rtas call
+ * @param next_seq_num next sequence number
+ * @param work_area_bytes size of input/output work area
+ * @return 0 on success, !0 on failure
+ */
+int rtas_physical_attestation(char *workarea, int seq_num, int *next_seq_num,
+ int *work_area_bytes)
+{
+ static pthread_once_t phy_attestation_fn_once = PTHREAD_ONCE_INIT;
+
+ pthread_once(&phy_attestation_fn_once, phy_attestation_fn_setup);
+
+ return phy_attestation_fn(workarea, seq_num, next_seq_num,
+ work_area_bytes);
+}
--
2.47.1