/* * switchUser - Switches UID to radio, preserving CAP_NET_ADMIN capabilities. * Our group, cache, was set by init. */ void switchUser() { char debuggable[PROP_VALUE_MAX]; 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); } /* * Debuggable build only: * Set DUMPABLE that was cleared by setuid() to have tombstone on RIL crash */ property_get("ro.debuggable", debuggable, "0"); if (strcmp(debuggable, "1") == 0) { prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); } }
int check_capabilities() { struct __user_cap_header_struct cap_header; struct __user_cap_data_struct cap_data; cap_header.pid = getpid(); cap_header.version = _LINUX_CAPABILITY_VERSION; /* Check if oor is already running: /var/run/oor.pid */ if (capget(&cap_header, &cap_data) < 0) { OOR_LOG(LCRIT, "Could not retrieve capabilities"); return BAD; } OOR_LOG(LWRN, "Rights: Effective [%u] Permitted [%u]", cap_data.effective, cap_data.permitted); /* check for capabilities */ if( (cap_data.effective & CAP_TO_MASK(CAP_NET_ADMIN)) && (cap_data.effective & CAP_TO_MASK(CAP_NET_RAW)) ) { } else { OOR_LOG(LCRIT, "Insufficient rights, you need CAP_NET_ADMIN and CAP_NET_RAW. See README"); return BAD; } return GOOD; }
static void drop_capabilities_bounding_set_if_needed(struct minijail *j) { if (ALLOW_ADBD_ROOT || is_device_unlocked()) { if (__android_log_is_debuggable()) { return; } } minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID)); }
static void lower_my_caps(void) { struct __user_cap_header_struct caphdr = { .version = _LINUX_CAPABILITY_VERSION }; cap_user_data_t capdata; ssize_t capstrlen = 0; cap_t my_cap; char *cap_text; int capsz; (void) capget(&caphdr, NULL); switch (caphdr.version) { case _LINUX_CAPABILITY_VERSION_1: capsz = _LINUX_CAPABILITY_U32S_1; break; case _LINUX_CAPABILITY_VERSION_2: capsz = _LINUX_CAPABILITY_U32S_2; break; default: abort(); /* can't happen */ } capdata = gsh_calloc(capsz, sizeof(struct __user_cap_data_struct)); caphdr.pid = getpid(); if (capget(&caphdr, capdata) != 0) LogFatal(COMPONENT_INIT, "Failed to query capabilities for process, errno=%u", errno); /* Set the capability bitmask to remove CAP_SYS_RESOURCE */ if (capdata->effective & CAP_TO_MASK(CAP_SYS_RESOURCE)) capdata->effective &= ~CAP_TO_MASK(CAP_SYS_RESOURCE); if (capdata->permitted & CAP_TO_MASK(CAP_SYS_RESOURCE)) capdata->permitted &= ~CAP_TO_MASK(CAP_SYS_RESOURCE); if (capdata->inheritable & CAP_TO_MASK(CAP_SYS_RESOURCE)) capdata->inheritable &= ~CAP_TO_MASK(CAP_SYS_RESOURCE); if (capset(&caphdr, capdata) != 0) LogFatal(COMPONENT_INIT, "Failed to set capabilities for process, errno=%u", errno); else LogEvent(COMPONENT_INIT, "CAP_SYS_RESOURCE was successfully removed for proper quota management in FSAL"); /* Print newly set capabilities (same as what CLI "getpcaps" displays */ my_cap = cap_get_proc(); cap_text = cap_to_text(my_cap, &capstrlen); LogEvent(COMPONENT_INIT, "currenty set capabilities are: %s", cap_text); cap_free(cap_text); cap_free(my_cap); gsh_free(capdata); }
static int badness(struct task_struct *p) { int points, cpu_time, run_time; if (!p->mm) return 0; if (p->flags & PF_MEMDIE) return 0; /* * The memory size of the process is the basis for the badness. */ points = p->mm->total_vm; /* * CPU time is in seconds and run time is in minutes. There is no * particular reason for this other than that it turned out to work * very well in practice. This is not safe against jiffie wraps * but we don't care _that_ much... */ cpu_time = (p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3); run_time = (jiffies - p->start_time) >> (SHIFT_HZ + 10); points /= int_sqrt(cpu_time); points /= int_sqrt(int_sqrt(run_time)); /* * Niced processes are most likely less important, so double * their badness points. */ if (p->nice > 0) points *= 2; /* * Superuser processes are usually more important, so we make it * less likely that we kill those. */ if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) || p->uid == 0 || p->euid == 0) points /= 4; /* * We don't want to kill a process with direct hardware access. * Not only could that mess up the hardware, but usually users * tend to only have this flag set on applications they think * of as important. */ if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO)) points /= 4; #ifdef DEBUG printk(KERN_DEBUG "OOMkill: task %d (%s) got %d points\n", p->pid, p->comm, points); #endif return points; }
static void drop_capabilities_bounding_set_if_needed(struct minijail *j) { #if defined(ALLOW_ADBD_ROOT) char value[PROPERTY_VALUE_MAX]; property_get("ro.debuggable", value, ""); if (strcmp(value, "1") == 0) { return; } #endif minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID)); }
static int drop_privs() { struct sched_param param; memset(¶m, 0, sizeof(param)); if (set_sched_policy(0, SP_BACKGROUND) < 0) { return -1; } if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) { return -1; } if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) { return -1; } if (prctl(PR_SET_KEEPCAPS, 1) < 0) { return -1; } gid_t groups[] = { AID_READPROC }; if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) { 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; }
/* * Check for superuser privileges */ int check_capabilities() { struct __user_cap_header_struct cap_header; struct __user_cap_data_struct cap_data; cap_header.pid = getpid(); cap_header.version = _LINUX_CAPABILITY_VERSION; if (capget(&cap_header, &cap_data) < 0) { lispd_log_msg(LISP_LOG_ERR, "Could not retrieve capabilities"); return BAD; } lispd_log_msg(LISP_LOG_DEBUG_1, "Rights: Effective [%u] Permitted [%u]", cap_data.effective, cap_data.permitted); /* check for capabilities */ if( (cap_data.effective & CAP_TO_MASK(CAP_NET_ADMIN)) && (cap_data.effective & CAP_TO_MASK(CAP_NET_RAW)) ) { } else { lispd_log_msg(LISP_LOG_CRIT, "Insufficient rights, you need CAP_NET_ADMIN and CAP_NET_RAW. See README"); return BAD; } /* Clear all but the capability to bind to low ports */ cap_data.effective = CAP_TO_MASK(CAP_NET_ADMIN) | CAP_TO_MASK(CAP_NET_RAW); cap_data.permitted = cap_data.effective ; cap_data.inheritable = 0; if (capset(&cap_header, &cap_data) < 0) { lispd_log_msg(LISP_LOG_WARNING, "Could not drop privileges"); return BAD; } /* Tell kernel not clear permitted capabilities when dropping root */ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { lispd_log_msg(LISP_LOG_WARNING, "Sprctl(PR_SET_KEEPCAPS) failed"); return GOOD; } /* Now we can drop privilege, drop effective rights even with KEEPCAPS */ if (setuid(getuid()) < 0) { lispd_log_msg(LISP_LOG_WARNING, "Could not drop privileges"); } /* that's why we need to set effective rights equal to permitted rights */ if (capset(&cap_header, &cap_data) < 0) { lispd_log_msg(LISP_LOG_CRIT, "Could not set effective rights to permitted ones"); return (BAD); } lispd_log_msg(LISP_LOG_DEBUG_1, "Rights: Effective [%u] Permitted [%u]", cap_data.effective, cap_data.permitted); return GOOD; }
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; /* don't clear capabilities when dropping root */ if (prctl(PR_SET_KEEPCAPS, 1) < 0) { error("%s: prctl(): %s", __func__, strerror(errno)); return false; } /* Android bluetooth user UID=1002 */ if (setuid(1002) < 0) { error("%s: setuid(): %s", __func__, strerror(errno)); return false; } /* 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 SetPermission(int flag) { int errno = 0; struct __user_cap_header_struct header; header.version = _LINUX_CAPABILITY_VERSION_3; header.pid = (int)ISyscall(__NR_gettid); printf("version: 0x%08x\n", header.version); unsigned int data[3]; memset(data, 0, sizeof(data)); if (ISyscall(__NR_capget, &header, &data)) { printf("capget failed!\n"); return 0; } //memset(data, 0, sizeof(data)); data[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag); if ((errno = ISyscall(__NR_capset, &header, &data))) { printf("capset failed! [%d]\n", errno); printf("version: 0x%08x\n", header.version); return 0; } printf("0x%08x\n", data[0]); printf("0x%08x\n", data[1]); printf("0x%08x\n", data[2]); return 1; }
/* audit interface for capability */ void kse_cap_audit(struct task_struct *tsk, int cap, int result) { int sclass, request; struct common_audit_data ad; if (kse_noyaudit == 1 && result == 0) return; COMMON_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; ad.u.cap = cap; request = CAP_TO_MASK(cap); switch (CAP_TO_INDEX(cap)) { case 0: sclass = SECCLASS_CAPABILITY; break; case 1: sclass = SECCLASS_CAPABILITY2; break; default: printk(KERN_ERR "KUXSE: out of range capability %d\n", cap); BUG(); } //kse_audit(task_cred_xxx(tsk, security), NULL, NULL, 0, sclass, //request, result, &ad); kse_audit(tsk->security, NULL, NULL, 0, sclass, request, result, &ad); }
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; }
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); } }
/* * 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 int has_cap(sd_bus_creds *c, unsigned offset, int capability) { size_t sz; assert(c); assert(capability >= 0); assert(c->capability); if ((unsigned) capability > cap_last_cap()) return 0; sz = DIV_ROUND_UP(cap_last_cap(), 32U); return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability)); }
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 }
/* * Look at the environment for some special options. */ static void supR3GrabOptions(void) { const char *pszOpt; # ifdef RT_OS_LINUX g_uCaps = 0; /* * Do _not_ perform any capability-related system calls for root processes * (leaving g_uCaps at 0). * (Hint: getuid gets the real user id, not the effective.) */ if (getuid() != 0) { /* * CAP_NET_RAW. * Default: enabled. * Can be disabled with 'export VBOX_HARD_CAP_NET_RAW=0'. */ pszOpt = getenv("VBOX_HARD_CAP_NET_RAW"); if ( !pszOpt || memcmp(pszOpt, "0", sizeof("0")) != 0) g_uCaps = CAP_TO_MASK(CAP_NET_RAW); /* * CAP_NET_BIND_SERVICE. * Default: disabled. * Can be enabled with 'export VBOX_HARD_CAP_NET_BIND_SERVICE=1'. */ pszOpt = getenv("VBOX_HARD_CAP_NET_BIND_SERVICE"); if ( pszOpt && memcmp(pszOpt, "0", sizeof("0")) != 0) g_uCaps |= CAP_TO_MASK(CAP_NET_BIND_SERVICE); } # endif }
/** * We must be careful though to never send SIGKILL a process with * CAP_SYS_RAW_IO set, send SIGTERM instead (but it's unlikely that * we select a process with CAP_SYS_RAW_IO set). */ void oom_kill_task(struct task_struct *p) { printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", p->pid, p->comm); /* * We give our sacrificial lamb high priority and access to * all the memory it needs. That way it should be able to * exit() and clear out its resources quickly... */ p->counter = 5 * HZ; /* This process has hardware access, be more careful. */ if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO)) { force_sig(SIGTERM, p); } else { force_sig(SIGKILL, p); } }
/** 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]); }
void linux_cap_change(int on, ...) { struct __user_cap_header_struct x; struct __user_cap_data_struct s[3] = {}; x.version = _LINUX_CAPABILITY_VERSION_3; x.pid = syscall(SYS_gettid); if(syscall(SYS_capget, &x, s)) { perror("capget"); exit(1); } va_list ap; va_start(ap, on); int cap; while((cap = va_arg(ap, int)) != -1) { if(!cap_valid(cap)) { fprintf(stderr, "cap %d is not valid\n", cap); exit(1); } if(on) { s[CAP_TO_INDEX(cap)].effective |= CAP_TO_MASK(cap); } else { s[CAP_TO_INDEX(cap)].effective &= ~CAP_TO_MASK(cap); } } if(syscall(SYS_capset, &x, s)) { perror("capset"); exit(1); } }
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 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 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(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; }
/* * 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); }