upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
230
android/system/extras/runconuid/runconuid.cpp
Normal file
230
android/system/extras/runconuid/runconuid.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
const char* optstr = "<1u:g:G:c:s";
|
||||
const char* usage =
|
||||
R"(usage: runconuid [-s] [-u UID] [-g GID] [-G GROUPS] [-c CONTEXT] COMMAND ARGS
|
||||
|
||||
Run a command in the specified security context, as the specified user,
|
||||
with the specified group membership.
|
||||
|
||||
-c SELinux context
|
||||
-g Group ID by name or numeric value
|
||||
-G List of groups by name or numeric value
|
||||
-s Set enforcing mode
|
||||
-u User ID by name or numeric value
|
||||
)";
|
||||
|
||||
#include <assert.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static uid_t uid = -1;
|
||||
static gid_t gid = -1;
|
||||
static gid_t* groups = nullptr;
|
||||
static size_t ngroups = 0;
|
||||
static char* context = nullptr;
|
||||
static bool setenforce = false;
|
||||
static char** child_argv = nullptr;
|
||||
|
||||
[[noreturn]] void perror_exit(const char* message) {
|
||||
perror(message);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void do_child(void) {
|
||||
if (context && setexeccon(context) < 0) {
|
||||
perror_exit("Setting context to failed");
|
||||
}
|
||||
|
||||
if (ngroups && setgroups(ngroups, groups) < 0) {
|
||||
perror_exit("Setting supplementary groups failed.");
|
||||
}
|
||||
|
||||
if (gid != (gid_t) -1 && setresgid(gid, gid, gid) < 0) {
|
||||
perror_exit("Setting group failed.");
|
||||
}
|
||||
|
||||
if (uid != (uid_t) -1 && setresuid(uid, uid, uid) < 0) {
|
||||
perror_exit("Setting user failed.");
|
||||
}
|
||||
|
||||
ptrace(PTRACE_TRACEME, 0, 0, 0);
|
||||
raise(SIGSTOP);
|
||||
execvp(child_argv[0], child_argv);
|
||||
perror_exit("Failed to execve");
|
||||
}
|
||||
|
||||
uid_t lookup_uid(char* c) {
|
||||
struct passwd* pw;
|
||||
uid_t u;
|
||||
|
||||
if (sscanf(c, "%d", &u) == 1) {
|
||||
return u;
|
||||
}
|
||||
|
||||
if ((pw = getpwnam(c)) != 0) {
|
||||
return pw->pw_uid;
|
||||
}
|
||||
|
||||
perror_exit("Could not resolve user ID by name");
|
||||
}
|
||||
|
||||
gid_t lookup_gid(char* c) {
|
||||
struct group* gr;
|
||||
gid_t g;
|
||||
|
||||
if (sscanf(c, "%d", &g) == 1) {
|
||||
return g;
|
||||
}
|
||||
|
||||
if ((gr = getgrnam(c)) != 0) {
|
||||
return gr->gr_gid;
|
||||
}
|
||||
|
||||
perror_exit("Could not resolve group ID by name");
|
||||
}
|
||||
|
||||
void lookup_groups(char* c) {
|
||||
char* group;
|
||||
|
||||
// Count the number of groups
|
||||
for (group = c; *group; group++) {
|
||||
if (*group == ',') {
|
||||
ngroups++;
|
||||
*group = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// The last group is not followed by a comma.
|
||||
ngroups++;
|
||||
|
||||
// Allocate enough space for all of them
|
||||
groups = (gid_t*)calloc(ngroups, sizeof(gid_t));
|
||||
group = c;
|
||||
|
||||
// Fill in the group IDs
|
||||
for (size_t n = 0; n < ngroups; n++) {
|
||||
groups[n] = lookup_gid(group);
|
||||
group += strlen(group) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_arguments(int argc, char** argv) {
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, optstr)) != -1) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
uid = lookup_uid(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
gid = lookup_gid(optarg);
|
||||
break;
|
||||
case 'G':
|
||||
lookup_groups(optarg);
|
||||
break;
|
||||
case 's':
|
||||
setenforce = true;
|
||||
break;
|
||||
case 'c':
|
||||
context = optarg;
|
||||
break;
|
||||
default:
|
||||
perror_exit(usage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
child_argv = &argv[optind];
|
||||
|
||||
if (optind == argc) {
|
||||
perror_exit(usage);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
pid_t child;
|
||||
|
||||
parse_arguments(argc, argv);
|
||||
child = fork();
|
||||
|
||||
if (child < 0) {
|
||||
perror_exit("Could not fork.");
|
||||
}
|
||||
|
||||
if (setenforce && is_selinux_enabled()) {
|
||||
if (security_setenforce(0) < 0) {
|
||||
perror("Couldn't set enforcing status to 0");
|
||||
}
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
do_child();
|
||||
}
|
||||
|
||||
if (ptrace(PTRACE_ATTACH, child, 0, 0) < 0) {
|
||||
int err = errno;
|
||||
kill(SIGKILL, child);
|
||||
errno = err;
|
||||
perror_exit("Could not ptrace child.");
|
||||
}
|
||||
|
||||
// Wait for the SIGSTOP
|
||||
int status = 0;
|
||||
if (-1 == wait(&status)) {
|
||||
perror_exit("Could not wait for child SIGSTOP");
|
||||
}
|
||||
|
||||
// Trace all syscalls.
|
||||
ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACESYSGOOD);
|
||||
|
||||
while (1) {
|
||||
ptrace(PTRACE_SYSCALL, child, 0, 0);
|
||||
waitpid(child, &status, 0);
|
||||
|
||||
// Child raises SIGINT after the execve, on the first instruction.
|
||||
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Child did some other syscall.
|
||||
if (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Child exited.
|
||||
if (WIFEXITED(status)) {
|
||||
exit(WEXITSTATUS(status));
|
||||
}
|
||||
}
|
||||
|
||||
if (setenforce && is_selinux_enabled()) {
|
||||
if (security_setenforce(1) < 0) {
|
||||
perror("Couldn't set enforcing status to 1");
|
||||
}
|
||||
}
|
||||
|
||||
ptrace(PTRACE_DETACH, child, 0, 0);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue