#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/uio.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <sys/types.h>
+#include <sys/endian.h>
#include "su.h"
#include "utils.h"
return ppwd->pw_uid;
}
-void exec_log(char *priority, char* logline) {
- int pid;
- if ((pid = fork()) == 0) {
- int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
- int null = open("/dev/null", O_WRONLY | O_CLOEXEC);
- dup2(null, 0);
- dup2(null, 1);
- dup2(null, 2);
- execl("/system/bin/log", "/system/bin/log", "-p", priority, "-t", LOG_TAG, logline, NULL);
- _exit(0);
- }
+int fork_zero_fucks() {
+ int pid = fork();
+ if (pid) {
+ int status;
+ waitpid(pid, &status, 0);
+ return pid;
+ }
+ else {
+ if ((pid = fork()))
+ exit(0);
+ return 0;
+ }
}
-void exec_loge(const char* fmt, ...) {
+void exec_log(int priority, const char* fmt, ...) {
+ static int log_fd = -1;
+ struct iovec vec[3];
va_list args;
+ char msg[PATH_MAX];
- char logline[PATH_MAX];
- va_start(args, fmt);
- vsnprintf(logline, PATH_MAX, fmt, args);
- va_end(args);
- exec_log("e", logline);
-}
-
-void exec_logw(const char* fmt, ...) {
- va_list args;
+ if (log_fd < 0) {
+ log_fd = open("/dev/log/main", O_WRONLY);
+ if (log_fd < 0) {
+ return;
+ }
+ }
- char logline[PATH_MAX];
va_start(args, fmt);
- vsnprintf(logline, PATH_MAX, fmt, args);
+ vsnprintf(msg, PATH_MAX, fmt, args);
va_end(args);
- exec_log("w", logline);
-}
-void exec_logd(const char* fmt, ...) {
- va_list args;
+ vec[0].iov_base = (unsigned char *) &priority;
+ vec[0].iov_len = 1;
+ vec[1].iov_base = (void *) LOG_TAG;
+ vec[1].iov_len = strlen(LOG_TAG) + 1;
+ vec[2].iov_base = (void *) msg;
+ vec[2].iov_len = strlen(msg) + 1;
- char logline[PATH_MAX];
- va_start(args, fmt);
- vsnprintf(logline, PATH_MAX, fmt, args);
- va_end(args);
- exec_log("d", logline);
+ writev(log_fd, vec, 3);
}
static int from_init(struct su_initiator *from) {
from->uid = getuid();
from->pid = getppid();
+ if (is_daemon) {
+ from->uid = daemon_from_uid;
+ from->pid = daemon_from_pid;
+ }
+
/* Get the command line */
snprintf(path, sizeof(path), "/proc/%u/cmdline", from->pid);
fd = open(path, O_RDONLY);
strncpy(from->name, pw->pw_name, sizeof(from->name));
}
- if (is_daemon) {
- from->uid = daemon_from_uid;
- from->pid = daemon_from_pid;
- }
-
return 0;
}
static int socket_send_request(int fd, const struct su_context *ctx) {
#define write_data(fd, data, data_len) \
do { \
- size_t __len = htonl(data_len); \
+ uint32_t __len = htonl(data_len); \
__len = write((fd), &__len, sizeof(__len)); \
- LOGE("%d", __len);\
if (__len != sizeof(__len)) { \
PLOGE("write(" #data ")"); \
return -1; \
static int socket_receive_result(int fd, char *result, ssize_t result_len) {
ssize_t len;
- LOGD("waiting for user");
+ LOGV("waiting for user");
len = read(fd, result, result_len-1);
if (len < 0) {
PLOGE("read(result)");
fprintf(stream,
"Usage: su [options] [--] [-] [LOGIN] [--] [args...]\n\n"
"Options:\n"
+ " --daemon start the su daemon agent\n"
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
" -h, --help display this help message and exit\n"
" -, -l, --login pretend the shell to be a login shell\n"
* Find the properties ourselves.
*/
int access_disabled(const struct su_initiator *from) {
+#ifndef SUPERUSER_EMBEDDED
+ return 0;
+#else
char *data;
char build_type[PROPERTY_VALUE_MAX];
char debuggable[PROPERTY_VALUE_MAX], enabled[PROPERTY_VALUE_MAX];
if (data != NULL) {
len = strlen(data);
if (len >= PROPERTY_VALUE_MAX)
- memcpy(enabled, "1", 2);
+ memcpy(enabled, "0", 2);
else
memcpy(enabled, data, len + 1);
free(data);
} else
- memcpy(enabled, "1", 2);
+ memcpy(enabled, "0", 2);
/* enforce persist.sys.root_access on non-eng builds for apps */
if (strcmp("eng", build_type) != 0 &&
}
return 0;
+#endif
+}
+
+static int get_api_version() {
+ char sdk_ver[PROPERTY_VALUE_MAX];
+ char *data = read_file("/system/build.prop");
+ get_property(data, sdk_ver, "ro.build.version.sdk", "0");
+ int ver = atoi(sdk_ver);
+ free(data);
+ return ver;
+}
+
+static void fork_for_samsung(void)
+{
+ // Samsung CONFIG_SEC_RESTRICT_SETUID wants the parent process to have
+ // EUID 0, or else our setresuid() calls will be denied. So make sure
+ // all such syscalls are executed by a child process.
+ int rv;
+
+ switch (fork()) {
+ case 0:
+ return;
+ case -1:
+ PLOGE("fork");
+ exit(1);
+ default:
+ if (wait(&rv) < 0) {
+ exit(1);
+ } else {
+ exit(WEXITSTATUS(rv));
+ }
+ }
}
int main(int argc, char *argv[]) {
+ return su_main(argc, argv, 1);
+}
+
+int su_main(int argc, char *argv[], int need_client) {
// start up in daemon mode if prompted
if (argc == 2 && strcmp(argv[1], "--daemon") == 0) {
return run_daemon();
}
- if (geteuid() != AID_ROOT && getuid() != AID_ROOT) {
- // attempt to connect to daemon...
- LOGD("starting daemon client %d %d", getuid(), geteuid());
- return connect_daemon(argc, argv);
- }
+ int ppid = getppid();
+ fork_for_samsung();
// Sanitize all secure environment variables (from linker_environ.c in AOSP linker).
/* The same list than GLibc at this point */
cp++;
}
- /*
- * set LD_LIBRARY_PATH if the linker has wiped out it due to we're suid.
- * This occurs on Android 4.0+
- */
- setenv("LD_LIBRARY_PATH", "/vendor/lib:/system/lib", 0);
-
LOGD("su invoked.");
struct su_context ctx = {
usage(2);
}
}
+
+ if (need_client) {
+ // attempt to use the daemon client if not root,
+ // or this is api 18 and adb shell (/data is not readable even as root)
+ // or just always use it on API 19+ (ART)
+ if ((geteuid() != AID_ROOT && getuid() != AID_ROOT) ||
+ (get_api_version() >= 18 && getuid() == AID_SHELL) ||
+ get_api_version() >= 19) {
+ // attempt to connect to daemon...
+ LOGD("starting daemon client %d %d", getuid(), geteuid());
+ return connect_daemon(argc, argv, ppid);
+ }
+ }
+
if (optind < argc && !strcmp(argv[optind], "-")) {
ctx.to.login = 1;
optind++;