1 /*
2 * Copyright (C) 2023 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 "./shell-code.h"
18
19 #include <sys/mman.h>
20 #include <sys/types.h>
21
22 #define PAGE_START(addr) ((uintptr_t)addr & ~(PAGE_SIZE - 1))
23
24 // Shell code that sets the SELinux context of the current process.
25 //
26 // The shell code expects a null-terminated SELinux context string to be placed
27 // immediately after it in memory. After the SELinux context has been changed
28 // the shell code will stop the current process with SIGSTOP.
29 //
30 // This shell code must be self-contained and position-independent.
31 extern "C" void __setcon_shell_code_start();
32 extern "C" void __setcon_shell_code_end();
33
34 // Shell code that stops execution of the current process by raising a signal.
35 // The specific signal that is raised is given in __trap_shell_code_signal.
36 //
37 // This shell code can be used to inject break points into a traced process.
38 //
39 // The shell code must not modify any registers other than the program counter.
40 extern "C" void __trap_shell_code_start();
41 extern "C" void __trap_shell_code_end();
42 extern "C" int __trap_shell_code_signal;
43
44 namespace shell_as {
45
46 namespace {
EnsureShellcodeReadable(void (* start)(),void (* end)())47 void EnsureShellcodeReadable(void (*start)(), void (*end)()) {
48 mprotect((void*)PAGE_START(start),
49 PAGE_START(end) - PAGE_START(start) + PAGE_SIZE,
50 PROT_READ | PROT_EXEC);
51 }
52 } // namespace
53
GetSELinuxShellCode(char * selinux_context,size_t * total_size)54 std::unique_ptr<uint8_t[]> GetSELinuxShellCode(
55 char* selinux_context, size_t* total_size) {
56 EnsureShellcodeReadable(&__setcon_shell_code_start, &__setcon_shell_code_end);
57
58 size_t shell_code_size = (uintptr_t)&__setcon_shell_code_end -
59 (uintptr_t)&__setcon_shell_code_start;
60 size_t selinux_context_size = strlen(selinux_context) + 1 /* null byte */;
61 *total_size = shell_code_size + selinux_context_size;
62
63 std::unique_ptr<uint8_t[]> shell_code(new uint8_t[*total_size]);
64 memcpy(shell_code.get(), (void*)&__setcon_shell_code_start, shell_code_size);
65 memcpy(shell_code.get() + shell_code_size, selinux_context,
66 selinux_context_size);
67 return shell_code;
68 }
69
GetTrapShellCode(int * expected_signal,size_t * total_size)70 std::unique_ptr<uint8_t[]> GetTrapShellCode(int* expected_signal,
71 size_t* total_size) {
72 EnsureShellcodeReadable(&__trap_shell_code_start, &__trap_shell_code_end);
73
74 *expected_signal = __trap_shell_code_signal;
75
76 *total_size =
77 (uintptr_t)&__trap_shell_code_end - (uintptr_t)&__trap_shell_code_start;
78 std::unique_ptr<uint8_t[]> shell_code(new uint8_t[*total_size]);
79 memcpy(shell_code.get(), (void*)&__trap_shell_code_start, *total_size);
80 return shell_code;
81 }
82 } // namespace shell_as
83