1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <getopt.h>
18 #include <unistd.h>
19
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 #include <android-base/strings.h>
24 #include <android-base/unique_fd.h>
25 #include <bootloader_message/bootloader_message.h>
26
27 #include <functional>
28 #include <iostream>
29
AddItem(std::string * s,const char * item)30 void AddItem(std::string* s, const char* item) {
31 if (!s->empty()) *s += ",";
32 *s += item;
33 }
34
CheckAndUnset(uint32_t & mode,uint32_t mask)35 bool CheckAndUnset(uint32_t& mode, uint32_t mask) {
36 bool is_set = mode & mask;
37 mode &= ~mask;
38 return is_set;
39 }
40
UpdateProp(const char * prop_name,const misc_memtag_message & m)41 bool UpdateProp(const char* prop_name, const misc_memtag_message& m) {
42 uint32_t mode = m.memtag_mode;
43 std::string prop_str;
44 if (CheckAndUnset(mode, MISC_MEMTAG_MODE_MEMTAG)) AddItem(&prop_str, "memtag");
45 if (CheckAndUnset(mode, MISC_MEMTAG_MODE_MEMTAG_ONCE)) AddItem(&prop_str, "memtag-once");
46 if (CheckAndUnset(mode, MISC_MEMTAG_MODE_MEMTAG_KERNEL)) AddItem(&prop_str, "memtag-kernel");
47 if (CheckAndUnset(mode, MISC_MEMTAG_MODE_MEMTAG_KERNEL_ONCE))
48 AddItem(&prop_str, "memtag-kernel-once");
49 if (CheckAndUnset(mode, MISC_MEMTAG_MODE_MEMTAG_OFF)) AddItem(&prop_str, "memtag-off");
50 if (CheckAndUnset(mode, MISC_MEMTAG_MODE_FORCED)) AddItem(&prop_str, "forced");
51 if (android::base::GetProperty(prop_name, "") != prop_str)
52 android::base::SetProperty(prop_name, prop_str);
53 if (mode) {
54 LOG(ERROR) << "MTE mode in misc message contained unknown bits: " << mode
55 << ". Ignoring and setting " << prop_name << " to " << prop_str;
56 }
57 return mode == 0;
58 }
59
PrintUsage(const char * progname)60 void PrintUsage(const char* progname) {
61 std::cerr
62 << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
63 "!!! YOU PROBABLY DO NOT NEED TO USE THIS !!!\n"
64 "!!! USE THE `arm64.memtag.bootctl` SYSTEM PROPERTY INSTEAD. !!!\n"
65 "!!! This program is an implementation detail that is used !!!\n"
66 "!!! by the system to apply MTE settings. !!!\n"
67 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
68 "\n"
69 << "USAGE: " << progname
70 << "\n"
71 " [-s PROPERTY_NAME]\n"
72 " [none,][memtag,][memtag-once,][memtag-kernel,][memtag-kernel-once,][memtag-off,]\n"
73 " [default|force_on|force_off]\n"
74 " [-t PATH_TO_FAKE_MISC_PARTITION]\n"
75
76 "OPTIONS:\n"
77 " -s PROPERTY_NAME\n"
78 " Sets the system property 'PROPERTY_NAME' to the new MTE mode (if provided), or to\n"
79 " the current value from the /misc partition.\n"
80 " [none,][memtag,][memtag-once,][memtag-kernel,][memtag-kernel-once,][memtag-off,]\n"
81 " A set of MTE options to be applied, if provided. Multiple options may be\n"
82 " specified as a ','-delimited list, e.g. 'memtag,memtag-kernel'.\n"
83 " The options are described below:\n"
84 " - none: default settings for MTE for the product will be applied on next\n"
85 " reboot.\n"
86 " - memtag: MTE is persistently enabled in userspace upon the next reboot.\n"
87 " - memtag-once: MTE is enabled in userspace, only for the next reboot.\n"
88 " - memtag-kernel: MTE is persistently enabled in the kernel upon the next \n"
89 " reboot.\n"
90 " - memtag-kernel-once: MTE is enabled in the kernel, only for the next reboot.\n"
91 " - memtag-off: MTE is persistently disabled in both userspace and kernel upon \n"
92 " the next reboot.\n"
93 " - forced: the current state is the result of force_on or force_off in the next\n"
94 " argument. When the next argument is set back to \"default\", the\n"
95 " state will be cleared.\n"
96 " [default|force_on|force_off]\n"
97 " An alternative method of configuring the MTE options to be applied, if provided.\n"
98 " This control is generally to be used by device_config only, and it overwrites\n"
99 " the previously described settings that are expected to be utilized by the user.\n"
100 " The options are described below:\n"
101 " - default: This flag is not overwriting the MTE mode, and so the setting\n"
102 " should be inherited from the userspace controls (if present), or the\n"
103 " default value from the bootloader's ROM.\n"
104 " - force_on: MTE is persistently enabled in userspace, overwriting the userspace\n"
105 " setting.\n"
106 " - force_off: MTE is persistently disabled in userspace and the kernel, \n"
107 " overwriting the userspace setting.\n";
108 }
109
StringToMode(const char * value)110 int StringToMode(const char* value) {
111 int memtag_mode = 0;
112 for (const auto& field : android::base::Split(value, ",")) {
113 if (field == "memtag") {
114 memtag_mode |= MISC_MEMTAG_MODE_MEMTAG;
115 } else if (field == "memtag-once") {
116 memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_ONCE;
117 } else if (field == "memtag-kernel") {
118 memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_KERNEL;
119 } else if (field == "memtag-kernel-once") {
120 memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_KERNEL_ONCE;
121 } else if (field == "memtag-off") {
122 memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_OFF;
123 } else if (field == "forced") {
124 memtag_mode |= MISC_MEMTAG_MODE_FORCED;
125 } else if (field != "none") {
126 LOG(ERROR) << "Unknown value for mode: " << field;
127 return -1;
128 }
129 }
130 return memtag_mode;
131 }
132
133 // Handles the override flag and applies it to the memtag message.
134 // The logic is as follows:
135 // If the override changes the configuration (i.e., if MTE was not enabled
136 // through MODE_MEMTAG and the override is force_on, or MTE was not
137 // disabled through MEMTAG_OFF and the override is force_off), the MTE
138 // state is considered FORCED. In that case, if the override gets reset
139 // to "default" (i.e. no override), the default state of memtag config
140 // is restored. The theory for this is that disabling the override should
141 // only keep the non-default state if it has been active throughout the
142 // override, not restore it if it had been dormant for the duration of the
143 // override.
144 //
145 // State machine diagrams of the MTE state and the effect of override below:
146 //
147 // default,force_off
148 // ┌───┐
149 // │ │
150 // ┌──┴───▼───┐
151 // │memtag-off│
152 // └─────┬────┘
153 // │
154 // force_on │ ┌────┐
155 // │ │ │ force_on
156 // force_off┌───────▼───┴─┐ │
157 // ┌────────┤memtag,forced│◄─┘
158 // │ └▲─────────┬──┘
159 // force_off │ │ │
160 // ┌────┐ │ force_on│ │ default
161 // │ │ │ │ │
162 // │ ┌─┴────▼─────────┴┐ ┌▼──────┐
163 // └─►│memtag-off,forced├───────►none │
164 // └─────────────────┘default└───────┘
165 //
166 //
167 //
168 // default,force_on
169 // ┌───┐
170 // │ │
171 // ┌──┴───▼───┐
172 // │memtag │
173 // └─────┬────┘
174 // │
175 // force_off│ ┌────┐
176 // │ │ │ force_off
177 // force_on ┌───────┴───────┴─┐ │
178 // ┌────────┤memtag-off,forced◄──┘
179 // │ └▲─────────┬──────┘
180 // force_on │ │ │
181 // ┌────┐ │force_off│ │ default
182 // │ │ │ │ │
183 // │ ┌─┴────▼─────────┴┐ ┌▼──────┐
184 // └─►│memtag,forced ├───────►none │
185 // └─────────────────┘default└───────┘
186 //
187 //
188 //
189 // default
190 // ┌───┐
191 // │ │
192 // force_off ┌──┴───▼───┐
193 // ┌─────────────┤none │
194 // │ └─────┬────┘
195 // │ │
196 // │ force_on │ ┌────┐
197 // │ │ │ │ force_on
198 // │ force_off┌───────▼───┴─┐ │
199 // │ ┌────────┤memtag,forced│◄─┘
200 // │ │ └▲─────────┬──┘
201 // force_off│ │ │ │
202 // ┌────┐ │ │ force_on│ │ default
203 // │ │ │ │ │ │
204 // │ ┌─┴─▼──▼─────────┴┐ ┌▼──────┐
205 // └─►│memtag-off,forced├───────►none │
206 // └─────────────────┘default└───────┘
HandleOverride(const std::string & override_value,misc_memtag_message * m)207 bool HandleOverride(const std::string& override_value, misc_memtag_message* m) {
208 if (override_value == "force_off") {
209 // If the force_off override is active, only allow MEMTAG_MODE_MEMTAG_ONCE.
210 if ((m->memtag_mode & MISC_MEMTAG_MODE_MEMTAG_OFF) == 0) {
211 m->memtag_mode |= MISC_MEMTAG_MODE_FORCED;
212 }
213 m->memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_OFF;
214 m->memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG;
215 } else if (override_value == "force_on") {
216 if ((m->memtag_mode & MISC_MEMTAG_MODE_MEMTAG) == 0) {
217 m->memtag_mode |= MISC_MEMTAG_MODE_FORCED;
218 }
219 m->memtag_mode |= MISC_MEMTAG_MODE_MEMTAG;
220 m->memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG_OFF;
221 } else if (override_value.empty() || override_value == "default") {
222 // The mode changed from forced_on or forced_off to default, which means we
223 // restore the normal state.
224 if (m->memtag_mode & MISC_MEMTAG_MODE_FORCED) {
225 m->memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG;
226 m->memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG_OFF;
227 m->memtag_mode &= ~MISC_MEMTAG_MODE_FORCED;
228 }
229 } else {
230 return false;
231 }
232 return true;
233 }
234
main(int argc,char ** argv)235 int main(int argc, char** argv) {
236 const char* set_prop = nullptr;
237 int opt;
238 std::function<bool(misc_memtag_message*, std::string*)> read_memtag_message =
239 ReadMiscMemtagMessage;
240 std::function<bool(const misc_memtag_message&, std::string*)> write_memtag_message =
241 WriteMiscMemtagMessage;
242
243 android::base::unique_fd fake_partition_fd;
244 while ((opt = getopt(argc, argv, "s:t:")) != -1) {
245 switch (opt) {
246 case 's':
247 // Set property in argument to state of misc partition. If given by
248 // itself, sets the property to the current state. We do this on device
249 // boot,
250 //
251 // Otherwise, applies new state and then sets property to newly applied
252 // state.
253 set_prop = optarg;
254 break;
255 case 't': {
256 // Use different fake misc partition for testing.
257 const char* filename = optarg;
258 fake_partition_fd.reset(open(filename, O_RDWR | O_CLOEXEC));
259 int raw_fd = fake_partition_fd.get();
260 CHECK_NE(raw_fd, -1);
261 CHECK_NE(ftruncate(raw_fd, sizeof(misc_memtag_message)), -1);
262 read_memtag_message = [raw_fd](misc_memtag_message* m, std::string*) {
263 CHECK(android::base::ReadFully(raw_fd, m, sizeof(*m)));
264 return true;
265 };
266 write_memtag_message = [raw_fd](const misc_memtag_message& m, std::string*) {
267 CHECK(android::base::WriteFully(raw_fd, &m, sizeof(m)));
268 return true;
269 };
270 break;
271 }
272 default:
273 PrintUsage(argv[0]);
274 return 1;
275 }
276 }
277
278 const char* value = optind < argc ? argv[optind++] : nullptr;
279 const char* override_value = optind < argc ? argv[optind++] : nullptr;
280
281 if (optind != argc) { // Unknown argument.
282 PrintUsage(argv[0]);
283 return 1;
284 }
285
286 if (!value && set_prop) {
287 // -s <property> is given on its own. This means we want to read the state
288 // of the misc partition into the property.
289 std::string err;
290 misc_memtag_message m = {};
291 if (!read_memtag_message(&m, &err)) {
292 LOG(ERROR) << "Failed to read memtag message: " << err;
293 return 1;
294 }
295 if (m.magic != MISC_MEMTAG_MAGIC_HEADER || m.version != MISC_MEMTAG_MESSAGE_VERSION) {
296 // This should not fail by construction.
297 CHECK(UpdateProp(set_prop, {}));
298 // This is an expected case, as the partition gets initialized to all zero.
299 return 0;
300 }
301 // Unlike above, setting the system property here can fail if the misc partition
302 // was corrupted by another program (e.g. the bootloader).
303 return UpdateProp(set_prop, m) ? 0 : 1;
304 }
305
306 if (!value) {
307 PrintUsage(argv[0]);
308 return 1;
309 }
310
311 misc_memtag_message m = {.version = MISC_MEMTAG_MESSAGE_VERSION,
312 .magic = MISC_MEMTAG_MAGIC_HEADER};
313 int memtag_mode = StringToMode(value);
314 bool valid_value = memtag_mode != -1;
315 m.memtag_mode = valid_value ? memtag_mode : 0;
316
317 bool valid_override = true;
318 if (override_value) valid_override = HandleOverride(override_value, &m);
319
320 if (!valid_value && !valid_override) {
321 return 1;
322 }
323 std::string err;
324 if (!write_memtag_message(m, &err)) {
325 LOG(ERROR) << "Failed to apply mode: " << value << ", override: " << override_value << err;
326 return 1;
327 } else {
328 const char* parse_error = "";
329 const char* verb = "Applied";
330 if (!valid_value) {
331 parse_error = " (invalid mode)";
332 verb = "Partially applied";
333 } else if (!valid_override) {
334 // else if because we bail out if both are false above.
335 parse_error = " (invalid override)";
336 verb = "Partially applied";
337 }
338 LOG(INFO) << verb << " mode: " << value << ", "
339 << "override: " << (override_value ? override_value : "") << parse_error;
340 // Because all the bits in memtag_mode were set above, this should never fail.
341 if (set_prop) CHECK(UpdateProp(set_prop, m));
342 return !valid_value || !valid_override;
343 }
344 }
345