run-as.c revision 4ead8beac8fe59b01ad1e5670713b99e7f841b9b
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 * 391f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This program runs as set-uid root on Android production devices. 401f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * Be very conservative when modifying it to avoid any serious 411f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 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 * 641f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * The 'run-as' binary is setuid, but will check the following: 651f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 661f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that it is invoked from the 'shell' or 'root' user (abort otherwise) 671f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that '<package-name>' is the name of an installed and debuggable package 681f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - that the package's data directory is well-formed (see package.c) 691f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 701f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * If so, it will cd to the package's data directory, drop to the application's 711f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * user id / group id then run the command there. 721f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 731f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * This can be useful for a number of different things on production devices: 741f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 751f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Allow application developers to look at their own applicative data 761f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * during development. 771f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * 781f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * - Run the 'gdbserver' binary executable to allow native debugging 791f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 801f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 811f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerstatic void 821f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerusage(void) 831f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 841f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n"; 851f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner write(1, str, strlen(str)); 861f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner exit(1); 871f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 881f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 891f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 901f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerstatic void 911f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerpanic(const char* format, ...) 921f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 931f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner va_list args; 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); 991f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner exit(1); 1001f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 1011f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1021f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1031f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turnerint main(int argc, char **argv) 1041f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner{ 1051f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner const char* pkgname; 1061f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner int myuid, uid, gid; 1071f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner PackageInfo info; 1081f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1091f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check arguments */ 1101f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (argc < 2) 1111f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner usage(); 1121f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1131f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check userid of caller - must be 'shell' or 'root' */ 1141f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner myuid = getuid(); 1151f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (myuid != AID_SHELL && myuid != AID_ROOT) { 1161f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("only 'shell' or 'root' users can run this program\n"); 1171f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1181f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1191f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* retrieve package information from system */ 1201f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner pkgname = argv[1]; 1211f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (get_package_info(pkgname, &info) < 0) { 1221f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is unknown\n", pkgname); 1231f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1241f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1251f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1261f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject system packages */ 1271f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (info.uid < AID_APP) { 1281f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not an application\n", pkgname); 1291f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1301f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1311f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1321f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* reject any non-debuggable package */ 1331f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (!info.isDebuggable) { 1341f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' is not debuggable\n", pkgname); 1351f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1361f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1371f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1381f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* check that the data directory path is valid */ 1391f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (check_data_path(info.dataDir, info.uid) < 0) { 1401f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Package '%s' has corrupt installation\n", pkgname); 1411f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1421f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1431f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1441f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* then move to it */ 1451f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner { 1461f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner int ret; 1471f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner do { 1481f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner ret = chdir(info.dataDir); 1491f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } while (ret < 0 && errno == EINTR); 1501f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1511f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (ret < 0) { 1521f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Could not cd to package's data directory: %s\n", strerror(errno)); 1531f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1541f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1551f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1561f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1571f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Ensure that we change all real/effective/saved IDs at the 1581f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner * same time to avoid nasty surprises. 1591f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner */ 1601f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner uid = gid = info.uid; 1611f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { 1621f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("Permission denied\n"); 1631f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1641f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1651f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1664ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley if (selinux_android_setcontext(uid, 0, NULL, pkgname) < 0) { 1674ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley panic("Could not set SELinux security context: %s\n", strerror(errno)); 1684ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley return 1; 1694ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley } 1704ead8beac8fe59b01ad1e5670713b99e7f841b9bStephen Smalley 1711f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* User specified command for exec. */ 1721f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (argc >= 3 ) { 1731f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner if (execvp(argv[2], argv+2) < 0) { 1741f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("exec failed for %s Error:%s\n", argv[2], strerror(errno)); 1751f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return -errno; 1761f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1771f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner } 1781f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1791f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner /* Default exec shell. */ 1801f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner execlp("/system/bin/sh", "sh", NULL); 1811f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner 1821f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner panic("exec failed\n"); 1831f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner return 1; 1841f4d95296acf34a93128332441782a80c10845b4David 'Digit' Turner} 185