blob: ac9cacc3cd8317d3c297cc2f17e915b68f7f842b [file] [log] [blame]
/*
* 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