1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2023 - Google Inc
4  * Author: Mostafa Saleh <smostafa@google.com>
5  * Simple module for pKVM SMC filtering.
6  */
7 
8 #include <asm/kvm_pkvm_module.h>
9 #include <linux/arm-smccc.h>
10 #include <linux/bsearch.h>
11 
12 #include "events.h"
13 #define HYP_EVENT_FILE ../../../../drivers/misc/pkvm-smc/pkvm/events.h
14 #include <nvhe/define_events.h>
15 
16 const struct pkvm_module_ops *pkvm_ops;
17 bool permissive;
18 
19 #ifdef CONFIG_TRACING
20 extern char __hyp_event_ids_start[];
21 extern char __hyp_event_ids_end[];
22 
tracing_reserve_entry(unsigned long length)23 void *tracing_reserve_entry(unsigned long length)
24 {
25 	return pkvm_ops->tracing_reserve_entry(length);
26 }
27 
tracing_commit_entry(void)28 void tracing_commit_entry(void)
29 {
30 	pkvm_ops->tracing_commit_entry();
31 }
32 #endif
33 
34 struct pkvm_smc_filter {
35 	u64 smc_id;
36 	bool (*cb)(struct user_pt_regs *regs); /* Forward unconditionally if NULL. */
37 };
38 
deny_smc(struct user_pt_regs * regs)39 static bool deny_smc(struct user_pt_regs *regs)
40 {
41 	trace_filtered_smc(regs->regs[0]);
42 
43 	if (permissive)
44 		return false;
45 
46 	regs->regs[0] = SMCCC_RET_NOT_SUPPORTED;
47 	return true;
48 }
49 
50 /*
51  * Must be sorted.
52  * Allow SMCCCs that are known to be safe.
53  * PSCI and FFA are already handled by the hypervisor.
54  */
55 const struct pkvm_smc_filter allow_list[] = {
56 	/* Trusted OS Calls: Trusty Trusted OS (Yielding) */
57 	{0x32000014, NULL,}, /* SMC_SC_VIRTIO_GET_DESCR. */
58 	{0x32000015, NULL,}, /* SMC_SC_VIRTIO_START. */
59 	{0x32000016, NULL,}, /* SMC_SC_VIRTIO_STOP. */
60 	{0x32000017, NULL,}, /* SMC_SC_VDEV_RESET. */
61 	{0x32000018, NULL,}, /* SMC_SC_VDEV_KICK_VQ. */
62 	{0x32000019, NULL,}, /* SMC_NC_VDEV_KICK_VQ. */
63 	{0x3200001E, NULL,}, /* SMC_SC_CREATE_QL_TIPC_DEV. */
64 	{0x3200001F, NULL,}, /* SMC_SC_SHUTDOWN_QL_TIPC_DEV. */
65 	{0x32000020, NULL,}, /* SMC_SC_HANDLE_QL_TIPC_DEV_CMD. */
66 	{0x32000021, NULL,}, /* SMC_FC_HANDLE_QL_TIPC_DEV_CMD. */
67 
68 	/* Trusted OS Calls: Trusty Secure Monitor (Yielding) */
69 	{0x3C000000, NULL,}, /* SMC_SC_RESTART_LAST. */
70 	{0x3C000001, NULL,}, /* SMC_SC_LOCKED_NOP. */
71 	{0x3C000002, NULL,}, /* SMC_SC_RESTART_FIQ. */
72 	{0x3C000003, NULL,}, /* SMC_SC_NOP. */
73 	{0x3C000004, NULL,}, /* SMC_SC_SCHED_SHARE_REGISTER. */
74 	{0x3C000005, NULL,}, /* SMC_SC_SCHED_SHARE_UNREGISTER. */
75 
76 	/* Arm Architecture Calls. */
77 	{0x80000000, NULL}, /* SMCCC_VERSION. */
78 	{0x80000001, NULL}, /* SMCCC_ARCH_FEATURES. */
79 	{0x80000002, NULL}, /* SMCCC_ARCH_SOC_ID. */
80 
81 	/* Standard Secure services: TRNG */
82 	{0x84000050, NULL,}, /* TRNG_VERSION. */
83 	{0x84000051, NULL,}, /* TRNG_FEATURES. */
84 	{0x84000052, NULL,}, /* TRNG_GET_UUID. */
85 	{0x84000053, NULL,}, /* TRNG_RND. */
86 
87 	/* Trusted OS Calls: Trusty Secure Monitor (Fast) */
88 	{0xBC000001, NULL,}, /* SMC_FC_FIQ_EXIT. */
89 	{0xBC000002, NULL,}, /* SMC_FC_REQUEST_FIQ. */
90 	{0xBC000003, NULL,}, /* SMC_FC_GET_NEXT_IRQ. */
91 	{0xBC000007, NULL,}, /* SMC_FC_CPU_SUSPEND. */
92 	{0xBC000008, NULL,}, /* SMC_FC_CPU_RESUME. */
93 	{0xBC000009, NULL,}, /* SMC_FC_AARCH_SWITCH. */
94 	{0xBC00000A, NULL,}, /* SMC_FC_GET_VERSION_STR. */
95 	{0xBC00000B, NULL,}, /* SMC_FC_API_VERSION. */
96 	{0xBC00000C, NULL,}, /* SMC_FC_FIQ_RESUME. */
97 	{0xBC00000D, NULL,}, /* SMC_FC_GET_SMP_MAX_CPUS. */
98 };
99 
match_smc(const void * key,const void * elt)100 static inline int match_smc(const void *key, const void *elt)
101 {
102 	u64 smc_id = ((struct pkvm_smc_filter *)key)->smc_id;
103 	u64 cur_id = ((struct pkvm_smc_filter *)elt)->smc_id;
104 
105 	return smc_id - cur_id;
106 }
107 
108 /*
109  * Block all by default.
110  * return false will allow the SMC to be forwarded.
111  */
filter_smc(struct user_pt_regs * regs)112 bool filter_smc(struct user_pt_regs *regs)
113 {
114 	u64 smc_id = regs->regs[0];
115 	/*
116 	 * Ignore bits that doesn't change the functionality:
117 	 * Bit[30]: 32/64 bit convention
118 	 * Bit[16]: SVE hint
119 	 */
120 	u64 mask = ~(ARM_SMCCC_1_3_SVE_HINT | BIT(ARM_SMCCC_CALL_CONV_SHIFT));
121 	struct pkvm_smc_filter pval = {smc_id & mask, NULL};
122 	struct pkvm_smc_filter *entry;
123 
124 	/* alternatively, we can do 2 level binary search or switch case by service. */
125 	entry = (struct pkvm_smc_filter *)__inline_bsearch((void *)&pval, allow_list,
126 							   ARRAY_SIZE(allow_list),
127 							   sizeof(allow_list[0]),
128 							   match_smc);
129 	if (!entry)
130 		return deny_smc(regs);
131 
132 	return entry->cb ? entry->cb(regs) : false;
133 }
134 
pkvm_smc_filter_hyp_init(const struct pkvm_module_ops * ops)135 int pkvm_smc_filter_hyp_init(const struct pkvm_module_ops *ops)
136 {
137 	pkvm_ops = ops;
138 	return ops->register_host_smc_handler(filter_smc);
139 }
140