1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <vector>
33
34 #include "memtag_globals.h"
35
36 // Adapted from the LLD test suite: lld/test/ELF/Inputs/aarch64-memtag-globals.s
37
38 int global_extern;
39 static int global_extern_hidden;
40 __attribute__((no_sanitize("memtag"))) int global_extern_untagged;
41 __attribute__((no_sanitize("memtag"))) int global_extern_untagged_definition_but_tagged_import;
42
assertion_failure()43 void assertion_failure() {
44 exit(1);
45 }
46
check_tagged(const void * a)47 void check_tagged(const void* a) {
48 uintptr_t a_uptr = reinterpret_cast<uintptr_t>(a);
49 #if defined(__aarch64__)
50 if ((a_uptr >> 56) == 0) {
51 fprintf(stderr, "**********************************\n");
52 fprintf(stderr, "Failed assertion:\n");
53 fprintf(stderr, " tag(0x%zx) != 0\n", a_uptr);
54 fprintf(stderr, "**********************************\n");
55
56 assertion_failure();
57 }
58 #endif // defined(__aarch64__)
59 }
60
check_untagged(const void * a)61 void check_untagged(const void* a) {
62 uintptr_t a_uptr = reinterpret_cast<uintptr_t>(a);
63 #if defined(__aarch64__)
64 if ((a_uptr >> 56) != 0) {
65 fprintf(stderr, "**********************************\n");
66 fprintf(stderr, "Failed assertion:\n");
67 fprintf(stderr, " tag(0x%zx) == 0\n", a_uptr);
68 fprintf(stderr, "**********************************\n");
69
70 assertion_failure();
71 }
72 #endif // defined(__aarch64__)
73 }
74
check_matching_tags(const void * a,const void * b)75 void check_matching_tags(const void* a, const void* b) {
76 uintptr_t a_uptr = reinterpret_cast<uintptr_t>(a);
77 uintptr_t b_uptr = reinterpret_cast<uintptr_t>(b);
78 #if defined(__aarch64__)
79 if (a_uptr >> 56 != b_uptr >> 56) {
80 fprintf(stderr, "**********************************\n");
81 fprintf(stderr, "Failed assertion:\n");
82 fprintf(stderr, " tag(0x%zx) != tag(0x%zx)\n", a_uptr, b_uptr);
83 fprintf(stderr, "**********************************\n");
84
85 assertion_failure();
86 }
87 #endif // defined(__aarch64__)
88 }
89
check_eq(const void * a,const void * b)90 void check_eq(const void* a, const void* b) {
91 if (a != b) {
92 fprintf(stderr, "**********************************\n");
93 fprintf(stderr, "Failed assertion:\n");
94 fprintf(stderr, " %p != %p\n", a, b);
95 fprintf(stderr, "**********************************\n");
96
97 assertion_failure();
98 }
99 }
100
101 #define LONGEST_VARIABLE_NAME "51"
print_variable_address(const char * name,const void * ptr)102 void print_variable_address(const char* name, const void* ptr) {
103 printf("%" LONGEST_VARIABLE_NAME "s: %16p\n", name, ptr);
104 }
105
get_expected_tagged_vars()106 static const std::vector<std::pair<const char*, const void*>>& get_expected_tagged_vars() {
107 static std::vector<std::pair<const char*, const void*>> expected_tagged_vars = {
108 {"global_extern", &global_extern},
109 {"global_extern_hidden", &global_extern_hidden},
110 };
111 return expected_tagged_vars;
112 }
113
get_expected_untagged_vars()114 static const std::vector<std::pair<const char*, const void*>>& get_expected_untagged_vars() {
115 static std::vector<std::pair<const char*, const void*>> expected_untagged_vars = {
116 {"global_extern_untagged", &global_extern_untagged},
117 {"global_extern_untagged_definition_but_tagged_import",
118 &global_extern_untagged_definition_but_tagged_import},
119 };
120 return expected_untagged_vars;
121 }
122
dso_print_variables()123 void dso_print_variables() {
124 print_variables(" Variables declared in the DSO:\n", get_expected_tagged_vars(),
125 get_expected_untagged_vars());
126 }
127
print_variables(const char * header,const std::vector<std::pair<const char *,const void * >> & tagged_variables,const std::vector<std::pair<const char *,const void * >> & untagged_variables)128 void print_variables(const char* header,
129 const std::vector<std::pair<const char*, const void*>>& tagged_variables,
130 const std::vector<std::pair<const char*, const void*>>& untagged_variables) {
131 printf("==========================================================\n");
132 printf("%s", header);
133 printf("==========================================================\n");
134 printf(" Variables expected to be tagged:\n");
135 printf("----------------------------------------------------------\n");
136 for (const auto& [name, pointer] : tagged_variables) {
137 print_variable_address(name, pointer);
138 }
139
140 printf("\n----------------------------------------------------------\n");
141 printf(" Variables expected to be untagged:\n");
142 printf("----------------------------------------------------------\n");
143 for (const auto& [name, pointer] : untagged_variables) {
144 print_variable_address(name, pointer);
145 }
146 printf("\n");
147 }
148
dso_check_assertions(bool check_pointers_are_tagged)149 void dso_check_assertions(bool check_pointers_are_tagged) {
150 // Check that non-const variables are writeable.
151 global_extern = 0;
152 global_extern_hidden = 0;
153 global_extern_untagged = 0;
154 global_extern_untagged_definition_but_tagged_import = 0;
155
156 if (check_pointers_are_tagged) {
157 for (const auto& [_, pointer] : get_expected_tagged_vars()) {
158 check_tagged(pointer);
159 }
160 }
161
162 for (const auto& [_, pointer] : get_expected_untagged_vars()) {
163 check_untagged(pointer);
164 }
165 }
166