Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | #include <sys/sysctl.h> #include <darwintest.h> #include <perfdata/perfdata.h> #include "test_utils.h" #define KERNEL_PRIVATE 1 #include <sptm/sptm_xnu.h> /** * @file * @brief Perfdata tests for SPTM I/O ranges. * * This test collects perfdata for the various SPTM I/O ranges exposed by * kernel sysctls. The collected data includes the index, address, length, * and frame type for each I/O range. * * This data is useful for security review and regression testing allowing * for tracking changes to these I/O ranges across different builds and * hardware platforms. */ T_GLOBAL_META( T_META_NAMESPACE("xnu.arm"), T_META_RADAR_COMPONENT_NAME("xnu"), T_META_RADAR_COMPONENT_VERSION("arm"), T_META_OWNER("sai_ranjan"), T_META_ASROOT(true), T_META_TAG_PERF); /** * @brief Helper function to run a perfdata collection test for a given set of * SPTM I/O range sysctls. * * @param count_sysctl The name of the sysctl that provides the count of ranges. * @param range_sysctl The name of the sysctl that provides a range by index. * @param pd_name The name to use for the perfdata file. * @param metric_name The name to use for the primary metric in the perfdata file. * @param log_prefix A short string to use in log messages (e.g., "Allowed", "Pmap"). */ static void run_sptm_perfdata_test(const char *count_sysctl, const char *range_sysctl, const char *pd_name, const char *metric_name, const char *log_prefix) { int ret; unsigned int count = 0; size_t size = sizeof(count); ret = sysctlbyname(count_sysctl, &count, &size, NULL, 0); if (ret != 0) { T_SKIP("Sysctl '%s' not found", count_sysctl); } T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname %s", count_sysctl); T_LOG("Found %u SPTM %s I/O ranges", count, log_prefix); if (count == 0) { T_SKIP("No SPTM %s I/O ranges to report", log_prefix); } char pd_path[PATH_MAX] = ""; pdwriter_t writer = pdwriter_open_tmp("xnu", pd_name, 0, 0, pd_path, sizeof(pd_path)); T_ASSERT_NOTNULL(writer, "pdwriter_open_tmp"); char addr_buf[32]; for (unsigned int i = 0; i < count; i++) { sptm_io_range_t io_range; size_t range_size = sizeof(io_range); unsigned int index = i; ret = sysctlbyname(range_sysctl, &io_range, &range_size, &index, sizeof(index)); if (ret != 0) { T_FAIL("sysctlbyname %s for index %u failed", range_sysctl, i); } T_LOG("SPTM %s IO Range %u: addr=0x%llx, len=0x%zx, frame_type=%u", log_prefix, i, io_range.addr, io_range.len, io_range.type); /* Record the address as the primary metric. */ pdwriter_new_value(writer, metric_name, PDUNIT_CUSTOM(phys_addr), (double)io_range.addr); /* Attach the other data as variables to this metric. */ snprintf(addr_buf, sizeof(addr_buf), "0x%llx", io_range.addr); pdwriter_record_variable_str(writer, "addr", addr_buf); pdwriter_record_label_dbl(writer, "index", (double)i); pdwriter_record_variable_dbl(writer, "len", (double)io_range.len); pdwriter_record_variable_dbl(writer, "frame_type", (double)io_range.type); } pdwriter_close(writer); T_PASS("Successfully collected and wrote %u %s I/O ranges to %s", count, log_prefix, pd_path); } T_DECL(sptm_allowed_io_ranges_perfdata, "Collect SPTM Allowed I/O ranges into perfdata format", T_META_REQUIRES_SYSCTL_EQ("kern.page_protection_type", 2), T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), XNU_T_META_SOC_SPECIFIC, T_META_TAG_VM_NOT_ELIGIBLE) { run_sptm_perfdata_test("kern.sptm_allowed_io_ranges_count", "kern.sptm_allowed_io_ranges", "sptm_allowed_io_ranges", "allowed_io_range_addr", "Allowed"); } T_DECL(sptm_pmap_io_ranges_perfdata, "Collect SPTM Pmap I/O ranges into perfdata format", T_META_REQUIRES_SYSCTL_EQ("kern.page_protection_type", 2), T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), XNU_T_META_SOC_SPECIFIC, T_META_TAG_VM_NOT_ELIGIBLE) { run_sptm_perfdata_test("kern.sptm_pmap_io_ranges_count", "kern.sptm_pmap_io_ranges", "sptm_pmap_io_ranges", "pmap_io_range_addr", "Pmap"); } T_DECL(sptm_io_ranges_perfdata, "Collect SPTM Generic I/O ranges into perfdata format", T_META_REQUIRES_SYSCTL_EQ("kern.page_protection_type", 2), T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), XNU_T_META_SOC_SPECIFIC, T_META_TAG_VM_NOT_ELIGIBLE) { run_sptm_perfdata_test("kern.sptm_io_ranges_count", "kern.sptm_io_ranges", "sptm_io_ranges", "io_range_addr", "Generic"); } |