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 181f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#define PROGNAME "run-as" 191f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#define LOG_TAG PROGNAME 201f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 211f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <stdio.h> 221f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <stdlib.h> 231f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <string.h> 241f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <sys/types.h> 251f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <sys/stat.h> 261f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <dirent.h> 271f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <errno.h> 281f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <unistd.h> 291f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <time.h> 301f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <stdarg.h> 311f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 324ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley#include <selinux/android.h> 331f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <private/android_filesystem_config.h> 341f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include "package.h" 351f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 361f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner/* 371f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * WARNING WARNING WARNING WARNING 381f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 39b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * This program runs with CAP_SETUID and CAP_SETGID capabilities on Android 40b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * production devices. Be very conservative when modifying it to avoid any 41b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * serious security issue. Keep in mind the following: 421f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 431f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - This program should only run for the 'root' or 'shell' users 441f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 45b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * - Avoid anything that is more complex than simple system calls 46b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * until the uid/gid has been dropped to that of a normal user 47b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * or you are sure to exit. 481f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 491f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This avoids depending on environment variables, system properties 501f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * and other external factors that may affect the C library in 511f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * unpredictable ways. 521f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 531f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Do not trust user input and/or the filesystem whenever possible. 541f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 551f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * Read README.TXT for more details. 561f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 571f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 581f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 591f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * The purpose of this program is to run a command as a specific 601f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * application user-id. Typical usage is: 611f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 621f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * run-as <package-name> <command> <args> 631f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 64b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file 65b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * capabilities, but will check the following: 661f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 671f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that it is invoked from the 'shell' or 'root' user (abort otherwise) 681f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that '<package-name>' is the name of an installed and debuggable package 691f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that the package's data directory is well-formed (see package.c) 701f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 71b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * If so, it will drop to the application's user id / group id, cd to the 72b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * package's data directory, then run the command there. 73b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * 74b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * NOTE: In the future it might not be possible to cd to the package's data 75b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * directory under that package's user id / group id, in which case this 76b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin * utility will need to be changed accordingly. 771f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 781f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This can be useful for a number of different things on production devices: 791f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 801f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Allow application developers to look at their own applicative data 811f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * during development. 821f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 831f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Run the 'gdbserver' binary executable to allow native debugging 841f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 851f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 861f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerstatic void 871f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerusage(void) 881f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 891f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n"; 901f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner write(1, str, strlen(str)); 911f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner exit(1); 921f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 931f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 941f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 951f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerstatic void 961f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerpanic(const char* format, ...) 971f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 981f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_list args; 991f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1001f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner fprintf(stderr, "%s: ", PROGNAME); 1011f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_start(args, format); 1021f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner vfprintf(stderr, format, args); 1031f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_end(args); 1041f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner exit(1); 1051f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 1061f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1071f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1081f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerint main(int argc, char **argv) 1091f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 1101f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner const char* pkgname; 1111f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner int myuid, uid, gid; 1121f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner PackageInfo info; 1131f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1141f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check arguments */ 1151f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (argc < 2) 1161f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner usage(); 1171f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1181f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check userid of caller - must be 'shell' or 'root' */ 1191f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner myuid = getuid(); 1201f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (myuid != AID_SHELL && myuid != AID_ROOT) { 1211f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("only 'shell' or 'root' users can run this program\n"); 1221f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1231f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1241f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* retrieve package information from system */ 1251f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner pkgname = argv[1]; 1261f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (get_package_info(pkgname, &info) < 0) { 1271f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is unknown\n", pkgname); 1281f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1291f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1301f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1311f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject system packages */ 1321f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (info.uid < AID_APP) { 1331f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not an application\n", pkgname); 1341f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1351f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1361f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1371f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject any non-debuggable package */ 1381f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (!info.isDebuggable) { 1391f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not debuggable\n", pkgname); 1401f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1411f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1421f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1431f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check that the data directory path is valid */ 1441f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (check_data_path(info.dataDir, info.uid) < 0) { 1451f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' has corrupt installation\n", pkgname); 1461f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1471f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1481f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1491f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Ensure that we change all real/effective/saved IDs at the 1501f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * same time to avoid nasty surprises. 1511f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 1521f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner uid = gid = info.uid; 1531f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { 1541f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Permission denied\n"); 1551f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1561f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1571f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 158fced3ded831cb084121b10a78c12de99c89004aaRobert Craig if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { 1594ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley panic("Could not set SELinux security context: %s\n", strerror(errno)); 1604ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley return 1; 1614ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley } 1624ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley 163b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin /* cd into the data directory */ 164b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin { 165b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin int ret; 166b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin do { 167b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin ret = chdir(info.dataDir); 168b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin } while (ret < 0 && errno == EINTR); 169b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin 170b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin if (ret < 0) { 171b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin panic("Could not cd to package's data directory: %s\n", strerror(errno)); 172b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin return 1; 173b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin } 174b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin } 175b0739c662db6a19b49c0912b865edb2853156bdaAlex Klyubin 1761f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* User specified command for exec. */ 1771f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (argc >= 3 ) { 1781f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (execvp(argv[2], argv+2) < 0) { 1791f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("exec failed for %s Error:%s\n", argv[2], strerror(errno)); 1801f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return -errno; 1811f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1821f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1831f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1841f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Default exec shell. */ 1851f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner execlp("/system/bin/sh", "sh", NULL); 1861f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1871f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("exec failed\n"); 1881f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1891f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 190