Skip to content

Commit db66c6f

Browse files
Nick Rosbrookbrendank310
authored andcommitted
shim: implement KVM_GET_MSR_INDEX_LIST
Implment support in the shim for the KVM_GET_MSR_INDEX_LIST ioctl. Expand functionality in the mv_pp_op_msr_get_supported_list mock to support unit tests, and also add an intergratio test. Signed-off-by: Nick Rosbrook <[email protected]>
1 parent 0ca0d33 commit db66c6f

File tree

11 files changed

+455
-25
lines changed

11 files changed

+455
-25
lines changed

hypercall/mocks/mv_hypercall.h

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ extern "C"
5454

5555
#define GARBAGE ((uint64_t)0xFFFFFFFFFFFFFFFFU)
5656

57+
/** tells the list APIs to add an unknown entry */
58+
#define MV_STATUS_FAILURE_INC_NUM_ENTRIES ((mv_status_t)0x1234567800000001U)
59+
/** tells the list APIs to add an unknown entry */
60+
#define MV_STATUS_FAILURE_ADD_UNKNOWN ((mv_status_t)0x1234567800000002U)
61+
/** tells the list APIs to corrupt the number of entries */
62+
#define MV_STATUS_FAILURE_CORRUPT_NUM_ENTRIES ((mv_status_t)0x1234567800000003U)
63+
/** tells the list APIs to set reg1 in rdl */
64+
#define MV_STATUS_FAILURE_SET_RDL_REG1 ((mv_status_t)0x1234567800000004U)
65+
5766
/** @brief stores a value that can be returned by certain hypercalls */
5867
extern uint64_t g_mut_val;
5968

@@ -272,13 +281,42 @@ extern "C"
272281
NODISCARD static inline mv_status_t
273282
mv_pp_op_msr_get_supported_list(uint64_t const hndl) NOEXCEPT
274283
{
284+
uint64_t mut_i;
285+
275286
#ifdef __cplusplus
276287
bsl::expects(MV_INVALID_HANDLE != hndl);
277288
bsl::expects(hndl > ((uint64_t)0));
278289
#else
279290
platform_expects(MV_INVALID_HANDLE != hndl);
280291
platform_expects(hndl > ((uint64_t)0));
281292
#endif
293+
struct mv_rdl_t *const pmut_rdl = (struct mv_rdl_t *)g_mut_shared_pages[0];
294+
295+
#ifdef __cplusplus
296+
bsl::expects(nullptr != pmut_rdl);
297+
bsl::expects(pmut_rdl->num_entries < MV_RDL_MAX_ENTRIES);
298+
#else
299+
platform_expects(NULL != pmut_rdl);
300+
platform_expects(pmut_rdl->num_entries < MV_RDL_MAX_ENTRIES);
301+
#endif
302+
if (MV_STATUS_FAILURE_CORRUPT_NUM_ENTRIES == g_mut_mv_pp_op_msr_get_supported_list) {
303+
pmut_rdl->num_entries = GARBAGE;
304+
return MV_STATUS_SUCCESS;
305+
}
306+
307+
if (MV_STATUS_FAILURE_SET_RDL_REG1 == g_mut_mv_pp_op_msr_get_supported_list) {
308+
g_mut_mv_pp_op_msr_get_supported_list = MV_STATUS_SUCCESS;
309+
pmut_rdl->reg1 = ((uint64_t)1);
310+
}
311+
else {
312+
pmut_rdl->reg1 = ((uint64_t)0);
313+
}
314+
315+
pmut_rdl->num_entries = g_mut_val;
316+
for (mut_i = ((uint64_t)0); mut_i < pmut_rdl->num_entries; ++mut_i) {
317+
pmut_rdl->entries[mut_i].reg = g_mut_val;
318+
pmut_rdl->entries[mut_i].val = ((uint64_t)1);
319+
}
282320

283321
return g_mut_mv_pp_op_msr_get_supported_list;
284322
}
@@ -654,16 +692,9 @@ extern "C"
654692
return g_mut_mv_vp_op_vpid;
655693
}
656694

657-
/* -------------------------------------------------------------------------- */
658-
/* mv_vs_ops */
659-
/* -------------------------------------------------------------------------- */
660-
661-
/** tells the list APIs to add an unknown entry */
662-
#define MV_STATUS_FAILURE_INC_NUM_ENTRIES ((mv_status_t)0x1234567800000001U)
663-
/** tells the list APIs to add an unknown entry */
664-
#define MV_STATUS_FAILURE_ADD_UNKNOWN ((mv_status_t)0x1234567800000002U)
665-
/** tells the list APIs to corrupt the number of entries */
666-
#define MV_STATUS_FAILURE_CORRUPT_NUM_ENTRIES ((mv_status_t)0x1234567800000003U)
695+
/* -------------------------------------------------------------------------- */
696+
/* mv_vs_ops */
697+
/* -------------------------------------------------------------------------- */
667698

668699
/** @brief stores the return value for mv_vs_op_create_vs */
669700
extern uint16_t g_mut_mv_vs_op_create_vs;

hypercall/tests/mocks/mv_hypercall.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,10 @@ namespace shim
207207
bsl::ut_given{} = [&]() noexcept {
208208
constexpr auto hypercall{&mv_pp_op_msr_get_supported_list};
209209
constexpr auto expected{42_u64};
210+
mv_rdl_t mut_rdl{};
210211
bsl::ut_when{} = [&]() noexcept {
212+
mut_rdl.num_entries = bsl::safe_u64::magic_2().get();
213+
g_mut_shared_pages[0] = &mut_rdl;
211214
g_mut_mv_pp_op_msr_get_supported_list = expected.get();
212215
bsl::ut_then{} = [&]() noexcept {
213216
bsl::ut_check(expected == hypercall(hndl));

shim/include/kvm_msr_list.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ extern "C"
4444
*/
4545
struct kvm_msr_list
4646
{
47-
/** @brief replace me with contents from KVM API */
48-
int32_t dummy;
47+
/** @brief number of msrs in the indices array */
48+
uint32_t nmsrs;
49+
50+
/** @brief array containing the indices of supported MSRs */
51+
uint32_t *indices;
4952
};
5053

5154
#pragma pack(pop)

shim/include/kvm_msr_list.hpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @copyright
3+
* Copyright (C) 2021 Assured Information Security, Inc.
4+
*
5+
* @copyright
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* @copyright
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* @copyright
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
*/
26+
27+
#ifndef KVM_MSR_LIST_HPP
28+
#define KVM_MSR_LIST_HPP
29+
30+
#include <bsl/cstdint.hpp>
31+
32+
namespace shim
33+
{
34+
#pragma pack(push, 1)
35+
36+
/**
37+
* @struct kvm_msr_list
38+
*
39+
* <!-- description -->
40+
* @brief see /include/uapi/linux/kvm.h in Linux for more details.
41+
*/
42+
struct kvm_msr_list final
43+
{
44+
/** @brief number of msrs in the indices array */
45+
bsl::uint32 nmsrs;
46+
47+
/** @brief array containing the indices of supported MSRs */
48+
bsl::uint32 *indices;
49+
};
50+
}
51+
52+
#pragma pack(pop)
53+
54+
#endif

shim/integration/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ microv_add_shim_integration(kvm_check_extension HEADERS)
4545
microv_add_shim_integration(kvm_get_mp_state HEADERS)
4646
microv_add_shim_integration(kvm_set_mp_state HEADERS)
4747
microv_add_shim_integration(kvm_get_tsc_khz HEADERS)
48+
microv_add_shim_integration(kvm_get_msr_index_list HEADERS)
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/// @copyright
2+
/// Copyright (C) 2020 Assured Information Security, Inc.
3+
///
4+
/// @copyright
5+
/// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
/// of this software and associated documentation files (the "Software"), to deal
7+
/// in the Software without restriction, including without limitation the rights
8+
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
/// copies of the Software, and to permit persons to whom the Software is
10+
/// furnished to do so, subject to the following conditions:
11+
///
12+
/// @copyright
13+
/// The above copyright notice and this permission notice shall be included in
14+
/// all copies or substantial portions of the Software.
15+
///
16+
/// @copyright
17+
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
/// SOFTWARE.
24+
25+
#include <integration_utils.hpp>
26+
#include <ioctl_t.hpp>
27+
#include <kvm_msr_list.hpp>
28+
#include <shim_platform_interface.hpp>
29+
30+
#include <bsl/array.hpp>
31+
#include <bsl/convert.hpp>
32+
#include <bsl/enable_color.hpp>
33+
#include <bsl/exit_code.hpp>
34+
#include <bsl/safe_idx.hpp>
35+
#include <bsl/safe_integral.hpp>
36+
37+
/// <!-- description -->
38+
/// @brief Provides the main entry point for this application.
39+
///
40+
/// <!-- inputs/outputs -->
41+
/// @return bsl::exit_success on success, bsl::exit_failure otherwise.
42+
///
43+
[[nodiscard]] auto
44+
main() noexcept -> bsl::exit_code
45+
{
46+
shim::kvm_msr_list mut_msr_list{};
47+
constexpr auto star_val{0xC0000081_u32};
48+
constexpr auto pat_val{0x00000277_u32};
49+
constexpr auto apic_base_val{0x0000001B_u32};
50+
constexpr auto init_nmsrs{0x10_u32};
51+
52+
bsl::enable_color();
53+
integration::ioctl_t mut_system_ctl{shim::DEVICE_NAME};
54+
bsl::array<bsl::uint32, bsl::uintmx(init_nmsrs.get())> mut_msr_indices{};
55+
56+
// nmsrs is too big
57+
{
58+
mut_msr_list.nmsrs = HYPERVISOR_PAGE_SIZE.get();
59+
mut_msr_list.nmsrs++;
60+
mut_msr_list.indices = mut_msr_indices.front_if();
61+
62+
integration::verify(
63+
mut_system_ctl.write(shim::KVM_GET_MSR_INDEX_LIST, &mut_msr_list).is_neg());
64+
}
65+
66+
{
67+
mut_msr_list.nmsrs = init_nmsrs.get();
68+
mut_msr_list.indices = mut_msr_indices.front_if();
69+
70+
integration::verify(
71+
mut_system_ctl.write(shim::KVM_GET_MSR_INDEX_LIST, &mut_msr_list).is_zero());
72+
73+
auto mut_nmsrs{bsl::to_u32(mut_msr_list.nmsrs)};
74+
integration::verify(mut_nmsrs > bsl::safe_u32::magic_0());
75+
}
76+
77+
// Valid registers should be present
78+
{
79+
bool mut_found_star{false};
80+
bool mut_found_pat{false};
81+
bool mut_found_apic_base{false};
82+
auto mut_nmsrs{bsl::to_idx(mut_msr_list.nmsrs)};
83+
84+
for (bsl::safe_idx mut_i{}; mut_i < mut_nmsrs; ++mut_i) {
85+
if (star_val == mut_msr_list.indices[mut_i.get()]) {
86+
mut_found_star = true;
87+
}
88+
else if (pat_val == mut_msr_list.indices[mut_i.get()]) {
89+
mut_found_pat = true;
90+
}
91+
else if (apic_base_val == mut_msr_list.indices[mut_i.get()]) {
92+
mut_found_apic_base = true;
93+
}
94+
}
95+
96+
integration::verify(mut_found_star);
97+
integration::verify(mut_found_pat);
98+
integration::verify(mut_found_apic_base);
99+
}
100+
101+
// Try a bunch of times
102+
{
103+
constexpr auto num_loops{0x1000_umx};
104+
for (bsl::safe_idx mut_i{}; mut_i < num_loops; ++mut_i) {
105+
integration::verify(
106+
mut_system_ctl.write(shim::KVM_GET_MSR_INDEX_LIST, &mut_msr_list).is_zero());
107+
}
108+
}
109+
110+
return bsl::exit_success;
111+
}

shim/linux/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ ifneq ($(KERNELRELEASE),)
170170
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_mp_state_set_impl.o
171171
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_get_impl.o
172172
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_get_list_impl.o
173+
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_pp_op_msr_get_supported_list_impl.o
173174
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_set_impl.o
174175
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_set_list_impl.o
175176
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_fpu_get_all_impl.o
@@ -229,6 +230,7 @@ ifneq ($(KERNELRELEASE),)
229230
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_mp_state_set_impl.o
230231
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_get_impl.o
231232
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_get_list_impl.o
233+
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_pp_op_msr_get_supported_list_impl.o
232234
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_set_impl.o
233235
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_set_list_impl.o
234236
$(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_fpu_get_all_impl.o

shim/linux/include/platform_interface/shim_platform_interface.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <asm/ioctl.h>
3131
#include <kvm_fpu.hpp>
3232
#include <kvm_mp_state.hpp>
33+
#include <kvm_msr_list.hpp>
3334
#include <kvm_regs.hpp>
3435
#include <kvm_sregs.hpp>
3536
#include <kvm_userspace_memory_region.hpp>
@@ -61,7 +62,6 @@
6162
// #include <kvm_lapic_state.hpp>
6263
// #include <kvm_mp_state.hpp>
6364
// #include <kvm_msi.hpp>
64-
// #include <kvm_msr_list.hpp>
6565
// #include <kvm_msrs.hpp>
6666
// #include <kvm_nested_state.hpp>
6767
// #include <kvm_one_reg.hpp>
@@ -93,8 +93,9 @@ namespace shim
9393
constexpr bsl::safe_umx KVM_GET_API_VERSION{static_cast<bsl::uintmx>(_IO(SHIMIO.get(), 0x00))};
9494
/// @brief defines KVM's KVM_CREATE_VM IOCTL
9595
constexpr bsl::safe_umx KVM_CREATE_VM{static_cast<bsl::uintmx>(_IO(SHIMIO.get(), 0x01))};
96-
// /// @brief defines KVM's KVM_GET_MSR_INDEX_LIST IOCTL
97-
// constexpr bsl::safe_umx KVM_GET_MSR_INDEX_LIST{static_cast<bsl::uintmx>(_IOWR(SHIMIO.get(), 0x02, struct kvm_msr_list))};
96+
/// @brief defines KVM's KVM_GET_MSR_INDEX_LIST IOCTL
97+
constexpr bsl::safe_umx KVM_GET_MSR_INDEX_LIST{
98+
static_cast<bsl::uintmx>(_IOWR(SHIMIO.get(), 0x02, struct kvm_msr_list))};
9899
// /// @brief defines KVM's KVM_GET_MSR_FEATURE_INDEX_LIST IOCTL
99100
// constexpr bsl::safe_umx KVM_GET_MSR_FEATURE_INDEX_LIST{static_cast<bsl::uintmx>(_IOWR(SHIMIO.get(), 0x0a, struct kvm_msr_list))};
100101
/// @brief defines KVM's KVM_CHECK_EXTENSION IOCTL

shim/linux/src/entry.c

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <handle_system_kvm_create_vm.h>
3232
#include <handle_system_kvm_destroy_vm.h>
3333
#include <handle_system_kvm_get_api_version.h>
34+
#include <handle_system_kvm_get_msr_index_list.h>
3435
#include <handle_system_kvm_get_vcpu_mmap_size.h>
3536
#include <handle_vcpu_kvm_get_fpu.h>
3637
#include <handle_vcpu_kvm_get_mp_state.h>
@@ -228,10 +229,58 @@ dispatch_system_kvm_get_msr_feature_index_list(
228229
}
229230

230231
static long
231-
dispatch_system_kvm_get_msr_index_list(struct kvm_msr_list *const ioctl_args)
232+
dispatch_system_kvm_get_msr_index_list(
233+
struct kvm_msr_list __user *const user_args)
232234
{
233-
(void)ioctl_args;
234-
return -EINVAL;
235+
struct kvm_msr_list mut_args;
236+
uint32_t __user *pmut_mut_user_indices;
237+
int64_t mut_ret;
238+
uint64_t mut_alloc_size;
239+
240+
if (platform_copy_from_user(&mut_args, user_args, sizeof(mut_args))) {
241+
bferror("platform_copy_from_user failed");
242+
return -EINVAL;
243+
}
244+
245+
mut_alloc_size = mut_args.nmsrs * sizeof(*mut_args.indices);
246+
if (mut_alloc_size > HYPERVISOR_PAGE_SIZE) {
247+
bferror("requested nmsrs too big");
248+
return -ENOMEM;
249+
}
250+
251+
pmut_mut_user_indices = mut_args.indices;
252+
mut_args.indices = vzalloc(mut_alloc_size);
253+
254+
if (NULL == mut_args.indices) {
255+
bferror("vzalloc failed");
256+
return -ENOMEM;
257+
}
258+
259+
mut_ret = -EINVAL;
260+
if (handle_system_kvm_get_msr_index_list(&mut_args)) {
261+
bferror("handle_system_kvm_get_msr_index_list failed");
262+
goto out;
263+
}
264+
265+
if (platform_copy_to_user(user_args, &mut_args, sizeof(mut_args.nmsrs))) {
266+
bferror("platform_copy_to_user nmsrs failed");
267+
goto out;
268+
}
269+
270+
if (platform_copy_to_user(
271+
pmut_mut_user_indices,
272+
mut_args.indices,
273+
mut_args.nmsrs * sizeof(*mut_args.indices))) {
274+
bferror("platform_copy_to_user indices failed");
275+
goto out;
276+
}
277+
278+
mut_ret = 0;
279+
out:
280+
if (mut_args.indices)
281+
vfree(mut_args.indices);
282+
283+
return mut_ret;
235284
}
236285

237286
static long
@@ -322,7 +371,7 @@ dev_unlocked_ioctl_system(
322371

323372
case KVM_GET_MSR_INDEX_LIST: {
324373
return dispatch_system_kvm_get_msr_index_list(
325-
(struct kvm_msr_list *)ioctl_args);
374+
(struct kvm_msr_list __user *)ioctl_args);
326375
}
327376

328377
case KVM_GET_MSRS: {

0 commit comments

Comments
 (0)