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 321f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include <private/android_filesystem_config.h> 331f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner#include "package.h" 341f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 351f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner/* 361f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * WARNING WARNING WARNING WARNING 371f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 381f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This program runs as set-uid root on Android production devices. 391f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * Be very conservative when modifying it to avoid any serious 401f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * security issue. Keep in mind the following: 411f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 421f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - This program should only run for the 'root' or 'shell' users 431f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 44b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * - Avoid anything that is more complex than simple system calls 45b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * until the uid/gid has been dropped to that of a normal user 46b2d8f896b6ef081c1af263dd13d91d2f435de0faNick Kralevich * or you are sure to exit. 471f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 481f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This avoids depending on environment variables, system properties 491f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * and other external factors that may affect the C library in 501f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * unpredictable ways. 511f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 521f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Do not trust user input and/or the filesystem whenever possible. 531f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 541f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * Read README.TXT for more details. 551f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 561f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 571f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 581f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * The purpose of this program is to run a command as a specific 591f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * application user-id. Typical usage is: 601f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 611f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * run-as <package-name> <command> <args> 621f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 631f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * The 'run-as' binary is setuid, but will check the following: 641f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 651f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that it is invoked from the 'shell' or 'root' user (abort otherwise) 661f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that '<package-name>' is the name of an installed and debuggable package 671f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that the package's data directory is well-formed (see package.c) 681f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 691f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * If so, it will cd to the package's data directory, drop to the application's 701f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * user id / group id then run the command there. 711f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 721f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This can be useful for a number of different things on production devices: 731f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 741f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Allow application developers to look at their own applicative data 751f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * during development. 761f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 771f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Run the 'gdbserver' binary executable to allow native debugging 781f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 791f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 801f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerstatic void 811f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerusage(void) 821f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 831f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n"; 841f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner write(1, str, strlen(str)); 851f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner exit(1); 861f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 871f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 881f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 891f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerstatic void 901f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerpanic(const char* format, ...) 911f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 921f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_list args; 931f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 941f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner fprintf(stderr, "%s: ", PROGNAME); 951f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_start(args, format); 961f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner vfprintf(stderr, format, args); 971f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_end(args); 981f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner exit(1); 991f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 1001f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1011f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1021f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerint main(int argc, char **argv) 1031f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 1041f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner const char* pkgname; 1051f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner int myuid, uid, gid; 1061f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner PackageInfo info; 1071f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1081f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check arguments */ 1091f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (argc < 2) 1101f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner usage(); 1111f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1121f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check userid of caller - must be 'shell' or 'root' */ 1131f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner myuid = getuid(); 1141f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (myuid != AID_SHELL && myuid != AID_ROOT) { 1151f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("only 'shell' or 'root' users can run this program\n"); 1161f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1171f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1181f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* retrieve package information from system */ 1191f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner pkgname = argv[1]; 1201f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (get_package_info(pkgname, &info) < 0) { 1211f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is unknown\n", pkgname); 1221f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1231f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1241f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1251f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject system packages */ 1261f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (info.uid < AID_APP) { 1271f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not an application\n", pkgname); 1281f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1291f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1301f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1311f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject any non-debuggable package */ 1321f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (!info.isDebuggable) { 1331f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not debuggable\n", pkgname); 1341f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1351f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1361f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1371f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check that the data directory path is valid */ 1381f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (check_data_path(info.dataDir, info.uid) < 0) { 1391f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' has corrupt installation\n", pkgname); 1401f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1411f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1421f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1431f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* then move to it */ 1441f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner { 1451f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner int ret; 1461f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner do { 1471f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner ret = chdir(info.dataDir); 1481f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } while (ret < 0 && errno == EINTR); 1491f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1501f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (ret < 0) { 1511f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Could not cd to package's data directory: %s\n", strerror(errno)); 1521f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1531f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1541f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1551f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1561f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Ensure that we change all real/effective/saved IDs at the 1571f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * same time to avoid nasty surprises. 1581f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 1591f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner uid = gid = info.uid; 1601f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { 1611f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Permission denied\n"); 1621f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1631f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1641f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1651f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* User specified command for exec. */ 1661f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (argc >= 3 ) { 1671f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (execvp(argv[2], argv+2) < 0) { 1681f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("exec failed for %s Error:%s\n", argv[2], strerror(errno)); 1691f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return -errno; 1701f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1711f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1721f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1731f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Default exec shell. */ 1741f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner execlp("/system/bin/sh", "sh", NULL); 1751f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1761f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("exec failed\n"); 1771f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1781f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 179