11f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner/* 21f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** 31f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** Copyright 2010, The Android Open Source Project 41f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** 51f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** Licensed under the Apache License, Version 2.0 (the "License"); 61f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** you may not use this file except in compliance with the License. 71f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** You may obtain a copy of the License at 81f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** 91f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** http://www.apache.org/licenses/LICENSE-2.0 101f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** 111f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** Unless required by applicable law or agreed to in writing, software 121f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** distributed under the License is distributed on an "AS IS" BASIS, 131f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 141f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** See the License for the specific language governing permissions and 151f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner** limitations under the License. 161f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner*/ 171f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 18db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#define PROGNAME "run-as" 19db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#define LOG_TAG PROGNAME 201f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 21db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <dirent.h> 22db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <errno.h> 23db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <stdarg.h> 241f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <stdio.h> 251f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <stdlib.h> 261f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <string.h> 27db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <sys/capability.h> 28db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <sys/cdefs.h> 291f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <sys/stat.h> 30db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <sys/types.h> 311f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <time.h> 32db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <unistd.h> 331f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 341f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <private/android_filesystem_config.h> 35db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn#include <selinux/android.h> 36db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn 371f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include "package.h" 381f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 391f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner/* 401f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * WARNING WARNING WARNING WARNING 411f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 42b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * This program runs with CAP_SETUID and CAP_SETGID capabilities on Android 43b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * production devices. Be very conservative when modifying it to avoid any 44b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * serious security issue. Keep in mind the following: 451f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 461f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - This program should only run for the 'root' or 'shell' users 471f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 48b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * - Avoid anything that is more complex than simple system calls 49b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * until the uid/gid has been dropped to that of a normal user 50b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * or you are sure to exit. 511f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 521f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This avoids depending on environment variables, system properties 531f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * and other external factors that may affect the C library in 541f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * unpredictable ways. 551f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 561f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Do not trust user input and/or the filesystem whenever possible. 571f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 581f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * Read README.TXT for more details. 591f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 601f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 611f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 621f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * The purpose of this program is to run a command as a specific 631f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * application user-id. Typical usage is: 641f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 651f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * run-as <package-name> <command> <args> 661f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 67b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file 68b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * capabilities, but will check the following: 691f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 701f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that it is invoked from the 'shell' or 'root' user (abort otherwise) 711f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that '<package-name>' is the name of an installed and debuggable package 721f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that the package's data directory is well-formed (see package.c) 731f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 74b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * If so, it will drop to the application's user id / group id, cd to the 75b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * package's data directory, then run the command there. 76b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * 77b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * NOTE: In the future it might not be possible to cd to the package's data 78b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * directory under that package's user id / group id, in which case this 79b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * utility will need to be changed accordingly. 801f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 811f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This can be useful for a number of different things on production devices: 821f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 831f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Allow application developers to look at their own applicative data 841f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * during development. 851f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 861f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Run the 'gdbserver' binary executable to allow native debugging 871f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 881f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 89db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn__noreturn static void 901f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerpanic(const char* format, ...) 911f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 921f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_list args; 93db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn int e = errno; 941f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 951f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner fprintf(stderr, "%s: ", PROGNAME); 961f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_start(args, format); 971f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner vfprintf(stderr, format, args); 981f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_end(args); 99db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn exit(e ? -e : 1); 1001f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 1011f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 102db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzynstatic void 103db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzynusage(void) 104db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn{ 105a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov panic("Usage:\n " PROGNAME " <package-name> [--user <uid>] <command> [<args>]\n"); 106db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn} 1071f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1081f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerint main(int argc, char **argv) 1091f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 1101f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner const char* pkgname; 111a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov uid_t myuid, uid, gid, userAppId = 0; 112a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov int commandArgvOfs = 2, userId = 0; 1131f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner PackageInfo info; 114db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn struct __user_cap_header_struct capheader; 115db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn struct __user_cap_data_struct capdata[2]; 1161f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1171f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check arguments */ 118db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn if (argc < 2) { 1191f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner usage(); 120db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn } 1211f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1221f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check userid of caller - must be 'shell' or 'root' */ 1231f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner myuid = getuid(); 1241f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (myuid != AID_SHELL && myuid != AID_ROOT) { 1251f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("only 'shell' or 'root' users can run this program\n"); 1261f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1271f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 128db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn memset(&capheader, 0, sizeof(capheader)); 129db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn memset(&capdata, 0, sizeof(capdata)); 130db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn capheader.version = _LINUX_CAPABILITY_VERSION_3; 131db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID); 132db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID); 133db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); 134db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); 135db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn 136db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn if (capset(&capheader, &capdata[0]) < 0) { 137db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn panic("Could not set capabilities: %s\n", strerror(errno)); 138db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn } 139db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn 1401f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner pkgname = argv[1]; 141a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov 142a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov /* get user_id from command line if provided */ 143a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov if ((argc >= 4) && !strcmp(argv[2], "--user")) { 144a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov userId = atoi(argv[3]); 145a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov if (userId < 0) 146a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov panic("Negative user id %d is provided\n", userId); 147a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov commandArgvOfs += 2; 148a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov } 149a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov 150a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov /* retrieve package information from system (does setegid) */ 151a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov if (get_package_info(pkgname, userId, &info) < 0) { 1521f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is unknown\n", pkgname); 1531f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1541f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 155a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov /* verify that user id is not too big. */ 156a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) { 157a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov panic("User id %d is too big\n", userId); 158a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov } 159a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov 160a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov /* calculate user app ID. */ 161a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov userAppId = (AID_USER * userId) + info.uid; 162a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov 1631f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject system packages */ 164a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov if (userAppId < AID_APP) { 1651f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not an application\n", pkgname); 1661f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1671f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1681f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject any non-debuggable package */ 1691f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (!info.isDebuggable) { 1701f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not debuggable\n", pkgname); 1711f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1721f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1731f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check that the data directory path is valid */ 174a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov if (check_data_path(info.dataDir, userAppId) < 0) { 1751f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' has corrupt installation\n", pkgname); 1761f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1771f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1781f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Ensure that we change all real/effective/saved IDs at the 1791f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * same time to avoid nasty surprises. 1801f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 181a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov uid = gid = userAppId; 1821f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { 1831f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Permission denied\n"); 184db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn } 185db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn 186db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn /* Required if caller has uid and gid all non-zero */ 187db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn memset(&capdata, 0, sizeof(capdata)); 188db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn if (capset(&capheader, &capdata[0]) < 0) { 189db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn panic("Could not clear all capabilities: %s\n", strerror(errno)); 1901f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1911f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 192fced3ded831cb084121b10a78c12de99c89004aaRobert Craig if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { 193db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn panic("Could not set SELinux security context: %s\n", strerror(errno)); 1944ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley } 1954ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley 196b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin /* cd into the data directory */ 197db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) { 198db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn panic("Could not cd to package's data directory: %s\n", strerror(errno)); 199b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin } 200b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin 2011f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* User specified command for exec. */ 202a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov if ((argc >= commandArgvOfs + 1) && 203a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov (execvp(argv[commandArgvOfs], argv+commandArgvOfs) < 0)) { 204a08d313bb87279d2a203cded92669638e3458f5fOleksiy Vyalov panic("exec failed for %s: %s\n", argv[commandArgvOfs], strerror(errno)); 2051f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 2061f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 2071f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Default exec shell. */ 2081f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner execlp("/system/bin/sh", "sh", NULL); 2091f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 210db5334ad039dab3ec2b50e9a259c97ce882acc0dMark Salyzyn panic("exec failed: %s\n", strerror(errno)); 2111f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 212