freebsd_note_target.c (5160B)
1 /* A FreeBSD shared object may leave EI_OSABI at System V and carry its 2 * platform identity only in an NT_FREEBSD_ABI_TAG note. Target detection 3 * must consult that note before the linker performs OS compatibility checks. */ 4 5 #include <kit/object.h> 6 #include <stdint.h> 7 #include <string.h> 8 9 #include "lib/kit_unit.h" 10 11 enum { 12 ELF64_EHDR_SIZE = 64, 13 ELF64_PHDR_SIZE = 56, 14 ELF64_SHDR_SIZE = 64, 15 NOTE_SIZE = 24, 16 NOTE_OFFSET = ELF64_EHDR_SIZE + ELF64_PHDR_SIZE, 17 SECTION_NOTE_OFFSET = ELF64_EHDR_SIZE + ELF64_SHDR_SIZE, 18 IMAGE_SIZE = SECTION_NOTE_OFFSET + NOTE_SIZE, 19 }; 20 21 static void put16le(uint8_t* p, uint16_t v) { 22 p[0] = (uint8_t)v; 23 p[1] = (uint8_t)(v >> 8); 24 } 25 26 static void put32le(uint8_t* p, uint32_t v) { 27 p[0] = (uint8_t)v; 28 p[1] = (uint8_t)(v >> 8); 29 p[2] = (uint8_t)(v >> 16); 30 p[3] = (uint8_t)(v >> 24); 31 } 32 33 static void put64le(uint8_t* p, uint64_t v) { 34 put32le(p, (uint32_t)v); 35 put32le(p + 4, (uint32_t)(v >> 32)); 36 } 37 38 static void make_rv64_elf_with_note(uint8_t image[IMAGE_SIZE], 39 const char owner[8], uint32_t type) { 40 uint8_t* ph; 41 uint8_t* note; 42 memset(image, 0, IMAGE_SIZE); 43 44 image[0] = 0x7f; 45 image[1] = 'E'; 46 image[2] = 'L'; 47 image[3] = 'F'; 48 image[4] = 2; /* ELFCLASS64 */ 49 image[5] = 1; /* ELFDATA2LSB */ 50 image[6] = 1; /* EV_CURRENT */ 51 image[7] = 0; /* ELFOSABI_NONE / System V */ 52 put16le(image + 16, 3); /* ET_DYN */ 53 put16le(image + 18, 243); /* EM_RISCV */ 54 put32le(image + 20, 1); /* EV_CURRENT */ 55 put64le(image + 32, ELF64_EHDR_SIZE); 56 put16le(image + 52, ELF64_EHDR_SIZE); 57 put16le(image + 54, ELF64_PHDR_SIZE); 58 put16le(image + 56, 1); 59 60 ph = image + ELF64_EHDR_SIZE; 61 put32le(ph, 4); /* PT_NOTE */ 62 put64le(ph + 8, NOTE_OFFSET); 63 put64le(ph + 32, NOTE_SIZE); 64 put64le(ph + 40, NOTE_SIZE); 65 put64le(ph + 48, 4); 66 67 note = image + NOTE_OFFSET; 68 put32le(note, 8); /* namesz: "FreeBSD\0" */ 69 put32le(note + 4, 4); /* descsz: ABI version */ 70 put32le(note + 8, type); 71 memcpy(note + 12, owner, 8); 72 put32le(note + 20, 1500068); 73 } 74 75 static void make_rv64_elf_with_section_note(uint8_t image[IMAGE_SIZE], 76 const char owner[8], 77 uint32_t type) { 78 uint8_t* sh; 79 uint8_t* note; 80 make_rv64_elf_with_note(image, owner, type); 81 put64le(image + 32, 0); /* no program-header table */ 82 put16le(image + 54, 0); 83 put16le(image + 56, 0); 84 put64le(image + 40, ELF64_EHDR_SIZE); 85 put16le(image + 58, ELF64_SHDR_SIZE); 86 put16le(image + 60, 1); 87 88 sh = image + ELF64_EHDR_SIZE; 89 memset(sh, 0, ELF64_SHDR_SIZE); 90 put32le(sh + 4, 7); /* SHT_NOTE */ 91 put64le(sh + 24, SECTION_NOTE_OFFSET); 92 put64le(sh + 32, NOTE_SIZE); 93 put64le(sh + 48, 4); 94 95 note = image + SECTION_NOTE_OFFSET; 96 put32le(note, 8); 97 put32le(note + 4, 4); 98 put32le(note + 8, type); 99 memcpy(note + 12, owner, 8); 100 put32le(note + 20, 1500068); 101 } 102 103 int main(void) { 104 const char freebsd_owner[8] = {'F', 'r', 'e', 'e', 105 'B', 'S', 'D', '\0'}; 106 const char other_owner[8] = {'N', 'o', 't', 'F', 107 'r', 'e', 'e', '\0'}; 108 uint8_t image[IMAGE_SIZE]; 109 KitTargetSpec target; 110 KitUnit u; 111 112 kit_unit_init(&u); 113 114 make_rv64_elf_with_note(image, freebsd_owner, 1); 115 memset(&target, 0, sizeof target); 116 CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK, 117 "SysV-branded FreeBSD ELF is detected"); 118 CU_EXPECT(&u, target.arch == KIT_ARCH_RV64, "RISC-V arch is preserved"); 119 CU_EXPECT(&u, target.obj == KIT_OBJ_ELF, "ELF format is preserved"); 120 CU_EXPECT(&u, target.os == KIT_OS_FREEBSD, 121 "NT_FREEBSD_ABI_TAG supplies FreeBSD identity"); 122 123 make_rv64_elf_with_note(image, other_owner, 1); 124 memset(&target, 0, sizeof target); 125 CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK, 126 "generic SysV ELF is detected"); 127 CU_EXPECT(&u, target.os == KIT_OS_LINUX, 128 "unrecognized notes do not change the SysV default"); 129 130 make_rv64_elf_with_note(image, freebsd_owner, 2); 131 memset(&target, 0, sizeof target); 132 CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK, 133 "ELF with a non-ABI FreeBSD note is detected"); 134 CU_EXPECT(&u, target.os == KIT_OS_LINUX, 135 "only NT_FREEBSD_ABI_TAG changes target identity"); 136 137 make_rv64_elf_with_section_note(image, freebsd_owner, 1); 138 memset(&target, 0, sizeof target); 139 CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK, 140 "section-only FreeBSD ELF is detected"); 141 CU_EXPECT(&u, target.os == KIT_OS_FREEBSD, 142 "SHT_NOTE FreeBSD ABI tag supplies target identity"); 143 144 make_rv64_elf_with_note(image, freebsd_owner, 1); 145 put32le(image + NOTE_OFFSET, UINT32_MAX); 146 memset(&target, 0, sizeof target); 147 CU_EXPECT(&u, kit_detect_target(image, sizeof image, &target) == KIT_OK, 148 "malformed note does not invalidate an otherwise detectable ELF"); 149 CU_EXPECT(&u, target.os == KIT_OS_LINUX, 150 "out-of-bounds note payload is ignored safely"); 151 152 kit_unit_summary(&u, "freebsd_note_target"); 153 return kit_unit_status(&u); 154 }