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 <linux/prctl.h>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/prctl.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <memory>
26 
MaybeDowngrade()27 int MaybeDowngrade() {
28     int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
29     if (res == -1) return 1;
30     if (static_cast<unsigned long>(res) & PR_MTE_TCF_ASYNC) return 2;
31     time_t t = time(nullptr);
32     while (time(nullptr) - t < 100) {
33         res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
34         if (static_cast<unsigned long>(res) & PR_MTE_TCF_ASYNC) {
35             return 0;
36         }
37         sleep(1);
38     }
39     return 3;
40 }
41 
main(int argc,char ** argv)42 int main(int argc, char** argv) {
43     if (argc == 2 && strcmp(argv[1], "--check-downgrade") == 0) {
44         return MaybeDowngrade();
45     }
46     int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
47     if (res == -1) abort();
48     if (argc == 2 && strcmp(argv[1], "--get-mode") == 0) {
49         if (res & PR_MTE_TCF_ASYNC) {
50             return 1;
51         }
52         if (res & PR_MTE_TCF_SYNC) {
53             return 2;
54         }
55         abort();
56     }
57 
58     if (res & PR_MTE_TCF_ASYNC && res & PR_MTE_TCF_SYNC) {
59         // Disallow automatic upgrade from ASYNC mode.
60         if (prctl(PR_SET_TAGGED_ADDR_CTRL, res & ~PR_MTE_TCF_SYNC, 0, 0, 0) == -1) abort();
61     }
62     std::unique_ptr<volatile char[]> f(new char[1]);
63     // This out-of-bounds is on purpose: we are testing MTE, which is designed to turn
64     // out-of-bound errors into segfaults.
65     // This binary gets run by src/com/android/tests/init/MteUpgradeTest.java, which
66     // asserts that it crashes as expected.
67     f[17] = 'x';
68     char buf[1];
69     read(1, buf, 1);
70     return 0;
71 }
72