1*4d495c6eSApple OSS Distributions /* 2*4d495c6eSApple OSS Distributions * Copyright (c) 2025 Apple Inc. All rights reserved. 3*4d495c6eSApple OSS Distributions * 4*4d495c6eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5*4d495c6eSApple OSS Distributions * 6*4d495c6eSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code 7*4d495c6eSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License 8*4d495c6eSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in 9*4d495c6eSApple OSS Distributions * compliance with the License. The rights granted to you under the License 10*4d495c6eSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of, 11*4d495c6eSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to 12*4d495c6eSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any 13*4d495c6eSApple OSS Distributions * terms of an Apple operating system software license agreement. 14*4d495c6eSApple OSS Distributions * 15*4d495c6eSApple OSS Distributions * Please obtain a copy of the License at 16*4d495c6eSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file. 17*4d495c6eSApple OSS Distributions * 18*4d495c6eSApple OSS Distributions * The Original Code and all software distributed under the License are 19*4d495c6eSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20*4d495c6eSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21*4d495c6eSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22*4d495c6eSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23*4d495c6eSApple OSS Distributions * Please see the License for the specific language governing rights and 24*4d495c6eSApple OSS Distributions * limitations under the License. 25*4d495c6eSApple OSS Distributions * 26*4d495c6eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27*4d495c6eSApple OSS Distributions */ 28*4d495c6eSApple OSS Distributions 29*4d495c6eSApple OSS Distributions #include <darwintest.h> 30*4d495c6eSApple OSS Distributions #include <fcntl.h> 31*4d495c6eSApple OSS Distributions #include <sys/types.h> 32*4d495c6eSApple OSS Distributions #include <sys/sysctl.h> 33*4d495c6eSApple OSS Distributions #include <IOKit/IOKitLib.h> 34*4d495c6eSApple OSS Distributions #include "test_utils.h" 35*4d495c6eSApple OSS Distributions 36*4d495c6eSApple OSS Distributions // Include the KSANCOV tool header 37*4d495c6eSApple OSS Distributions #include "../san/tools/ksancov.h" 38*4d495c6eSApple OSS Distributions 39*4d495c6eSApple OSS Distributions T_GLOBAL_META( 40*4d495c6eSApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"), 41*4d495c6eSApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("kasan"), 42*4d495c6eSApple OSS Distributions T_META_OWNER("a_fioraldi") 43*4d495c6eSApple OSS Distributions ); 44*4d495c6eSApple OSS Distributions 45*4d495c6eSApple OSS Distributions T_DECL( 46*4d495c6eSApple OSS Distributions kcov_ksancov_mode_trace, 47*4d495c6eSApple OSS Distributions "Ensure that KSANCOV can trace program counters when the kernel is compiled with instrumentation (KSANCOV=1)", 48*4d495c6eSApple OSS Distributions // Only relevant on KASAN kernels with KCOV available 49*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.kcov.available", 1), 50*4d495c6eSApple OSS Distributions // Only relevant on KASAN kernels compiled with SanitizerCoverage instrumentation 51*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.kcov.sancov_compiled", 1) 52*4d495c6eSApple OSS Distributions ) { 53*4d495c6eSApple OSS Distributions int fd = ksancov_open(); 54*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(fd, "ksancov_open"); 55*4d495c6eSApple OSS Distributions 56*4d495c6eSApple OSS Distributions size_t max_entries = 64UL * 1024; 57*4d495c6eSApple OSS Distributions int ret = ksancov_mode_trace(fd, max_entries); 58*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_mode_trace"); 59*4d495c6eSApple OSS Distributions 60*4d495c6eSApple OSS Distributions uintptr_t addr; 61*4d495c6eSApple OSS Distributions size_t sz; 62*4d495c6eSApple OSS Distributions ret = ksancov_map(fd, &addr, &sz); 63*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_map"); 64*4d495c6eSApple OSS Distributions 65*4d495c6eSApple OSS Distributions ksancov_trace_t *trace = (ksancov_trace_t *)addr; 66*4d495c6eSApple OSS Distributions 67*4d495c6eSApple OSS Distributions ret = ksancov_thread_self(fd); 68*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_thread_self"); 69*4d495c6eSApple OSS Distributions 70*4d495c6eSApple OSS Distributions ksancov_reset(trace); 71*4d495c6eSApple OSS Distributions ksancov_start(trace); 72*4d495c6eSApple OSS Distributions 73*4d495c6eSApple OSS Distributions // trace the getppid syscall 74*4d495c6eSApple OSS Distributions getppid(); 75*4d495c6eSApple OSS Distributions 76*4d495c6eSApple OSS Distributions ksancov_stop(trace); 77*4d495c6eSApple OSS Distributions 78*4d495c6eSApple OSS Distributions // ksancov_trace_* contain useful assertions 79*4d495c6eSApple OSS Distributions size_t head = ksancov_trace_head(trace); 80*4d495c6eSApple OSS Distributions T_EXPECT_GT(head, (size_t)0, "Expected to have at least 1 program counter in the coverage trace"); 81*4d495c6eSApple OSS Distributions if (head > 0) { 82*4d495c6eSApple OSS Distributions ksancov_trace_entry(trace, 0); 83*4d495c6eSApple OSS Distributions } 84*4d495c6eSApple OSS Distributions 85*4d495c6eSApple OSS Distributions ret = close(fd); 86*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "close"); 87*4d495c6eSApple OSS Distributions } 88*4d495c6eSApple OSS Distributions 89*4d495c6eSApple OSS Distributions T_DECL( 90*4d495c6eSApple OSS Distributions kcov_ksancov_mode_trace_kext, 91*4d495c6eSApple OSS Distributions "Ensure that KSANCOV can trace program counters of a kext bundle", 92*4d495c6eSApple OSS Distributions // Only relevant on KASAN kernels with KCOV available 93*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.kcov.available", 1), 94*4d495c6eSApple OSS Distributions // Can enable coverage collection of KEXTs only when on demand KSANCOV is enabled 95*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.kcov.od.support_enabled", 1), 96*4d495c6eSApple OSS Distributions // Enable this test only on iPhone rdar://155524478 97*4d495c6eSApple OSS Distributions T_META_ENABLED(TARGET_OS_IOS && !TARGET_OS_MACCATALYST && !TARGET_OS_SIMULATOR) 98*4d495c6eSApple OSS Distributions ) { 99*4d495c6eSApple OSS Distributions io_service_t io_surface = IO_OBJECT_NULL; 100*4d495c6eSApple OSS Distributions io_surface = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot")); 101*4d495c6eSApple OSS Distributions T_ASSERT_NE(io_surface, IO_OBJECT_NULL, "Expected to find the IOSurface service"); 102*4d495c6eSApple OSS Distributions 103*4d495c6eSApple OSS Distributions int fd = ksancov_open(); 104*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(fd, "ksancov_open"); 105*4d495c6eSApple OSS Distributions 106*4d495c6eSApple OSS Distributions size_t max_entries = 64UL * 1024; 107*4d495c6eSApple OSS Distributions int ret = ksancov_mode_trace(fd, max_entries); 108*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_mode_trace"); 109*4d495c6eSApple OSS Distributions 110*4d495c6eSApple OSS Distributions uintptr_t addr; 111*4d495c6eSApple OSS Distributions size_t sz; 112*4d495c6eSApple OSS Distributions ret = ksancov_map(fd, &addr, &sz); 113*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_map"); 114*4d495c6eSApple OSS Distributions 115*4d495c6eSApple OSS Distributions ksancov_trace_t *trace = (ksancov_trace_t *)addr; 116*4d495c6eSApple OSS Distributions 117*4d495c6eSApple OSS Distributions ret = ksancov_thread_self(fd); 118*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_thread_self"); 119*4d495c6eSApple OSS Distributions 120*4d495c6eSApple OSS Distributions ret = ksancov_on_demand_set_gate(fd, "com.apple.iokit.IOSurface", true); 121*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_on_demand_set_gate"); 122*4d495c6eSApple OSS Distributions ksancov_reset(trace); 123*4d495c6eSApple OSS Distributions ksancov_start(trace); 124*4d495c6eSApple OSS Distributions 125*4d495c6eSApple OSS Distributions // trace the IOSurface IOServiceOpen/Close 126*4d495c6eSApple OSS Distributions io_connect_t connect = IO_OBJECT_NULL; 127*4d495c6eSApple OSS Distributions IOReturn ioret; 128*4d495c6eSApple OSS Distributions ioret = IOServiceOpen(io_surface, mach_task_self(), 0, &connect); 129*4d495c6eSApple OSS Distributions T_EXPECT_EQ(ioret, kIOReturnSuccess, "Unable to open the IOSurface userclient"); 130*4d495c6eSApple OSS Distributions if (ioret == kIOReturnSuccess) { 131*4d495c6eSApple OSS Distributions IOServiceClose(connect); 132*4d495c6eSApple OSS Distributions } 133*4d495c6eSApple OSS Distributions 134*4d495c6eSApple OSS Distributions ksancov_stop(trace); 135*4d495c6eSApple OSS Distributions ret = ksancov_on_demand_set_gate(fd, "com.apple.iokit.IOSurface", false); 136*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_on_demand_set_gate"); 137*4d495c6eSApple OSS Distributions 138*4d495c6eSApple OSS Distributions // ksancov_trace_* contain useful assertions 139*4d495c6eSApple OSS Distributions size_t head = ksancov_trace_head(trace); 140*4d495c6eSApple OSS Distributions T_EXPECT_GT(head, (size_t)0, "Expected to have at least 1 program counter in the coverage trace"); 141*4d495c6eSApple OSS Distributions if (head > 0) { 142*4d495c6eSApple OSS Distributions ksancov_trace_entry(trace, 0); 143*4d495c6eSApple OSS Distributions } 144*4d495c6eSApple OSS Distributions 145*4d495c6eSApple OSS Distributions ret = close(fd); 146*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "close"); 147*4d495c6eSApple OSS Distributions } 148*4d495c6eSApple OSS Distributions 149*4d495c6eSApple OSS Distributions T_DECL( 150*4d495c6eSApple OSS Distributions kcov_ksancov_mode_trace_cmp_kext, 151*4d495c6eSApple OSS Distributions "Ensure that KSANCOV can trace program counters and comparisons of a kext bundle", 152*4d495c6eSApple OSS Distributions // Only relevant on KASAN kernels with KCOV available 153*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.kcov.available", 1), 154*4d495c6eSApple OSS Distributions // Can enable coverage collection of KEXTs only when on demand KSANCOV is enabled 155*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.kcov.od.support_enabled", 1), 156*4d495c6eSApple OSS Distributions // Enable this test only on iPhone rdar://155524478 157*4d495c6eSApple OSS Distributions T_META_ENABLED(TARGET_OS_IOS && !TARGET_OS_MACCATALYST && !TARGET_OS_SIMULATOR) 158*4d495c6eSApple OSS Distributions ) { 159*4d495c6eSApple OSS Distributions io_service_t io_surface = IO_OBJECT_NULL; 160*4d495c6eSApple OSS Distributions io_surface = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot")); 161*4d495c6eSApple OSS Distributions T_ASSERT_NE(io_surface, IO_OBJECT_NULL, "Expected to find the IOSurface service"); 162*4d495c6eSApple OSS Distributions 163*4d495c6eSApple OSS Distributions int fd = ksancov_open(); 164*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(fd, "ksancov_open"); 165*4d495c6eSApple OSS Distributions 166*4d495c6eSApple OSS Distributions size_t max_entries = 64UL * 1024; 167*4d495c6eSApple OSS Distributions int ret = ksancov_mode_trace(fd, max_entries); 168*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_mode_trace"); 169*4d495c6eSApple OSS Distributions 170*4d495c6eSApple OSS Distributions uintptr_t addr; 171*4d495c6eSApple OSS Distributions size_t sz; 172*4d495c6eSApple OSS Distributions ret = ksancov_map(fd, &addr, &sz); 173*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_map"); 174*4d495c6eSApple OSS Distributions 175*4d495c6eSApple OSS Distributions ksancov_trace_t *trace = (ksancov_trace_t *)addr; 176*4d495c6eSApple OSS Distributions 177*4d495c6eSApple OSS Distributions ret = ksancov_cmps_mode_trace(fd, max_entries, true); 178*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_cmps_mode_trace"); 179*4d495c6eSApple OSS Distributions 180*4d495c6eSApple OSS Distributions ret = ksancov_cmps_map(fd, &addr, &sz); 181*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_cmps_map"); 182*4d495c6eSApple OSS Distributions 183*4d495c6eSApple OSS Distributions ksancov_trace_t *cmps_trace = (ksancov_trace_t *)addr; 184*4d495c6eSApple OSS Distributions 185*4d495c6eSApple OSS Distributions ret = ksancov_thread_self(fd); 186*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_thread_self"); 187*4d495c6eSApple OSS Distributions 188*4d495c6eSApple OSS Distributions ret = ksancov_on_demand_set_gate(fd, "com.apple.iokit.IOSurface", true); 189*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_on_demand_set_gate"); 190*4d495c6eSApple OSS Distributions ksancov_reset(trace); 191*4d495c6eSApple OSS Distributions ksancov_reset(cmps_trace); 192*4d495c6eSApple OSS Distributions ksancov_start(trace); 193*4d495c6eSApple OSS Distributions ksancov_start(cmps_trace); 194*4d495c6eSApple OSS Distributions 195*4d495c6eSApple OSS Distributions // trace the IOSurface IOServiceOpen/Close 196*4d495c6eSApple OSS Distributions io_connect_t connect = IO_OBJECT_NULL; 197*4d495c6eSApple OSS Distributions IOReturn ioret; 198*4d495c6eSApple OSS Distributions ioret = IOServiceOpen(io_surface, mach_task_self(), 0, &connect); 199*4d495c6eSApple OSS Distributions T_EXPECT_EQ(ioret, kIOReturnSuccess, "Unable to open the IOSurface userclient"); 200*4d495c6eSApple OSS Distributions if (ioret == kIOReturnSuccess) { 201*4d495c6eSApple OSS Distributions IOServiceClose(connect); 202*4d495c6eSApple OSS Distributions } 203*4d495c6eSApple OSS Distributions 204*4d495c6eSApple OSS Distributions ksancov_stop(trace); 205*4d495c6eSApple OSS Distributions ksancov_stop(cmps_trace); 206*4d495c6eSApple OSS Distributions ret = ksancov_on_demand_set_gate(fd, "com.apple.iokit.IOSurface", false); 207*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_on_demand_set_gate"); 208*4d495c6eSApple OSS Distributions 209*4d495c6eSApple OSS Distributions // ksancov_trace_* contain useful assertions 210*4d495c6eSApple OSS Distributions size_t head = ksancov_trace_head(trace); 211*4d495c6eSApple OSS Distributions T_EXPECT_GT(head, (size_t)0, "Expected to have at least 1 program counter in the coverage trace"); 212*4d495c6eSApple OSS Distributions if (head > 0) { 213*4d495c6eSApple OSS Distributions ksancov_trace_entry(trace, 0); 214*4d495c6eSApple OSS Distributions } 215*4d495c6eSApple OSS Distributions 216*4d495c6eSApple OSS Distributions head = ksancov_trace_head(cmps_trace); 217*4d495c6eSApple OSS Distributions T_EXPECT_GT(head, (size_t)0, "Expected to have at least 1 comparison in the comparisons trace"); 218*4d495c6eSApple OSS Distributions 219*4d495c6eSApple OSS Distributions size_t i; 220*4d495c6eSApple OSS Distributions for (i = 0; i < head;) { 221*4d495c6eSApple OSS Distributions ksancov_cmps_trace_ent_t *entry = ksancov_cmps_trace_entry(cmps_trace, i); 222*4d495c6eSApple OSS Distributions if (KCOV_CMP_IS_FUNC(entry->type)) { 223*4d495c6eSApple OSS Distributions size_t space = ksancov_cmps_trace_func_space(entry->len1_func, entry->len2_func); 224*4d495c6eSApple OSS Distributions i += space / sizeof(ksancov_cmps_trace_ent_t); 225*4d495c6eSApple OSS Distributions } else { 226*4d495c6eSApple OSS Distributions ++i; 227*4d495c6eSApple OSS Distributions } 228*4d495c6eSApple OSS Distributions } 229*4d495c6eSApple OSS Distributions T_EXPECT_EQ(i, head, "Cursor went past the end of the trace"); 230*4d495c6eSApple OSS Distributions 231*4d495c6eSApple OSS Distributions ret = close(fd); 232*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "close"); 233*4d495c6eSApple OSS Distributions } 234*4d495c6eSApple OSS Distributions 235*4d495c6eSApple OSS Distributions T_DECL( 236*4d495c6eSApple OSS Distributions kcov_ksancov_testcases, 237*4d495c6eSApple OSS Distributions "Test the testcases buffer feature in KSANCOV", 238*4d495c6eSApple OSS Distributions // Only relevant on KASAN kernels with KCOV available 239*4d495c6eSApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.kcov.available", 1) 240*4d495c6eSApple OSS Distributions ) { 241*4d495c6eSApple OSS Distributions int fd = ksancov_open(); 242*4d495c6eSApple OSS Distributions if (fd < 0) { 243*4d495c6eSApple OSS Distributions T_SKIP("Ksancov not available, skipping..."); 244*4d495c6eSApple OSS Distributions return; 245*4d495c6eSApple OSS Distributions } 246*4d495c6eSApple OSS Distributions 247*4d495c6eSApple OSS Distributions size_t max_entries = 32; 248*4d495c6eSApple OSS Distributions int ret = ksancov_mode_trace(fd, max_entries); 249*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_mode_trace"); 250*4d495c6eSApple OSS Distributions 251*4d495c6eSApple OSS Distributions size_t num_testcases = 2; 252*4d495c6eSApple OSS Distributions ret = ksancov_testcases(fd, num_testcases); 253*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_testcases"); 254*4d495c6eSApple OSS Distributions 255*4d495c6eSApple OSS Distributions uintptr_t addr; 256*4d495c6eSApple OSS Distributions size_t sz; 257*4d495c6eSApple OSS Distributions ret = ksancov_testcases_map(fd, &addr, &sz); 258*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_testcases_map"); 259*4d495c6eSApple OSS Distributions 260*4d495c6eSApple OSS Distributions T_EXPECT_EQ(sz, sizeof(ksancov_serialized_testcases_t) + sizeof(ksancov_serialized_testcase_t) * num_testcases, "Testcases mapped size mismatch"); 261*4d495c6eSApple OSS Distributions ksancov_serialized_testcases_t *testcases = (ksancov_serialized_testcases_t *)addr; 262*4d495c6eSApple OSS Distributions 263*4d495c6eSApple OSS Distributions ret = ksancov_thread_self(fd); 264*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "ksancov_thread_self"); 265*4d495c6eSApple OSS Distributions 266*4d495c6eSApple OSS Distributions T_ASSERT_EQ(sizeof(testcases->list[testcases->head].buffer), (size_t)KSANCOV_SERIALIZED_TESTCASE_BYTES, "Buffer size not KSANCOV_SERIALIZED_TESTCASE_BYTES"); 267*4d495c6eSApple OSS Distributions testcases->list[testcases->head].buffer[0] = 'f'; 268*4d495c6eSApple OSS Distributions testcases->list[testcases->head].buffer[1] = 'o'; 269*4d495c6eSApple OSS Distributions testcases->list[testcases->head].buffer[2] = 'o'; 270*4d495c6eSApple OSS Distributions testcases->list[testcases->head].buffer[3] = 0; 271*4d495c6eSApple OSS Distributions testcases->list[testcases->head].size = 4; 272*4d495c6eSApple OSS Distributions testcases->head = (testcases->head + 1) % num_testcases; 273*4d495c6eSApple OSS Distributions 274*4d495c6eSApple OSS Distributions ret = ksancov_testcases_log(fd); 275*4d495c6eSApple OSS Distributions // The serial log can fail if serial=0x1 or debug=0x2 are not set in the boot args 276*4d495c6eSApple OSS Distributions 277*4d495c6eSApple OSS Distributions ret = close(fd); 278*4d495c6eSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "close"); 279*4d495c6eSApple OSS Distributions } 280