/** Drop all capabilities except for the mentioned ones */ void dropCapabilities(int8_t keep[]) { struct __user_cap_header_struct header; struct __user_cap_data_struct cap[2]; memset(&header, 0, sizeof(header)); memset(&cap, 0, sizeof(cap)); header.version = _LINUX_CAPABILITY_VERSION_3; header.pid = 0; if (keep != NULL) { for (int i = 0; keep[i] >= 0; i++) { cap[CAP_TO_INDEX(keep[i])].permitted |= CAP_TO_MASK(keep[i]); } cap[0].effective = cap[0].inheritable = cap[0].permitted; cap[1].effective = cap[1].inheritable = cap[1].permitted; } capset(&header, &cap[0]); }
static void acquire_caps (void) { struct __user_cap_header_struct hdr = { _LINUX_CAPABILITY_VERSION_3, 0 }; struct __user_cap_data_struct data[2] = { { 0 } }; if (capget (&hdr, data) < 0) die_with_error ("capget failed"); if (((data[0].effective & REQUIRED_CAPS_0) == REQUIRED_CAPS_0) && ((data[0].permitted & REQUIRED_CAPS_0) == REQUIRED_CAPS_0) && ((data[1].effective & REQUIRED_CAPS_1) == REQUIRED_CAPS_1) && ((data[1].permitted & REQUIRED_CAPS_1) == REQUIRED_CAPS_1)) is_privileged = TRUE; if (getuid () != geteuid ()) { /* Tell kernel not clear capabilities when dropping root */ if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) die_with_error ("prctl(PR_SET_KEEPCAPS) failed"); /* Drop root uid, but retain the required permitted caps */ if (setuid (getuid ()) < 0) die_with_error ("unable to drop privs"); } if (is_privileged) { /* Drop all non-require capabilities */ data[0].effective = REQUIRED_CAPS_0; data[0].permitted = REQUIRED_CAPS_0; data[0].inheritable = 0; data[1].effective = REQUIRED_CAPS_1; data[1].permitted = REQUIRED_CAPS_1; data[1].inheritable = 0; if (capset (&hdr, data) < 0) die_with_error ("capset failed"); } /* Else, we try unprivileged user namespaces */ /* We need the process to be dumpable, or we can't access /proc/self/uid_map */ if (prctl (PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) die_with_error ("prctl(PR_SET_DUMPABLE) failed"); }
int os_program_init(void) { #ifndef QCA_ICS_PORTING //+-FLUG #ifdef ANDROID /* * We ignore errors here since errors are normal if we * are already running as non-root. */ gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; struct __user_cap_header_struct header; struct __user_cap_data_struct cap; setgroups(sizeof(groups)/sizeof(groups[0]), groups); prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); setgid(AID_WIFI); setuid(AID_WIFI); header.version = _LINUX_CAPABILITY_VERSION; header.pid = 0; cap.effective = cap.permitted = (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); cap.inheritable = 0; capset(&header, &cap); #endif /* ANDROID */ #endif /* QCA_ICS_PORTING */ //+-FLUG #ifdef WPA_TRACE dl_list_init(&alloc_list); #endif /* WPA_TRACE */ #ifdef NO_JOBCTRL /* * If SHELL doesn't support job-control. Changing another PGID to aviod to * terminate the program accidnetly. */ if (getpid() != getpgrp()) { setpgid(0, 0); //printf("Change to another PGID %d \n", getpgrp()); } #endif return 0; }
/** * li_run_drop_caps: * * Drop all remaining capabilities we have. * This needs to be run before replacing the process tree * with the actual application (we don't want it to have privileges). */ gboolean li_run_drop_caps (void) { struct __user_cap_header_struct hdr; struct __user_cap_data_struct data; memset (&hdr, 0, sizeof(hdr)); hdr.version = _LINUX_CAPABILITY_VERSION; data.effective = 0; data.permitted = 0; data.inheritable = 0; if (capset (&hdr, &data) < 0) { g_printerr ("capset failed\n"); return FALSE; } return TRUE; }
void set_minprivilage(void) { struct passwd* pwd = getpwnam("nobody"); if ( NULL == pwd ) ERR_EXIT("getpwnam error"); if ( -1 == setegid(pwd->pw_gid)) ERR_EXIT("setegid error"); if ( -1 == seteuid(pwd->pw_uid)) ERR_EXIT("seteuid error"); struct __user_cap_header_struct cap_header; cap_header.version = _LINUX_CAPABILITY_VERSION_1; cap_header.pid = 0; struct __user_cap_data_struct cap_data; cap_data.effective = cap_data.permitted = 1 << CAP_NET_BIND_SERVICE; cap_data.inheritable = 0; if ( -1 == capset(&cap_header,&cap_data)) ERR_EXIT("capset error"); }
static bool verifyCap() { int retried = 0; struct __user_cap_header_struct header; struct __user_cap_data_struct user[2]; header.version = _LINUX_CAPABILITY_VERSION_3; header.pid = 0; if (getuid()!=0) { WRITE_MSG(2, "'VERIFYCAP' can be executed as root only\n"); return false; } // if( prctl( PR_SET_KEEPCAPS, 1,0,0,0 ) < 0 ) { // perror( "prctl:" ); // return false; // } retry: if (capget(&header, user)==-1) { if (!retried && header.version != _LINUX_CAPABILITY_VERSION_3) { header.version = _LINUX_CAPABILITY_VERSION_1; retried = 1; goto retry; } perror("capget()"); return false; } user[0].effective = user[1].effective = 0; user[0].permitted = user[1].permitted = 0; user[0].inheritable = user[1].inheritable = 0; if (capset(&header, user)==-1) { perror("capset()"); return false; } return chroot("/")==-1; }
int main(int ac, char **av) { int lc; /* loop counter */ char *msg; /* message returned from parse_opts */ /* parse standard options */ if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL) { tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg); } /* perform global setup for test */ setup(); /* check looping state if -i option given */ for (lc = 0; TEST_LOOPING(lc); lc++) { /* reset Tst_count in case we are looping. */ Tst_count = 0; TEST(capset(&header, &data)); if (TEST_RETURN == 0) { tst_resm(TPASS, "capset() returned %d", TEST_RETURN); } else { tst_resm(TFAIL, "Test Failed, capset()" " returned %d, errno = %d : %s." " Maybe you need to do `modprobe capability`?", TEST_RETURN, TEST_ERRNO, strerror(TEST_ERRNO) ); } } /* End for TEST_LOOPING */ /* cleanup and exit */ cleanup(); /*NOTREACHED*/ return 0; } /* End main */
static int stress_capgetset_pid( const char *name, const pid_t pid, const bool do_set, uint64_t *counter, const bool exists) { int ret; struct __user_cap_header_struct uch; struct __user_cap_data_struct ucd[_LINUX_CAPABILITY_U32S_3]; memset(&uch, 0, sizeof uch); memset(ucd, 0, sizeof ucd); uch.version = _LINUX_CAPABILITY_VERSION_3; uch.pid = pid; ret = capget(&uch, ucd); if (ret < 0) { if (((errno == ESRCH) && exists) || (errno != ESRCH)) { pr_fail(stderr, "%s: capget on pid %d failed: errno=%d (%s)\n", name, pid, errno, strerror(errno)); } } if (do_set) { ret = capset(&uch, ucd); if (ret < 0) { if (((errno == ESRCH) && exists) || (errno != ESRCH)) { pr_fail(stderr, "%s: capget on pid %d failed: errno=%d (%s)\n", name, pid, errno, strerror(errno)); } } } (*counter)++; return ret; }
static int drop_privs() { struct sched_param param; memset(¶m, 0, sizeof(param)); if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) { return -1; } if (prctl(PR_SET_KEEPCAPS, 1) < 0) { return -1; } if (setgid(AID_LOGD) != 0) { return -1; } if (setuid(AID_LOGD) != 0) { return -1; } struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG); capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |= CAP_TO_MASK(CAP_AUDIT_CONTROL); capdata[0].effective = capdata[0].permitted; capdata[1].effective = capdata[1].permitted; capdata[0].inheritable = 0; capdata[1].inheritable = 0; if (capset(&capheader, &capdata[0]) < 0) { return -1; } return 0; }
/** * li_run_acquire_caps: * * Ensure we have just the capabilities we need to set up the environment. */ gboolean li_run_acquire_caps (void) { struct __user_cap_header_struct hdr; struct __user_cap_data_struct data; if (getuid () != geteuid ()) { /* Tell kernel not clear capabilities when dropping root */ if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { g_printerr ("prctl(PR_SET_KEEPCAPS) failed\n"); return FALSE; } /* Drop root uid, but retain the required permitted caps */ if (setuid (getuid ()) < 0) { g_printerr ("unable to drop privileges\n"); return FALSE; } } memset (&hdr, 0, sizeof(hdr)); hdr.version = _LINUX_CAPABILITY_VERSION; /* Drop all non-require capabilities */ data.effective = REQUIRED_CAPS; data.permitted = REQUIRED_CAPS; data.inheritable = 0; if (capset (&hdr, &data) < 0) { g_printerr ("capset failed\n"); return FALSE; } /* Never gain any more privs during exec */ if (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { g_printerr ("prctl(PR_SET_NO_NEW_CAPS) failed"); return FALSE; } return TRUE; }
int main(int argc, char **argv) { struct __user_cap_header_struct header = { _LINUX_CAPABILITY_VERSION_3, 0 }; struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; if (argc < 2) { fprintf(stderr, "Usage: %s COMMAND [ARGS]\n", argv[0]); exit(1); } prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); if (setgid(getgid()) < 0 || setuid(getuid()) < 0) error(EXIT_FAILURE, 0, "Failed to drop privileges"); capget(&header, data); data[CAP_NET_BIND_SERVICE >> 5].inheritable = 1 << (CAP_NET_BIND_SERVICE & 31); capset(&header, data); prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0); execvp(argv[1], argv + 1); error(EXIT_FAILURE, errno, "exec %s", argv[1]); }
static int drop_privs(void) { struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { return -1; } /* * ensure we're running as the system user */ if (setgid(AID_SYSTEM) != 0) { return -1; } if (setuid(AID_SYSTEM) != 0) { return -1; } /* * drop all capabilities except SYS_RAWIO */ memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted = CAP_TO_MASK(CAP_SYS_RAWIO); capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective = CAP_TO_MASK(CAP_SYS_RAWIO); if (capset(&capheader, &capdata[0]) < 0) { return -1; } /* no-execute for user, no access for group and other */ umask(S_IXUSR | S_IRWXG | S_IRWXO); return 0; }
static void drop_privileges() { if (prctl(PR_SET_KEEPCAPS, 1) < 0) { ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); exit(1); } if (setgid(AID_INSTALL) < 0) { ALOGE("setgid() can't drop privileges; exiting.\n"); exit(1); } if (setuid(AID_INSTALL) < 0) { ALOGE("setuid() can't drop privileges; exiting.\n"); exit(1); } struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE); capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN); capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); capdata[0].effective = capdata[0].permitted; capdata[1].effective = capdata[1].permitted; capdata[0].inheritable = 0; capdata[1].inheritable = 0; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); exit(1); } }
/* aplogd_drop_root() * * Description: Drops root user and keeps only what we need. * * Notes: None */ void aplogd_drop_root() { if (0 != getuid()) return; DPRINT("Dropping from root user to log user\n"); prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); /* We need AID_SYSTEM supplemental group to have read access to /proc/kmsg. * We need AID_SDCARD_RW supplemental group to have access to external storage. * We need AID_MOUNT supplemental group to have access to /dev/socket/vold. */ gid_t groups[] = {AID_SYSTEM, AID_SDCARD_RW, AID_MOUNT}; if (-1 == setgroups(sizeof(groups)/sizeof(groups[0]), groups)) { EPRINT("setgroups() failed; errno=%d", errno); exit(-1); } /* We need to be the AID_LOG as our primary group so that files we * create allow AID_LOG group access. */ if (-1 == setgid(AID_LOG)) { EPRINT("setgid() failed; errno=%d", errno); exit(-1); } /* We need to be the AID_LOG user because we are a logger. This must * be after changing groups. */ if (-1 == setuid(AID_LOG)) { EPRINT("setuid() failed; errno=%d", errno); exit(-1); } /* We need to keep CAP_SYS_ADMIN in order to read from /proc/kmsg. */ struct __user_cap_header_struct header; struct __user_cap_data_struct cap; header.version = _LINUX_CAPABILITY_VERSION; header.pid = 0; cap.effective = cap.permitted = cap.inheritable = 1 << CAP_SYS_ADMIN; if (-1 == capset(&header, &cap)) { EPRINT("capset() failed; errno=%d", errno); exit(-1); } }
static void set_capabilities(void) { #if defined(ANDROID) struct __user_cap_header_struct header; struct __user_cap_data_struct cap; header.version = _LINUX_CAPABILITY_VERSION; header.pid = 0; /* * CAP_NET_RAW: for snooping * CAP_DAC_READ_SEARCH: override path search permissions */ cap.effective = cap.permitted = CAP_TO_MASK(CAP_NET_RAW) | CAP_TO_MASK(CAP_DAC_READ_SEARCH); cap.inheritable = 0; /* TODO: Move to cap_set_proc once bionic support it */ if (capset(&header, &cap) < 0) exit(EXIT_FAILURE); #endif }
/* * switchUser - Switches UID to radio, preserving CAP_NET_ADMIN capabilities. * Our group, cache, was set by init. */ void switchUser() { prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); setuid(AID_RADIO); struct __user_cap_header_struct header; memset(&header, 0, sizeof(header)); header.version = _LINUX_CAPABILITY_VERSION_3; header.pid = 0; struct __user_cap_data_struct data[2]; memset(&data, 0, sizeof(data)); data[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN); data[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN); data[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW); data[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW); if (capset(&header, &data[0]) == -1) { RLOGE("capset failed: %s", strerror(errno)); exit(EXIT_FAILURE); } }
static bool set_capabilities(void) { #if defined(ANDROID) struct __user_cap_header_struct header; struct __user_cap_data_struct cap; header.version = _LINUX_CAPABILITY_VERSION; header.pid = 0; /* CAP_NET_ADMIN: Allow use of MGMT interface * CAP_NET_BIND_SERVICE: Allow use of privileged PSM * CAP_NET_RAW: Allow use of bnep ioctl calls */ cap.effective = cap.permitted = CAP_TO_MASK(CAP_NET_RAW) | CAP_TO_MASK(CAP_NET_ADMIN) | CAP_TO_MASK(CAP_NET_BIND_SERVICE); cap.inheritable = 0; /* TODO: Move to cap_set_proc once bionic support it */ if (capset(&header, &cap) < 0) { error("%s: capset(): %s", __func__, strerror(errno)); return false; } /* TODO: Move to cap_get_proc once bionic support it */ if (capget(&header, &cap) < 0) { error("%s: capget(): %s", __func__, strerror(errno)); return false; } DBG("Caps: eff: 0x%x, perm: 0x%x, inh: 0x%x", cap.effective, cap.permitted, cap.inheritable); #endif return true; }
int main (int argc, char *argv[]) { int option; // holds the option from getopt_long const char *const short_options = "hp:v:c:mis:g:w:r:lt:j:b:n"; // possible cmd line short options const struct option long_options[] = { // possible cmd line long options { "help", 0, NULL, 'h' }, { "port", 1, NULL, 'p' }, { "verbose", 1, NULL, 'v' }, { "command", 1, NULL, 'c' }, { "memdump", 0, NULL, 'm' }, { "image", 0, NULL, 'i' }, { "sahara", 1, NULL, 's' }, { "prefix", 1, NULL, 'g' }, { "where", 1, NULL, 'w' }, { "ramdumpimage", 1, NULL, 'r' }, { "efssyncloop", 0, NULL, 'l' }, { "rxtimeout", 1, NULL, 't' }, { "maxwrite", 1, NULL, 'j' }, { "addsearchpath", 1, NULL, 'b' }, { "noreset", 0, NULL, 'n' }, { NULL, 0, NULL, 0 } }; bool efs_sync = false; unsigned int i; bool enable_sahara_transfer = false; #ifndef WINDOWSPC unsigned long cap; int err; int rc; struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) { dbg(LOG_WARN, "set keepcaps failed!"); } for (cap = 0; prctl(PR_CAPBSET_READ, cap, 0, 0, 0) >= 0; cap++) { if ((cap == CAP_SETUID) || (cap == CAP_SETGID) || (cap == CAP_BLOCK_SUSPEND)) { continue; } err = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0); if ((err < 0) && (errno != EINVAL)) { dbg(LOG_WARN, "Drop capability %d failed\n", cap); } } if (setgid(AID_SYSTEM) != 0) { dbg(LOG_WARN, "setgid failed"); } else { if (setuid(AID_SYSTEM) != 0) { dbg(LOG_WARN, "setuid failed"); } else { memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_BLOCK_SUSPEND)].permitted |= CAP_TO_MASK(CAP_BLOCK_SUSPEND); capdata[CAP_TO_INDEX(CAP_BLOCK_SUSPEND)].effective |= CAP_TO_MASK(CAP_BLOCK_SUSPEND); if ((rc = capset(&capheader, capdata)) < 0) { dbg(LOG_WARN, "capset failed: %s, rc = %d\n", strerror(errno), rc); } } } #endif if (false == init_search_path_list() || false == init_sahara_mapping_list()) { dbg(LOG_ERROR, "Could not initialize."); return EXIT_FAILURE; } /* parse command-line options */ do { option = getopt_long (argc, argv, short_options, long_options, NULL); switch (option) { case -1: /* no more option arguments */ break; case 'h': /* -h or --help */ usage(); return EXIT_SUCCESS; case 'p': /* Get the port string name */ com_port.port_name = optarg; dbg(LOG_INFO, "Port name '%s'", com_port.port_name); break; case 's': /* -s or --sahara */ /*add the input to <id,file_name> list*/ if (false == add_input_to_sahara_mapping_list(optarg)) { dbg(LOG_ERROR, "Failed to add file to file list"); return EXIT_FAILURE; } enable_sahara_transfer = true; break; case 'b': if (false == add_search_path(optarg)) { dbg(LOG_ERROR, "Failed to add to search path list"); return EXIT_FAILURE; } break; case 'i': /* -i or --image */ sahara_data.mode = SAHARA_MODE_IMAGE_TX_PENDING; enable_sahara_transfer = true; break; case 'v': /* -v or --verbose */ kickstart_options.verbose = atoi(optarg); break; case 'm': /* -m or --memdump */ sahara_data.mode = SAHARA_MODE_MEMORY_DEBUG; enable_sahara_transfer = true; break; case 'r': /* -r or --ramdumpimage */ sahara_data.ram_dump_image = atoi(optarg); enable_sahara_transfer = true; break; case 'g': /* -g or --prefix */ kickstart_options.saved_file_prefix = optarg; break; case 'w': /* -w or --where - path for memory dump */ kickstart_options.path_to_save_files = optarg; break; case 'c': /* -c or --command */ sahara_data.mode = SAHARA_MODE_COMMAND; sahara_data.command = atoi(optarg); enable_sahara_transfer = true; break; case 'l': /* -l or --loop */ efs_sync = true; sahara_data.mode = SAHARA_MODE_MEMORY_DEBUG; com_port.rx_timeout = -1; enable_sahara_transfer = true; break; case 't': com_port.rx_timeout = atoi(optarg); break; case 'j': /* -c or --command */ com_port.MAX_TO_WRITE = atoi(optarg); break; case 'n': /* -n or --noreset */ sahara_data.allow_sahara_reset = false; break; default: /* unknown option. */ dbg(LOG_ERROR, "unrecognized option: '%c'", option); usage (); return EXIT_FAILURE; } } while (option != -1); #ifndef WINDOWSPC /* After parsing the command line args try to change the verbosity level of the logs if the system property was set. */ kickstart_options.verbose = read_verbosity_property (kickstart_options.verbose); #endif if (true == enable_sahara_transfer) { if (NULL == com_port.port_name) { dbg(LOG_ERROR, "Port device name not specified; use -p option."); return EXIT_FAILURE; } for (i = 0; i < kickstart_options.port_connect_retries; i++) { if (true == port_connect(com_port.port_name)) { break; } } if (kickstart_options.port_connect_retries == i) { dbg(LOG_ERROR, "Could not connect to %s", com_port.port_name); return EXIT_FAILURE; } // This is a little hacky. Ideally the timeout values should be passed in // as an argument, but since they don't change too often, hardcoding them // here for now if (efs_sync) { com_port.rx_timeout_sec = 0; com_port.rx_timeout_usec = 500000; dbg(LOG_STATUS, "Setting timeout to 500ms"); } else { com_port.rx_timeout_sec = 2; com_port.rx_timeout_usec = 0; dbg(LOG_STATUS, "Setting timeout to 2s"); } if (false == sahara_main (efs_sync)) { dbg(LOG_ERROR, "Uploading Image using Sahara protocol failed"); use_wakelock(WAKELOCK_RELEASE); port_disconnect(); return EXIT_FAILURE; } } port_disconnect(); return EXIT_SUCCESS; }
int dexopt(const char *apk_path, uid_t uid, int is_public) { struct utimbuf ut; struct stat apk_stat, dex_stat; char dex_path[PKG_PATH_MAX]; char dexopt_flags[PROPERTY_VALUE_MAX]; char *end; int res, zip_fd=-1, odex_fd=-1; /* Before anything else: is there a .odex file? If so, we have * pre-optimized the apk and there is nothing to do here. */ if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { return -1; } /* platform-specific flags affecting optimization and verification */ property_get("dalvik.vm.dexopt-flags", dexopt_flags, ""); strcpy(dex_path, apk_path); end = strrchr(dex_path, '.'); if (end != NULL) { strcpy(end, ".odex"); if (stat(dex_path, &dex_stat) == 0) { return 0; } } if (create_cache_path(dex_path, apk_path)) { return -1; } memset(&apk_stat, 0, sizeof(apk_stat)); stat(apk_path, &apk_stat); zip_fd = open(apk_path, O_RDONLY, 0); if (zip_fd < 0) { ALOGE("dexopt cannot open '%s' for input\n", apk_path); return -1; } unlink(dex_path); odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (odex_fd < 0) { ALOGE("dexopt cannot open '%s' for output\n", dex_path); goto fail; } if (fchmod(odex_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { ALOGE("dexopt cannot chmod '%s'\n", dex_path); goto fail; } if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { ALOGE("dexopt cannot chown '%s'\n", dex_path); goto fail; } ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { ALOGE("setgid(%d) failed during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { ALOGE("setuid(%d) during dexopt\n", uid); exit(65); } // drop capabilities struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); exit(66); } if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); exit(67); } run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags); exit(68); /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path); if (res != 0) { ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res); goto fail; } } ut.actime = apk_stat.st_atime; ut.modtime = apk_stat.st_mtime; utime(dex_path, &ut); close(odex_fd); close(zip_fd); return 0; fail: if (odex_fd >= 0) { close(odex_fd); unlink(dex_path); } if (zip_fd >= 0) { close(zip_fd); } return -1; }
void DropCapabilities(int Level) { #ifdef USE_LINUX_CAPABILITIES //use portable 'libcap' interface if it's available #ifdef HAVE_LIBCAP #include <sys/capability.h> #define CAPSET_SIZE 10 int CapSet[CAPSET_SIZE]; int NumCapsSet=0; cap_t cap; //if we are a session then drop everything. Switch user should have happened, //but if it failed we drop everything. Yes, a root attacker can probably //reclaim caps, but it at least makes them do some work if (Level < CAPS_LEVEL_SESSION) { CapSet[NumCapsSet]= CAP_CHOWN; NumCapsSet++; CapSet[NumCapsSet]= CAP_SETUID; NumCapsSet++; CapSet[NumCapsSet]= CAP_SETGID; NumCapsSet++; } if (Level < CAPS_LEVEL_CHROOTED) { CapSet[NumCapsSet] = CAP_SYS_CHROOT; NumCapsSet++; CapSet[NumCapsSet] = CAP_FOWNER; NumCapsSet++; CapSet[NumCapsSet] = CAP_DAC_OVERRIDE; NumCapsSet++; } if (Level==CAPS_LEVEL_STARTUP) { CapSet[NumCapsSet] = CAP_NET_BIND_SERVICE; NumCapsSet++; } cap=cap_init(); if (cap_set_flag(cap, CAP_EFFECTIVE, NumCapsSet, CapSet, CAP_SET) == -1) ; if (cap_set_flag(cap, CAP_PERMITTED, NumCapsSet, CapSet, CAP_SET) == -1) ; if (cap_set_flag(cap, CAP_INHERITABLE, NumCapsSet, CapSet, CAP_SET) == -1) ; cap_set_proc(cap); #else //if libcap is not available try linux-only interface #include <linux/capability.h> struct __user_cap_header_struct cap_hdr; cap_user_data_t cap_values; unsigned long CapVersions[]={ _LINUX_CAPABILITY_VERSION_3, _LINUX_CAPABILITY_VERSION_2, _LINUX_CAPABILITY_VERSION_1, 0}; int val=0, i, result; //the CAP_ values are not bitmask flags, but instead indexes, so we have //to use shift to get the appropriate flag value if (Level < CAPS_LEVEL_SESSION) { val |=(1 << CAP_CHOWN); val |=(1 << CAP_SETUID); val |=(1 << CAP_SETGID); } if (Level < CAPS_LEVEL_CHROOTED) { val |= (1 << CAP_SYS_CHROOT); val |= (1 << CAP_FOWNER); val |= (1 << CAP_DAC_OVERRIDE); } if (Level==CAPS_LEVEL_STARTUP) val |= (1 << CAP_NET_BIND_SERVICE); for (i=0; CapVersions[i] > 0; i++) { cap_hdr.version=CapVersions[i]; cap_hdr.pid=0; //Horrible cludgy interface. V1 uses 32bit, V2 uses 64 bit, and somehow spreads this over //two __user_cap_data_struct items if (CapVersions[i]==_LINUX_CAPABILITY_VERSION_1) cap_values=calloc(1,sizeof(struct __user_cap_data_struct)); else cap_values=calloc(2,sizeof(struct __user_cap_data_struct)); cap_values->effective=val; cap_values->permitted=val; cap_values->inheritable=val; result=capset(&cap_hdr, cap_values); free(cap_values); if (result == 0) break; } #endif #endif }
int main(int argc, char *argv[]) { struct sigaction sigact; int do_add_date = 0; int do_compress = 0; int do_vibrate = 1; char* use_outfile = 0; char* begin_sound = 0; char* end_sound = 0; int use_socket = 0; int do_fb = 0; if (getuid() != 0) { // Old versions of the adb client would call the // dumpstate command directly. Newer clients // call /system/bin/bugreport instead. If we detect // we're being called incorrectly, then exec the // correct program. return execl("/system/bin/bugreport", "/system/bin/bugreport", NULL); } ALOGI("begin\n"); memset(&sigact, 0, sizeof(sigact)); sigact.sa_handler = sigpipe_handler; sigaction(SIGPIPE, &sigact, NULL); /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); FILE *oom_adj = fopen("/proc/self/oom_adj", "w"); if (oom_adj) { fputs("-17", oom_adj); fclose(oom_adj); } /* very first thing, collect stack traces from Dalvik and native processes (needs root) */ dump_traces_path = dump_traces(); int c; while ((c = getopt(argc, argv, "b:de:ho:svqzp")) != -1) { switch (c) { case 'b': begin_sound = optarg; break; case 'd': do_add_date = 1; break; case 'e': end_sound = optarg; break; case 'o': use_outfile = optarg; break; case 's': use_socket = 1; break; case 'v': break; // compatibility no-op case 'q': do_vibrate = 0; break; case 'z': do_compress = 6; break; case 'p': do_fb = 1; break; case '?': printf("\n"); case 'h': usage(); exit(1); } } FILE *vibrator = 0; if (do_vibrate) { /* open the vibrator before dropping root */ vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w"); if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC); } /* read /proc/cmdline before dropping root */ FILE *cmdline = fopen("/proc/cmdline", "r"); if (cmdline != NULL) { fgets(cmdline_buf, sizeof(cmdline_buf), cmdline); fclose(cmdline); } if (prctl(PR_SET_KEEPCAPS, 1) < 0) { ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); return -1; } /* switch to non-root user and group */ gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW, AID_MOUNT, AID_INET, AID_NET_BW_STATS }; if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); return -1; } if (setgid(AID_SHELL) != 0) { ALOGE("Unable to setgid, aborting: %s\n", strerror(errno)); return -1; } if (setuid(AID_SHELL) != 0) { ALOGE("Unable to setuid, aborting: %s\n", strerror(errno)); return -1; } struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG); capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG); capdata[0].inheritable = 0; capdata[1].inheritable = 0; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); return -1; } char path[PATH_MAX], tmp_path[PATH_MAX]; pid_t gzip_pid = -1; if (use_socket) { redirect_to_socket(stdout, "dumpstate"); } else if (use_outfile) { strlcpy(path, use_outfile, sizeof(path)); if (do_add_date) { char date[80]; time_t now = time(NULL); strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now)); strlcat(path, date, sizeof(path)); } if (do_fb) { strlcpy(screenshot_path, path, sizeof(screenshot_path)); strlcat(screenshot_path, ".png", sizeof(screenshot_path)); } strlcat(path, ".txt", sizeof(path)); if (do_compress) strlcat(path, ".gz", sizeof(path)); strlcpy(tmp_path, path, sizeof(tmp_path)); strlcat(tmp_path, ".tmp", sizeof(tmp_path)); gzip_pid = redirect_to_file(stdout, tmp_path, do_compress); } if (begin_sound) { play_sound(begin_sound); } else if (vibrator) { fputs("150", vibrator); fflush(vibrator); } dumpstate(); if (end_sound) { play_sound(end_sound); } else if (vibrator) { int i; for (i = 0; i < 3; i++) { fputs("75\n", vibrator); fflush(vibrator); usleep((75 + 50) * 1000); } fclose(vibrator); } /* wait for gzip to finish, otherwise it might get killed when we exit */ if (gzip_pid > 0) { fclose(stdout); waitpid(gzip_pid, NULL, 0); } /* rename the (now complete) .tmp file to its final location */ if (use_outfile && rename(tmp_path, path)) { fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno)); } ALOGI("done\n"); return 0; }
int main(int argc, char* argv[]) { // Check arguments. if (argc < 2) { error(1, 0, "usage: run-as <package-name> [--user <uid>] <command> [<args>]\n"); } // This program runs with CAP_SETUID and CAP_SETGID capabilities on Android // production devices. Check user id of caller --- must be 'shell' or 'root'. if (getuid() != AID_SHELL && getuid() != AID_ROOT) { error(1, 0, "only 'shell' or 'root' users can run this program"); } __user_cap_header_struct capheader; __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID); capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID); capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); if (capset(&capheader, &capdata[0]) == -1) { error(1, errno, "couldn't set capabilities"); } char* pkgname = argv[1]; int cmd_argv_offset = 2; // Get user_id from command line if provided. int userId = 0; if ((argc >= 4) && !strcmp(argv[2], "--user")) { userId = atoi(argv[3]); if (userId < 0) error(1, 0, "negative user id: %d", userId); cmd_argv_offset += 2; } // Retrieve package information from system, switching egid so we can read the file. gid_t old_egid = getegid(); if (setegid(AID_PACKAGE_INFO) == -1) error(1, errno, "setegid(AID_PACKAGE_INFO) failed"); pkg_info info; memset(&info, 0, sizeof(info)); info.name = pkgname; if (!packagelist_parse(packagelist_parse_callback, &info)) { error(1, errno, "packagelist_parse failed"); } if (info.uid == 0) { error(1, 0, "unknown package: %s", pkgname); } if (setegid(old_egid) == -1) error(1, errno, "couldn't restore egid"); // Verify that user id is not too big. if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) { error(1, 0, "user id too big: %d", userId); } // Calculate user app ID. uid_t userAppId = (AID_USER * userId) + info.uid; // Reject system packages. if (userAppId < AID_APP) { error(1, 0, "package not an application: %s", pkgname); } // Reject any non-debuggable package. if (!info.debuggable) { error(1, 0, "package not debuggable: %s", pkgname); } // Check that the data directory path is valid. if (!check_data_path(info.data_dir, userAppId)) { error(1, 0, "package has corrupt installation: %s", pkgname); } // Ensure that we change all real/effective/saved IDs at the // same time to avoid nasty surprises. uid_t uid = userAppId; uid_t gid = userAppId; if (setresgid(gid, gid, gid) == -1) { error(1, errno, "setresgid failed"); } if (setresuid(uid, uid, uid) == -1) { error(1, errno, "setresuid failed"); } // Required if caller has uid and gid all non-zero. memset(&capdata, 0, sizeof(capdata)); if (capset(&capheader, &capdata[0]) == -1) { error(1, errno, "couldn't clear all capabilities"); } if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { error(1, errno, "couldn't set SELinux security context"); } // cd into the data directory, and set $HOME correspondingly. if (TEMP_FAILURE_RETRY(chdir(info.data_dir)) == -1) { error(1, errno, "couldn't chdir to package's data directory"); } setenv("HOME", info.data_dir, 1); // Reset parts of the environment, like su would. setenv("PATH", _PATH_DEFPATH, 1); unsetenv("IFS"); // Set the user-specific parts for this user. passwd* pw = getpwuid(uid); setenv("LOGNAME", pw->pw_name, 1); setenv("SHELL", pw->pw_shell, 1); setenv("USER", pw->pw_name, 1); // User specified command for exec. if ((argc >= cmd_argv_offset + 1) && (execvp(argv[cmd_argv_offset], argv+cmd_argv_offset) == -1)) { error(1, errno, "exec failed for %s", argv[cmd_argv_offset]); } // Default exec shell. execlp(_PATH_BSHELL, "sh", NULL); error(1, errno, "exec failed"); }
int main(int argc, char **argv) { bool fork_desired = TRUE; bool log_to_stderr_desired = FALSE; bool nat_traversal = FALSE; bool nat_t_spf = TRUE; /* support port floating */ unsigned int keep_alive = 0; bool force_keepalive = FALSE; char *virtual_private = NULL; int lockfd; #ifdef CAPABILITIES int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE }; #endif /* CAPABILITIES */ /* initialize library and optionsfrom */ if (!library_init(NULL)) { library_deinit(); exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } if (!libhydra_init("pluto")) { libhydra_deinit(); library_deinit(); exit(SS_RC_INITIALIZATION_FAILED); } if (!pluto_init(argv[0])) { pluto_deinit(); libhydra_deinit(); library_deinit(); exit(SS_RC_DAEMON_INTEGRITY); } options = options_create(); /* handle arguments */ for (;;) { # define DBG_OFFSET 256 static const struct option long_opts[] = { /* name, has_arg, flag, val */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "optionsfrom", required_argument, NULL, '+' }, { "nofork", no_argument, NULL, 'd' }, { "stderrlog", no_argument, NULL, 'e' }, { "nocrsend", no_argument, NULL, 'c' }, { "strictcrlpolicy", no_argument, NULL, 'r' }, { "crlcheckinterval", required_argument, NULL, 'x'}, { "cachecrls", no_argument, NULL, 'C' }, { "uniqueids", no_argument, NULL, 'u' }, { "disableuniqreqids", no_argument, NULL, 'Z'}, { "interface", required_argument, NULL, 'i' }, { "ikeport", required_argument, NULL, 'p' }, { "ctlbase", required_argument, NULL, 'b' }, { "secretsfile", required_argument, NULL, 's' }, { "foodgroupsdir", required_argument, NULL, 'f' }, { "perpeerlogbase", required_argument, NULL, 'P' }, { "perpeerlog", no_argument, NULL, 'l' }, { "policygroupsdir", required_argument, NULL, 'f' }, #ifdef USE_LWRES { "lwdnsq", required_argument, NULL, 'a' }, #else /* !USE_LWRES */ { "adns", required_argument, NULL, 'a' }, #endif /* !USE_LWRES */ { "pkcs11module", required_argument, NULL, 'm' }, { "pkcs11keepstate", no_argument, NULL, 'k' }, { "pkcs11initargs", required_argument, NULL, 'z' }, { "pkcs11proxy", no_argument, NULL, 'y' }, { "nat_traversal", no_argument, NULL, '1' }, { "keep_alive", required_argument, NULL, '2' }, { "force_keepalive", no_argument, NULL, '3' }, { "disable_port_floating", no_argument, NULL, '4' }, { "debug-natt", no_argument, NULL, '5' }, { "virtual_private", required_argument, NULL, '6' }, #ifdef DEBUG { "debug-none", no_argument, NULL, 'N' }, { "debug-all", no_argument, NULL, 'A' }, { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET }, { "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET }, { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET }, { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET }, { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET }, { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET }, { "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, { "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET }, { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET }, { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET }, { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET }, { "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET }, { "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET }, { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET }, { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET }, #endif { 0,0,0,0 } }; /* Note: we don't like the way short options get parsed * by getopt_long, so we simply pass an empty string as * the list. It could be "hvdenp:l:s:" "NARXPECK". */ int c = getopt_long(argc, argv, "", long_opts, NULL); /* Note: "breaking" from case terminates loop */ switch (c) { case EOF: /* end of flags */ break; case 0: /* long option already handled */ continue; case ':': /* diagnostic already printed by getopt_long */ case '?': /* diagnostic already printed by getopt_long */ usage(""); break; /* not actually reached */ case 'h': /* --help */ usage(NULL); break; /* not actually reached */ case 'v': /* --version */ { const char **sp = ipsec_copyright_notice(); printf("strongSwan "VERSION"%s\n", compile_time_interop_options); for (; *sp != NULL; sp++) puts(*sp); } exit_pluto(0); break; /* not actually reached */ case '+': /* --optionsfrom <filename> */ if (!options->from(options, optarg, &argc, &argv, optind)) { exit_pluto(1); } continue; case 'd': /* --nofork*/ fork_desired = FALSE; continue; case 'e': /* --stderrlog */ log_to_stderr_desired = TRUE; continue; case 'c': /* --nocrsend */ no_cr_send = TRUE; continue; case 'r': /* --strictcrlpolicy */ strict_crl_policy = TRUE; continue; case 'x': /* --crlcheckinterval <time>*/ if (optarg == NULL || !isdigit(optarg[0])) usage("missing interval time"); { char *endptr; long interval = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || interval <= 0) usage("<interval-time> must be a positive number"); crl_check_interval = interval; } continue; case 'C': /* --cachecrls */ cache_crls = TRUE; continue; case 'u': /* --uniqueids */ uniqueIDs = TRUE; continue; case 'Z': /* --disableuniqreqids */ disable_uniqreqids = TRUE; continue; case 'i': /* --interface <ifname> */ if (!use_interface(optarg)) usage("too many --interface specifications"); continue; case 'p': /* --port <portnumber> */ if (optarg == NULL || !isdigit(optarg[0])) usage("missing port number"); { char *endptr; long port = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || port <= 0 || port > 0x10000) usage("<port-number> must be a number between 1 and 65535"); pluto_port = port; } continue; case 'b': /* --ctlbase <path> */ if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path) , "%s%s", optarg, CTL_SUFFIX) == -1) usage("<path>" CTL_SUFFIX " too long for sun_path"); if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path) , "%s%s", optarg, INFO_SUFFIX) == -1) usage("<path>" INFO_SUFFIX " too long for sun_path"); if (snprintf(pluto_lock, sizeof(pluto_lock) , "%s%s", optarg, LOCK_SUFFIX) == -1) usage("<path>" LOCK_SUFFIX " must fit"); continue; case 's': /* --secretsfile <secrets-file> */ shared_secrets_file = optarg; continue; case 'f': /* --policygroupsdir <policygroups-dir> */ policygroups_dir = optarg; continue; case 'a': /* --adns <pathname> */ pluto_adns_option = optarg; continue; case 'm': /* --pkcs11module <pathname> */ pkcs11_module_path = optarg; continue; case 'k': /* --pkcs11keepstate */ pkcs11_keep_state = TRUE; continue; case 'y': /* --pkcs11proxy */ pkcs11_proxy = TRUE; continue; case 'z': /* --pkcs11initargs */ pkcs11_init_args = optarg; continue; #ifdef DEBUG case 'N': /* --debug-none */ base_debugging = DBG_NONE; continue; case 'A': /* --debug-all */ base_debugging = DBG_ALL; continue; #endif case 'P': /* --perpeerlogbase */ base_perpeer_logdir = optarg; continue; case 'l': log_to_perpeer = TRUE; continue; case '1': /* --nat_traversal */ nat_traversal = TRUE; continue; case '2': /* --keep_alive */ keep_alive = atoi(optarg); continue; case '3': /* --force_keepalive */ force_keepalive = TRUE; continue; case '4': /* --disable_port_floating */ nat_t_spf = FALSE; continue; case '5': /* --debug-nat_t */ base_debugging |= DBG_NATT; continue; case '6': /* --virtual_private */ virtual_private = optarg; continue; default: #ifdef DEBUG if (c >= DBG_OFFSET) { base_debugging |= c - DBG_OFFSET; continue; } # undef DBG_OFFSET #endif bad_case(c); } break; } if (optind != argc) usage("unexpected argument"); reset_debugging(); lockfd = create_lock(); /* select between logging methods */ if (log_to_stderr_desired) { log_to_syslog = FALSE; } else { log_to_stderr = FALSE; } /* set the logging function of pfkey debugging */ #ifdef DEBUG pfkey_debug_func = DBG_log; #else pfkey_debug_func = NULL; #endif /* create control socket. * We must create it before the parent process returns so that * there will be no race condition in using it. The easiest * place to do this is before the daemon fork. */ { err_t ugh = init_ctl_socket(); if (ugh != NULL) { fprintf(stderr, "pluto: %s", ugh); exit_pluto(1); } } /* If not suppressed, do daemon fork */ if (fork_desired) { { pid_t pid = fork(); if (pid < 0) { int e = errno; fprintf(stderr, "pluto: fork failed (%d %s)\n", errno, strerror(e)); exit_pluto(1); } if (pid != 0) { /* parent: die, after filling PID into lock file. * must not use exit_pluto: lock would be removed! */ exit(fill_lock(lockfd, pid)? 0 : 1); } } if (setsid() < 0) { int e = errno; fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n", errno, strerror(e)); exit_pluto(1); } } else { /* no daemon fork: we have to fill in lock file */ (void) fill_lock(lockfd, getpid()); fprintf(stdout, "Pluto initialized\n"); fflush(stdout); } /* Redirect stdin, stdout and stderr to /dev/null */ { int fd; if ((fd = open("/dev/null", O_RDWR)) == -1) abort(); if (dup2(fd, 0) != 0) abort(); if (dup2(fd, 1) != 1) abort(); if (!log_to_stderr && dup2(fd, 2) != 2) abort(); close(fd); } init_constants(); init_log("pluto"); /* Note: some scripts may look for this exact message -- don't change * ipsec barf was one, but it no longer does. */ plog("Starting IKEv1 pluto daemon (strongSwan "VERSION")%s", compile_time_interop_options); if (lib->integrity) { plog("integrity tests enabled:"); plog("lib 'libstrongswan': passed file and segment integrity tests"); plog("lib 'libhydra': passed file and segment integrity tests"); plog("daemon 'pluto': passed file integrity test"); } /* load plugins, further infrastructure may need it */ if (!lib->plugins->load(lib->plugins, NULL, lib->settings->get_str(lib->settings, "pluto.load", PLUGINS))) { exit(SS_RC_INITIALIZATION_FAILED); } print_plugins(); init_builder(); if (!init_secret() || !init_crypto()) { plog("initialization failed - aborting pluto"); exit_pluto(SS_RC_INITIALIZATION_FAILED); } init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf); init_virtual_ip(virtual_private); scx_init(pkcs11_module_path, pkcs11_init_args); init_states(); init_demux(); init_kernel(); init_adns(); init_myid(); fetch_initialize(); ac_initialize(); whack_attribute_initialize(); /* drop unneeded capabilities and change UID/GID */ prctl(PR_SET_KEEPCAPS, 1); #ifdef IPSEC_GROUP { struct group group, *grp; char buf[1024]; if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 || grp == NULL || setgid(grp->gr_gid) != 0) { plog("unable to change daemon group"); abort(); } } #endif #ifdef IPSEC_USER { struct passwd passwd, *pwp; char buf[1024]; if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 || pwp == NULL || setuid(pwp->pw_uid) != 0) { plog("unable to change daemon user"); abort(); } } #endif #ifdef CAPABILITIES_LIBCAP { cap_t caps; caps = cap_init(); cap_set_flag(caps, CAP_EFFECTIVE, countof(keep), keep, CAP_SET); cap_set_flag(caps, CAP_INHERITABLE, countof(keep), keep, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, countof(keep), keep, CAP_SET); if (cap_set_proc(caps) != 0) { plog("unable to drop daemon capabilities"); abort(); } cap_free(caps); } #endif /* CAPABILITIES_LIBCAP */ #ifdef CAPABILITIES_NATIVE { struct __user_cap_data_struct caps = { .effective = 0 }; struct __user_cap_header_struct header = { .version = _LINUX_CAPABILITY_VERSION, }; int i; for (i = 0; i < countof(keep); i++) { caps.effective |= 1 << keep[i]; caps.permitted |= 1 << keep[i]; caps.inheritable |= 1 << keep[i]; } if (capset(&header, &caps) != 0) { plog("unable to drop daemon capabilities"); abort(); } } #endif /* CAPABILITIES_NATIVE */ /* loading X.509 CA certificates */ load_authcerts("ca", CA_CERT_PATH, X509_CA); /* loading X.509 AA certificates */ load_authcerts("aa", AA_CERT_PATH, X509_AA); /* loading X.509 OCSP certificates */ load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER); /* loading X.509 CRLs */ load_crls(); /* loading attribute certificates (experimental) */ ac_load_certs(); lib->processor->set_threads(lib->processor, lib->settings->get_int(lib->settings, "pluto.threads", DEFAULT_THREADS)); daily_log_event(); call_server(); return -1; /* Shouldn't ever reach this */ } /* leave pluto, with status. * Once child is launched, parent must not exit this way because * the lock would be released. * * 0 OK * 1 general discomfort * 10 lock file exists */ void exit_pluto(int status) { lib->processor->set_threads(lib->processor, 0); reset_globals(); /* needed because we may be called in odd state */ free_preshared_secrets(); free_remembered_public_keys(); delete_every_connection(); whack_attribute_finalize(); /* free in-memory pools */ kernel_finalize(); fetch_finalize(); /* stop fetching thread */ free_crl_fetch(); /* free chain of crl fetch requests */ free_ocsp_fetch(); /* free chain of ocsp fetch requests */ free_authcerts(); /* free chain of X.509 authority certificates */ free_crls(); /* free chain of X.509 CRLs */ free_ca_infos(); /* free chain of X.509 CA information records */ free_ocsp(); /* free ocsp cache */ free_ifaces(); ac_finalize(); /* free X.509 attribute certificates */ scx_finalize(); /* finalize and unload PKCS #11 module */ stop_adns(); free_md_pool(); free_crypto(); free_myid(); /* free myids */ free_events(); /* free remaining events */ free_vendorid(); /* free all vendor id records */ free_builder(); delete_lock(); options->destroy(options); pluto_deinit(); lib->plugins->unload(lib->plugins); libhydra_deinit(); library_deinit(); close_log(); exit(status); }
int main(void) { int retVal; pthread_attr_t attr; struct sched_param schedParam; pthread_t thread; struct __user_cap_header_struct cap_header_data; cap_user_header_t cap_header = &cap_header_data; struct __user_cap_data_struct cap_data_data; cap_user_data_t cap_data = &cap_data_data; int ret; if (setresuid(0, 0, 0)) { fprintf(stderr, "Cannot switch to root: %s.\n", strerror(errno)); return 1; } cap_header->pid = getpid(); cap_header->version = _LINUX_CAPABILITY_VERSION; if (capget(cap_header, cap_data) < 0) { perror("Failed capget"); exit(1); } printf("Cap data 0x%x, 0x%x, 0x%x\n", cap_data->effective, cap_data->permitted, cap_data->inheritable); /* Clear all but the capability to bind to low ports */ cap_data->effective |= CAP_TO_MASK(CAP_SYS_ADMIN) | CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SYS_NICE); cap_data->permitted |= CAP_TO_MASK(CAP_SYS_ADMIN) | CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SYS_NICE); cap_data->inheritable |= CAP_TO_MASK(CAP_SYS_ADMIN) | CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SYS_NICE); if (capset(cap_header, cap_data) < 0) printf("capset failed"); printf("Cap data 0x%x, 0x%x, 0x%x\n", cap_data->effective, cap_data->permitted, cap_data->inheritable); ret = nice(-1); printf("nice: %d\n", ret); /* Tell kernel not clear capabilities when dropping root */ if (prctl(PR_SET_KEEPCAPS, 1) < 0) printf("prctl(PR_SET_KEEPCAPS) failed "); setresuid(1000,1000,1000); printf("setresuid\n"); /* Clear all but the capability to bind to low ports */ cap_data->effective |= CAP_TO_MASK(CAP_SYS_ADMIN) | CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SYS_NICE); cap_data->permitted |= CAP_TO_MASK(CAP_SYS_ADMIN) | CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SYS_NICE); cap_data->inheritable |= CAP_TO_MASK(CAP_SYS_ADMIN) | CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SYS_NICE); if (capset(cap_header, cap_data) < 0) printf("capset failed"); printf("Cap data 0x%x, 0x%x, 0x%x\n", cap_data->effective, cap_data->permitted, cap_data->inheritable); retVal = pthread_attr_init(&attr); if (retVal) { fprintf(stderr, "pthread_attr_init error %d\n", retVal); exit(1); } retVal = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if (retVal) { fprintf(stderr, "pthread_attr_setinheritsched error %d\n", retVal); exit(1); } retVal = pthread_attr_setschedpolicy(&attr, SCHED_RR); if (retVal) { fprintf(stderr, "pthread_attr_setschedpolicy error %d\n", retVal); exit(1); } schedParam.sched_priority = 99; retVal = pthread_attr_setschedparam(&attr, &schedParam); if (retVal) { fprintf(stderr, "pthread_attr_setschedparam error %d\n", retVal); exit(1); } retVal = pthread_create(&thread, &attr, _Thread, NULL); if (retVal) { fprintf(stderr, "pthread_create error %d\n", retVal); exit(1); } retVal = pthread_join(thread, NULL); if (retVal) { fprintf(stderr, "pthread_join error %d\n", retVal); exit(1); } printf("main run successfully\n"); return 0; }
/** * Drop any root privileges we might be holding. */ static void supR3HardenedMainDropPrivileges(void) { /* * Try use setre[ug]id since this will clear the save uid/gid and thus * leave fewer traces behind that libs like GTK+ may pick up. */ uid_t euid, ruid, suid; gid_t egid, rgid, sgid; # if defined(RT_OS_DARWIN) /* The really great thing here is that setreuid isn't available on OS X 10.4, libc emulates it. While 10.4 have a slightly different and non-standard setuid implementation compared to 10.5, the following works the same way with both version since we're super user (10.5 req). The following will set all three variants of the group and user IDs. */ setgid(g_gid); setuid(g_uid); euid = geteuid(); ruid = suid = getuid(); egid = getegid(); rgid = sgid = getgid(); # elif defined(RT_OS_SOLARIS) /* Solaris doesn't have setresuid, but the setreuid interface is BSD compatible and will set the saved uid to euid when we pass it a ruid that isn't -1 (which we do). */ setregid(g_gid, g_gid); setreuid(g_uid, g_uid); euid = geteuid(); ruid = suid = getuid(); egid = getegid(); rgid = sgid = getgid(); # else /* This is the preferred one, full control no questions about semantics. PORTME: If this isn't work, try join one of two other gangs above. */ setresgid(g_gid, g_gid, g_gid); setresuid(g_uid, g_uid, g_uid); if (getresuid(&ruid, &euid, &suid) != 0) { euid = geteuid(); ruid = suid = getuid(); } if (getresgid(&rgid, &egid, &sgid) != 0) { egid = getegid(); rgid = sgid = getgid(); } # endif /* Check that it worked out all right. */ if ( euid != g_uid || ruid != g_uid || suid != g_uid || egid != g_gid || rgid != g_gid || sgid != g_gid) supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!" " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n", euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid); # if RT_OS_LINUX /* * Re-enable the cap_net_raw capability which was disabled during setresuid. */ if (g_uCaps != 0) { # ifdef USE_LIB_PCAP /** @todo Warn if that does not work? */ /* XXX cap_net_bind_service */ cap_set_proc(cap_from_text("cap_net_raw+ep")); # else cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr)); cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap)); memset(hdr, 0, sizeof(*hdr)); hdr->version = _LINUX_CAPABILITY_VERSION; memset(cap, 0, sizeof(*cap)); cap->effective = g_uCaps; cap->permitted = g_uCaps; /** @todo Warn if that does not work? */ capset(hdr, cap); # endif /* !USE_LIB_PCAP */ } # endif }
/** * Grabs extra non-root capabilities / privileges that we might require. * * This is currently only used for being able to do ICMP from the NAT engine. * * @note We still have root privileges at the time of this call. */ static void supR3HardenedMainGrabCapabilites(void) { # if defined(RT_OS_LINUX) /* * We are about to drop all our privileges. Remove all capabilities but * keep the cap_net_raw capability for ICMP sockets for the NAT stack. */ if (g_uCaps != 0) { # ifdef USE_LIB_PCAP /* XXX cap_net_bind_service */ if (!cap_set_proc(cap_from_text("all-eip cap_net_raw+ep"))) prctl(PR_SET_KEEPCAPS, 1 /*keep=*/, 0, 0, 0); prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0); # else cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr)); cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap)); memset(hdr, 0, sizeof(*hdr)); hdr->version = _LINUX_CAPABILITY_VERSION; memset(cap, 0, sizeof(*cap)); cap->effective = g_uCaps; cap->permitted = g_uCaps; if (!capset(hdr, cap)) prctl(PR_SET_KEEPCAPS, 1 /*keep*/, 0, 0, 0); prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0); # endif /* !USE_LIB_PCAP */ } # elif defined(RT_OS_SOLARIS) /* * Add net_icmpaccess privilege to effective privileges and limit * permitted privileges before completely dropping root privileges. * This requires dropping root privileges temporarily to get the normal * user's privileges. */ seteuid(g_uid); priv_set_t *pPrivEffective = priv_allocset(); priv_set_t *pPrivNew = priv_allocset(); if (pPrivEffective && pPrivNew) { int rc = getppriv(PRIV_EFFECTIVE, pPrivEffective); seteuid(0); if (!rc) { priv_copyset(pPrivEffective, pPrivNew); rc = priv_addset(pPrivNew, PRIV_NET_ICMPACCESS); if (!rc) { /* Order is important, as one can't set a privilege which is * not in the permitted privilege set. */ rc = setppriv(PRIV_SET, PRIV_EFFECTIVE, pPrivNew); if (rc) supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set effective privilege set.\n"); rc = setppriv(PRIV_SET, PRIV_PERMITTED, pPrivNew); if (rc) supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set permitted privilege set.\n"); } else supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to add NET_ICMPACCESS privilege.\n"); } } else { /* for memory allocation failures just continue */ seteuid(0); } if (pPrivEffective) priv_freeset(pPrivEffective); if (pPrivNew) priv_freeset(pPrivNew); # endif }
/* * The ruid refers to the caller's uid and is used to reset the effective uid * back to the callers real uid. * This clutch mainly exists for setuid-based new{g,u}idmap binaries that are * called in contexts where all capabilities other than the necessary * CAP_SET{G,U}ID capabilities are dropped. Since the kernel will require * assurance that the caller holds CAP_SYS_ADMIN over the target user namespace * the only way it can confirm is in this case is if the effective uid is * equivalent to the uid owning the target user namespace. * Note, we only support this when a) new{g,u}idmap is not called by root and * b) if the caller's uid and the uid retrieved via system appropriate means * (shadow file or other) are identical. Specifically, this does not support * when the root user calls the new{g,u}idmap binary for an unprivileged user. * If this is wanted: use file capabilities! */ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings, const char *map_file, uid_t ruid) { int idx; struct map_range *mapping; size_t bufsize; char *buf, *pos; int fd; #if HAVE_SYS_CAPABILITY_H int cap; struct __user_cap_header_struct hdr = {_LINUX_CAPABILITY_VERSION_3, 0}; struct __user_cap_data_struct data[2] = {{0}}; if (strcmp(map_file, "uid_map") == 0) { cap = CAP_SETUID; } else if (strcmp(map_file, "gid_map") == 0) { cap = CAP_SETGID; } else { fprintf(stderr, _("%s: Invalid map file %s specified\n"), Prog, map_file); exit(EXIT_FAILURE); } /* Align setuid- and fscaps-based new{g,u}idmap behavior. */ if (geteuid() == 0 && geteuid() != ruid) { if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { fprintf(stderr, _("%s: Could not prctl(PR_SET_KEEPCAPS)\n"), Prog); exit(EXIT_FAILURE); } if (seteuid(ruid) < 0) { fprintf(stderr, _("%s: Could not seteuid to %d\n"), Prog, ruid); exit(EXIT_FAILURE); } } /* Lockdown new{g,u}idmap by dropping all unneeded capabilities. */ memset(data, 0, sizeof(data)); data[0].effective = CAP_TO_MASK(cap); data[0].permitted = data[0].effective; if (capset(&hdr, data) < 0) { fprintf(stderr, _("%s: Could not set caps\n"), Prog); exit(EXIT_FAILURE); } #endif bufsize = ranges * ((ULONG_DIGITS + 1) * 3); pos = buf = xmalloc(bufsize); /* Build the mapping command */ mapping = mappings; for (idx = 0; idx < ranges; idx++, mapping++) { /* Append this range to the string that will be written */ int written = snprintf(pos, bufsize - (pos - buf), "%lu %lu %lu\n", mapping->upper, mapping->lower, mapping->count); if ((written <= 0) || (written >= (bufsize - (pos - buf)))) { fprintf(stderr, _("%s: snprintf failed!\n"), Prog); exit(EXIT_FAILURE); } pos += written; } /* Write the mapping to the mapping file */ fd = openat(proc_dir_fd, map_file, O_WRONLY); if (fd < 0) { fprintf(stderr, _("%s: open of %s failed: %s\n"), Prog, map_file, strerror(errno)); exit(EXIT_FAILURE); } if (write(fd, buf, pos - buf) != (pos - buf)) { fprintf(stderr, _("%s: write to %s failed: %s\n"), Prog, map_file, strerror(errno)); exit(EXIT_FAILURE); } close(fd); }
int adb_main(int is_daemon, int server_port) { #if !ADB_HOST int secure = 0; int port; char value[PROPERTY_VALUE_MAX]; #endif atexit(adb_cleanup); #ifdef HAVE_WIN32_PROC SetConsoleCtrlHandler( ctrlc_handler, TRUE ); #elif defined(HAVE_FORKEXEC) signal(SIGCHLD, sigchld_handler); signal(SIGPIPE, SIG_IGN); #endif init_transport_registration(); #if ADB_HOST HOST = 1; usb_vendors_init(); usb_init(); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); if(install_listener(local_name, "*smartsocket*", NULL)) { exit(1); } #else /* run adbd in secure mode if ro.secure is set and ** we are not in the emulator */ property_get("ro.kernel.qemu", value, ""); if (strcmp(value, "1") != 0) { property_get("ro.secure", value, ""); if (strcmp(value, "1") == 0) { // don't run as root if ro.secure is set... secure = 1; // ... except we allow running as root in userdebug builds if the // service.adb.root property has been set by the "adb root" command property_get("ro.debuggable", value, ""); if (strcmp(value, "1") == 0) { property_get("service.adb.root", value, ""); if (strcmp(value, "1") == 0) { secure = 0; } } } } /* don't listen on a port (default 5037) if running in secure mode */ /* don't run as root if we are running in secure mode */ if (secure) { struct __user_cap_header_struct header; struct __user_cap_data_struct cap; if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) { exit(1); } /* add extra groups: ** AID_ADB to access the USB driver ** AID_LOG to read system logs (adb logcat) ** AID_INPUT to diagnose input issues (getevent) ** AID_INET to diagnose network issues (netcfg, ping) ** AID_GRAPHICS to access the frame buffer ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) ** AID_SDCARD_RW to allow writing to the SD card ** AID_MOUNT to allow unmounting the SD card before rebooting */ gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_RW, AID_MOUNT }; if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { exit(1); } /* then switch user and group to "shell" */ if (setgid(AID_SHELL) != 0) { exit(1); } if (setuid(AID_SHELL) != 0) { exit(1); } /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */ header.version = _LINUX_CAPABILITY_VERSION; header.pid = 0; cap.effective = cap.permitted = (1 << CAP_SYS_BOOT); cap.inheritable = 0; capset(&header, &cap); D("Local port disabled\n"); } else { char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); if(install_listener(local_name, "*smartsocket*", NULL)) { exit(1); } } /* for the device, start the usb transport if the ** android usb device exists and the "service.adb.tcp.port" and ** "persist.adb.tcp.port" properties are not set. ** Otherwise start the network transport. */ property_get("service.adb.tcp.port", value, ""); if (!value[0]) property_get("persist.adb.tcp.port", value, ""); if (sscanf(value, "%d", &port) == 1 && port > 0) { // listen on TCP port specified by service.adb.tcp.port property local_init(port); } else if (access("/dev/android_adb", F_OK) == 0) { // listen on USB usb_init(); } else { // listen on default port local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); } init_jdwp(); #endif if (is_daemon) { // inform our parent that we are up and running. #ifdef HAVE_WIN32_PROC DWORD count; WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); #elif defined(HAVE_FORKEXEC) fprintf(stderr, "OK\n"); #endif start_logging(); } fdevent_loop(); usb_cleanup(); return 0; }
int adb_main(int is_daemon, int server_port) { #if !ADB_HOST int port; char value[PROPERTY_VALUE_MAX]; umask(000); #endif atexit(adb_cleanup); #ifdef HAVE_WIN32_PROC SetConsoleCtrlHandler( ctrlc_handler, TRUE ); #elif defined(HAVE_FORKEXEC) // No SIGCHLD. Let the service subproc handle its children. signal(SIGPIPE, SIG_IGN); #endif init_transport_registration(); #if ADB_HOST HOST = 1; usb_vendors_init(); usb_init(); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); adb_auth_init(); char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); if(install_listener(local_name, "*smartsocket*", NULL, 0)) { exit(1); } #else property_get("ro.adb.secure", value, "0"); auth_enabled = !strcmp(value, "1"); if (auth_enabled) adb_auth_init(); // Our external storage path may be different than apps, since // we aren't able to bind mount after dropping root. const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE"); if (NULL != adb_external_storage) { setenv("EXTERNAL_STORAGE", adb_external_storage, 1); } else { D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE" " unchanged.\n"); } /* don't listen on a port (default 5037) if running in secure mode */ /* don't run as root if we are running in secure mode */ if (should_drop_privileges()) { struct __user_cap_header_struct header; struct __user_cap_data_struct cap[2]; if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) { exit(1); } /* add extra groups: ** AID_ADB to access the USB driver ** AID_LOG to read system logs (adb logcat) ** AID_INPUT to diagnose input issues (getevent) ** AID_INET to diagnose network issues (netcfg, ping) ** AID_GRAPHICS to access the frame buffer ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) ** AID_SDCARD_R to allow reading from the SD card ** AID_SDCARD_RW to allow writing to the SD card ** AID_MOUNT to allow unmounting the SD card before rebooting ** AID_NET_BW_STATS to read out qtaguid statistics */ gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, AID_MOUNT, AID_NET_BW_STATS }; if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { exit(1); } /* then switch user and group to "shell" */ if (setgid(AID_SHELL) != 0) { exit(1); } if (setuid(AID_SHELL) != 0) { exit(1); } memset(&header, 0, sizeof(header)); memset(cap, 0, sizeof(cap)); /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */ header.version = _LINUX_CAPABILITY_VERSION_3; header.pid = 0; cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT); cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT); capset(&header, cap); D("Local port disabled\n"); } else { char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); if(install_listener(local_name, "*smartsocket*", NULL, 0)) { exit(1); } } int usb = 0; if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) { // listen on USB usb_init(); usb = 1; } // If one of these properties is set, also listen on that port // If one of the properties isn't set and we couldn't listen on usb, // listen on the default port. property_get("service.adb.tcp.port", value, ""); if (!value[0]) { property_get("persist.adb.tcp.port", value, ""); } if (sscanf(value, "%d", &port) == 1 && port > 0) { printf("using port=%d\n", port); // listen on TCP port specified by service.adb.tcp.port property local_init(port); } else if (!usb) { // listen on default port local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); } D("adb_main(): pre init_jdwp()\n"); init_jdwp(); D("adb_main(): post init_jdwp()\n"); #endif if (is_daemon) { // inform our parent that we are up and running. #ifdef HAVE_WIN32_PROC DWORD count; WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); #elif defined(HAVE_FORKEXEC) fprintf(stderr, "OK\n"); #endif start_logging(); } D("Event loop starting\n"); fdevent_loop(); usb_cleanup(); return 0; }
int dexopt(const char *apk_path, uid_t uid, int is_public) { struct utimbuf ut; struct stat apk_stat, dex_stat; char out_path[PKG_PATH_MAX]; char dexopt_flags[PROPERTY_VALUE_MAX]; char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX]; char *end; int res, zip_fd=-1, out_fd=-1; if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { return -1; } /* platform-specific flags affecting optimization and verification */ property_get("dalvik.vm.dexopt-flags", dexopt_flags, ""); ALOGV("dalvik.vm.dexopt_flags=%s\n", dexopt_flags); /* The command to run depend ones the value of persist.sys.dalvik.vm.lib */ property_get("persist.sys.dalvik.vm.lib", persist_sys_dalvik_vm_lib, "libdvm.so"); /* Before anything else: is there a .odex file? If so, we have * precompiled the apk and there is nothing to do here. */ sprintf(out_path, "%s%s", apk_path, ".odex"); if (stat(out_path, &dex_stat) == 0) { return 0; } if (create_cache_path(out_path, apk_path)) { return -1; } memset(&apk_stat, 0, sizeof(apk_stat)); stat(apk_path, &apk_stat); zip_fd = open(apk_path, O_RDONLY, 0); if (zip_fd < 0) { ALOGE("installd cannot open '%s' for input during dexopt\n", apk_path); return -1; } unlink(out_path); out_fd = open(out_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (out_fd < 0) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_path); goto fail; } if (fchmod(out_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { ALOGE("installd cannot chmod '%s' during dexopt\n", out_path); goto fail; } if (fchown(out_fd, AID_SYSTEM, uid) < 0) { ALOGE("installd cannot chown '%s' during dexopt\n", out_path); goto fail; } ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { ALOGE("setgid(%d) failed in installd during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { ALOGE("setuid(%d) failed in installd during dexopt\n", uid); exit(65); } // drop capabilities struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); exit(66); } if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno)); exit(67); } if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) { run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags); } else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) { run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags); } else { exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */ } exit(68); /* only get here on exec failure */ } else { res = wait_child(pid); if (res == 0) { ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path); } else { ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res); goto fail; } } ut.actime = apk_stat.st_atime; ut.modtime = apk_stat.st_mtime; utime(out_path, &ut); close(out_fd); close(zip_fd); return 0; fail: if (out_fd >= 0) { close(out_fd); unlink(out_path); } if (zip_fd >= 0) { close(zip_fd); } return -1; }