Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gc #13

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open

Gc #13

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c6ef3cc
Add missing usistd.h for system(3)
Jul 19, 2012
5bbd487
Set effective uid/gid back, unlink fails otherwise
Jul 19, 2012
a315e38
Clean up database_check
Jul 19, 2012
ffe8b01
Fix compilation on JB
Jul 19, 2012
2899822
Use /dev as storage for cache again
Jul 19, 2012
0fa617a
Move headers required by PLOGE in su.h
Jul 23, 2012
f09ab43
Use fork/exec instead of system(3)
Jul 23, 2012
53f2241
Set close-on-exec for the socket
Jul 23, 2012
4692fd8
Move CM-specific code to access_disabled()
Jul 24, 2012
2ceab21
Speed up the CM-specific code a bit for non-CM ROMs
Jul 25, 2012
fcd02a7
Declare deny/allow as noreturn
Jul 26, 2012
acf38cd
Move socket_path to the su context
Jul 26, 2012
dbe1249
Don't wait until am terminates, kill it, if it hangs
Jul 26, 2012
40c3d17
Guard select from SIGCHLD
Jul 28, 2012
6799779
Wait until the child is really killed, ...
Jul 31, 2012
dfb29f9
Don't touch su context in children
Jul 31, 2012
70a5e41
Move kill_child into send_intent
Aug 1, 2012
fb7c8d1
Mark child as volatile
Aug 1, 2012
6a5c06e
Remove <endian.h>
Aug 1, 2012
ad1151e
Read in the extra line of the default store file
ChainsDD Aug 19, 2012
fa0b93d
Prevent command line pollution from allowing privilege escalation
ChainsDD Aug 19, 2012
779707b
Fix for apps that use multiple commands not being remembered properly
ChainsDD Oct 1, 2012
de0050d
Fix for apps that use multiple commands
ChainsDD Nov 18, 2012
794fb00
Multi-user support with 3 modes
ChainsDD Nov 20, 2012
95e81e5
Update version
ChainsDD Nov 20, 2012
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 93 additions & 48 deletions activity.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,62 +15,107 @@
** limitations under the License.
*/

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <paths.h>

#include "su.h"

int send_intent(const struct su_context *ctx,
const char *socket_path, int allow, const char *action)
static void kill_child(pid_t pid)
{
char command[PATH_MAX];
LOGD("killing child %d", pid);
if (pid) {
sigset_t set, old;

sprintf(command, "/system/bin/am broadcast -a '%s' --es socket '%s' --ei caller_uid '%d' --ei allow '%d' --ei version_code '%d' > /dev/null",
action, socket_path, ctx->from.uid, allow, VERSION_CODE);
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &set, &old)) {
PLOGE("sigprocmask(SIG_BLOCK)");
return;
}
if (kill(pid, SIGKILL))
PLOGE("kill (%d)", pid);
else if (sigsuspend(&old) && errno != EINTR)
PLOGE("sigsuspend");
if (sigprocmask(SIG_SETMASK, &old, NULL))
PLOGE("sigprocmask(SIG_BLOCK)");
}
}

// before sending the intent, make sure the (uid and euid) and (gid and egid) match,
// otherwise LD_LIBRARY_PATH is wiped in Android 4.0+.
// Also, sanitize all secure environment variables (from linker_environ.c in linker).
static void setup_sigchld_handler(__sighandler_t handler)
{
struct sigaction act;

/* The same list than GLibc at this point */
static const char* const unsec_vars[] = {
"GCONV_PATH",
"GETCONF_DIR",
"HOSTALIASES",
"LD_AUDIT",
"LD_DEBUG",
"LD_DEBUG_OUTPUT",
"LD_DYNAMIC_WEAK",
"LD_LIBRARY_PATH",
"LD_ORIGIN_PATH",
"LD_PRELOAD",
"LD_PROFILE",
"LD_SHOW_AUXV",
"LD_USE_LOAD_BIAS",
"LOCALDOMAIN",
"LOCPATH",
"MALLOC_TRACE",
"MALLOC_CHECK_",
"NIS_PATH",
"NLSPATH",
"RESOLV_HOST_CONF",
"RES_OPTIONS",
"TMPDIR",
"TZDIR",
"LD_AOUT_LIBRARY_PATH",
"LD_AOUT_PRELOAD",
// not listed in linker, used due to system() call
"IFS",
};
const char* const* cp = unsec_vars;
const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]);
while (cp < endp) {
unsetenv(*cp);
cp++;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
if (sigaction(SIGCHLD, &act, NULL)) {
PLOGE("sigaction(SIGCHLD)");
exit(EXIT_FAILURE);
}
}

// sane value so "am" works
setenv("LD_LIBRARY_PATH", "/vendor/lib:/system/lib", 1);
setegid(getgid());
seteuid(getuid());
return system(command);
int send_intent(struct su_context *ctx, allow_t allow, const char *action)
{
const char *socket_path;
unsigned int uid = ctx->from.uid;
__sighandler_t handler;
pid_t pid;

pid = ctx->child;
if (pid) {
kill_child(pid);
pid = ctx->child;
if (pid) {
LOGE("child %d is still running", pid);
return -1;
}
}
if (allow == INTERACTIVE) {
socket_path = ctx->sock_path;
handler = sigchld_handler;
} else {
socket_path = "";
handler = SIG_IGN;
}
setup_sigchld_handler(handler);

pid = fork();
/* Child */
if (!pid) {
char command[ARG_MAX];

snprintf(command, sizeof(command),
"exec /system/bin/am broadcast --user %d -a %s --es socket '%s' "
"--ei caller_uid %d --ei allow %d --es desired_cmd '%s' "
"--ei all %d --ei version_code %d",
ctx->user.userid, action, socket_path, uid, allow, get_command(&ctx->to),
ctx->to.all, VERSION_CODE);
char *args[] = { "sh", "-c", command, NULL, };

/*
* before sending the intent, make sure the effective uid/gid match
* the real uid/gid, otherwise LD_LIBRARY_PATH is wiped
* in Android 4.0+.
*/
set_identity(uid);
int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
dup2(zero, 0);
int null = open("/dev/null", O_WRONLY | O_CLOEXEC);
dup2(null, 1);
dup2(null, 2);
LOGD("Executing %s\n", command);
execv(_PATH_BSHELL, args);
PLOGE("exec am");
_exit(EXIT_FAILURE);
}
/* Parent */
if (pid < 0) {
PLOGE("fork");
return -1;
}
ctx->child = pid;
return 0;
}
76 changes: 51 additions & 25 deletions db.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,68 @@
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <cutils/log.h>

#include "su.h"

int database_check(const struct su_context *ctx)
int database_check(struct su_context *ctx)
{
FILE *fp;
char allow = '-';
char *filename = malloc(snprintf(NULL, 0, "%s/%u-%u", REQUESTOR_STORED_PATH, ctx->from.uid, ctx->to.uid) + 1);
sprintf(filename, "%s/%u-%u", REQUESTOR_STORED_PATH, ctx->from.uid, ctx->to.uid);
char filename[PATH_MAX];
char allow[7];
int last = 0;
int from_uid = ctx->from.uid;

if (ctx->user.owner_mode) {
from_uid = from_uid % 100000;
}

snprintf(filename, sizeof(filename),
"%s/%u-%u", ctx->user.store_path, from_uid, ctx->to.uid);
if ((fp = fopen(filename, "r"))) {
LOGD("Found file");
char cmd[PATH_MAX];
fgets(cmd, sizeof(cmd), fp);
int last = strlen(cmd) - 1;
LOGD("this is the last character %u of the string", cmd[5]);
if (cmd[last] == '\n') {
cmd[last] = '\0';
}
LOGD("Comparing %c %s, %u to %s", cmd[last - 2], cmd, last, get_command(&ctx->to));
if (strcmp(cmd, get_command(&ctx->to)) == 0) {
allow = fgetc(fp);
LOGD("Found file %s", filename);

while (fgets(allow, sizeof(allow), fp)) {
last = strlen(allow) - 1;
if (last >= 0)
allow[last] = 0;

char cmd[ARG_MAX];
fgets(cmd, sizeof(cmd), fp);
/* skip trailing '\n' */
last = strlen(cmd) - 1;
if (last >= 0)
cmd[last] = 0;

LOGD("Comparing '%s' to '%s'", cmd, get_command(&ctx->to));
if (strcmp(cmd, get_command(&ctx->to)) == 0)
break;
else if (strcmp(cmd, "any") == 0) {
ctx->to.all = 1;
break;
}
else
strcpy(allow, "prompt");
}
fclose(fp);
} else if ((fp = fopen(REQUESTOR_STORED_DEFAULT, "r"))) {
LOGD("Using default");
allow = fgetc(fp);
} else if ((fp = fopen(ctx->user.store_default, "r"))) {
LOGD("Using default file %s", ctx->user.store_default);
fgets(allow, sizeof(allow), fp);
last = strlen(allow) - 1;
if (last >=0)
allow[last] = 0;

fclose(fp);
}
free(filename);

if (allow == '1') {
return DB_ALLOW;
} else if (allow == '0') {
return DB_DENY;
if (strcmp(allow, "allow") == 0) {
return ALLOW;
} else if (strcmp(allow, "deny") == 0) {
return DENY;
} else {
return DB_INTERACTIVE;
if (ctx->user.userid != 0 && ctx->user.owner_mode) {
return DENY;
} else {
return INTERACTIVE;
}
}
}
Loading