| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "./shell-code.h" |
| |
| #include <sys/mman.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| // Shell code that sets the SELinux context of the current process. |
| // |
| // The shell code expects a null-terminated SELinux context string to be placed |
| // immediately after it in memory. After the SELinux context has been changed |
| // the shell code will stop the current process with SIGSTOP. |
| // |
| // This shell code must be self-contained and position-independent. |
| extern "C" void __setcon_shell_code_start(); |
| extern "C" void __setcon_shell_code_end(); |
| |
| // Shell code that stops execution of the current process by raising a signal. |
| // The specific signal that is raised is given in __trap_shell_code_signal. |
| // |
| // This shell code can be used to inject break points into a traced process. |
| // |
| // The shell code must not modify any registers other than the program counter. |
| extern "C" void __trap_shell_code_start(); |
| extern "C" void __trap_shell_code_end(); |
| extern "C" int __trap_shell_code_signal; |
| |
| namespace shell_as { |
| |
| namespace { |
| uintptr_t PageStart(void (*addr)()) { |
| return ((uintptr_t)addr & ~(getpagesize() - 1)); |
| } |
| |
| void EnsureShellcodeReadable(void (*start)(), void (*end)()) { |
| mprotect((void*)PageStart(start), |
| PageStart(end) - PageStart(start) + getpagesize(), |
| PROT_READ | PROT_EXEC); |
| } |
| } // namespace |
| |
| std::unique_ptr<uint8_t[]> GetSELinuxShellCode( |
| char* selinux_context, size_t* total_size) { |
| EnsureShellcodeReadable(&__setcon_shell_code_start, &__setcon_shell_code_end); |
| |
| size_t shell_code_size = (uintptr_t)&__setcon_shell_code_end - |
| (uintptr_t)&__setcon_shell_code_start; |
| size_t selinux_context_size = strlen(selinux_context) + 1 /* null byte */; |
| *total_size = shell_code_size + selinux_context_size; |
| |
| std::unique_ptr<uint8_t[]> shell_code(new uint8_t[*total_size]); |
| memcpy(shell_code.get(), (void*)&__setcon_shell_code_start, shell_code_size); |
| memcpy(shell_code.get() + shell_code_size, selinux_context, |
| selinux_context_size); |
| return shell_code; |
| } |
| |
| std::unique_ptr<uint8_t[]> GetTrapShellCode(int* expected_signal, |
| size_t* total_size) { |
| EnsureShellcodeReadable(&__trap_shell_code_start, &__trap_shell_code_end); |
| |
| *expected_signal = __trap_shell_code_signal; |
| |
| *total_size = |
| (uintptr_t)&__trap_shell_code_end - (uintptr_t)&__trap_shell_code_start; |
| std::unique_ptr<uint8_t[]> shell_code(new uint8_t[*total_size]); |
| memcpy(shell_code.get(), (void*)&__trap_shell_code_start, *total_size); |
| return shell_code; |
| } |
| } // namespace shell_as |