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 132 133 134 135 | /* * Copyright (c) 2026 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Test case for bpf_setup() NULL buffer panic. * * bpf_setup() copies buffers from d_from to d_to but doesn't verify * that d_from has buffers allocated. If d_from has BPF_COMP_REQ set * but was never attached to an interface (BIOCSETIF never called), * its bd_prev_sbuf is NULL. The code copies BPF_COMP_REQ to d_to, * allocates bd_prev_sbuf for d_to, then tries to memcpy from * d_from's NULL bd_prev_sbuf — triggering a bounds-safety trap. * * Steps: * 1. Open BPF device d_from, enable header compression (sets BPF_COMP_REQ) * but do NOT call BIOCSETIF — buffers stay NULL * 2. Get d_from's UUID via BIOCGETUUID * 3. Open BPF device d_to * 4. Call BIOCSETUP on d_to with d_from's UUID and a valid interface name * -> on an unpatched kernel, panics in bpf_setup() at the memcpy * -> on a patched kernel, BIOCSETUP returns an error */ #include <darwintest.h> #include <sys/types.h> #include <sys/ioctl.h> #include <net/bpf.h> #include <net/if.h> #include <uuid/uuid.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> T_GLOBAL_META( T_META_NAMESPACE("xnu.net"), T_META_RADAR_COMPONENT_NAME("xnu"), T_META_RADAR_COMPONENT_VERSION("networking"), T_META_ASROOT(true) ); static int open_bpf(void) { char path[32]; for (int i = 0; i < 256; i++) { snprintf(path, sizeof(path), "/dev/bpf%d", i); int fd = open(path, O_RDWR); if (fd >= 0) { return fd; } } return -1; } T_DECL(bpf_setup_null_buf, "test bpf_setup with unattached d_from having BPF_COMP_REQ set", T_META_CHECK_LEAKS(false)) { /* * Step 1: Open d_from and enable header compression. * Do NOT call BIOCSETIF — buffers remain unallocated. */ int fd_from = open_bpf(); T_ASSERT_POSIX_SUCCESS(fd_from, "open BPF device for d_from"); int comp = 1; T_ASSERT_POSIX_SUCCESS(ioctl(fd_from, BIOCSHDRCOMP, &comp), "BIOCSHDRCOMP on d_from (set BPF_COMP_REQ)"); /* * Step 2: Get d_from's UUID. */ uuid_t uuid; T_ASSERT_POSIX_SUCCESS(ioctl(fd_from, BIOCGETUUID, &uuid), "BIOCGETUUID on d_from"); uuid_string_t uuid_str; uuid_unparse(uuid, uuid_str); T_LOG("d_from UUID: %s", uuid_str); /* * Step 3: Open d_to. */ int fd_to = open_bpf(); T_ASSERT_POSIX_SUCCESS(fd_to, "open BPF device for d_to"); /* * Step 4: Call BIOCSETUP on d_to with d_from's UUID. * On an unpatched kernel this panics in bpf_setup() because d_from * has no buffers allocated but has BPF_COMP_REQ set. * On a patched kernel this should return an error. */ struct bpf_setup_args bsa; memset(&bsa, 0, sizeof(bsa)); uuid_copy(bsa.bsa_uuid, uuid); strlcpy(bsa.bsa_ifname, "lo0", sizeof(bsa.bsa_ifname)); T_LOG("Calling BIOCSETUP (would panic an unpatched kernel)..."); int ret = ioctl(fd_to, BIOCSETUP, &bsa); T_EXPECT_POSIX_FAILURE(ret, ENOENT, "BIOCSETUP should fail when d_from has no buffers"); close(fd_from); close(fd_to); T_PASS("bpf_setup_null_buf completed without panic"); } |