am b6f38def: Merge "run-as: bracket capability"

* commit 'b6f38def22add4b5d6878185d238f91659239161':
  run-as: bracket capability
This commit is contained in:
Mark Salyzyn 2015-03-31 17:46:42 +00:00 committed by Android Git Automerger
commit 3cc18a2cf9

View file

@ -15,22 +15,25 @@
** limitations under the License. ** limitations under the License.
*/ */
#define PROGNAME "run-as" #define PROGNAME "run-as"
#define LOG_TAG PROGNAME #define LOG_TAG PROGNAME
#include <dirent.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/capability.h>
#include <sys/cdefs.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <dirent.h> #include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <time.h> #include <time.h>
#include <stdarg.h> #include <unistd.h>
#include <selinux/android.h>
#include <private/android_filesystem_config.h> #include <private/android_filesystem_config.h>
#include <selinux/android.h>
#include "package.h" #include "package.h"
/* /*
@ -83,37 +86,37 @@
* - Run the 'gdbserver' binary executable to allow native debugging * - Run the 'gdbserver' binary executable to allow native debugging
*/ */
static void __noreturn static void
usage(void)
{
const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n";
write(1, str, strlen(str));
exit(1);
}
static void
panic(const char* format, ...) panic(const char* format, ...)
{ {
va_list args; va_list args;
int e = errno;
fprintf(stderr, "%s: ", PROGNAME); fprintf(stderr, "%s: ", PROGNAME);
va_start(args, format); va_start(args, format);
vfprintf(stderr, format, args); vfprintf(stderr, format, args);
va_end(args); va_end(args);
exit(1); exit(e ? -e : 1);
} }
static void
usage(void)
{
panic("Usage:\n " PROGNAME " <package-name> <command> [<args>]\n");
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
const char* pkgname; const char* pkgname;
int myuid, uid, gid; int myuid, uid, gid;
PackageInfo info; PackageInfo info;
struct __user_cap_header_struct capheader;
struct __user_cap_data_struct capdata[2];
/* check arguments */ /* check arguments */
if (argc < 2) if (argc < 2) {
usage(); usage();
}
/* check userid of caller - must be 'shell' or 'root' */ /* check userid of caller - must be 'shell' or 'root' */
myuid = getuid(); myuid = getuid();
@ -121,29 +124,37 @@ int main(int argc, char **argv)
panic("only 'shell' or 'root' users can run this program\n"); panic("only 'shell' or 'root' users can run this program\n");
} }
/* retrieve package information from system */ 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]) < 0) {
panic("Could not set capabilities: %s\n", strerror(errno));
}
/* retrieve package information from system (does setegid) */
pkgname = argv[1]; pkgname = argv[1];
if (get_package_info(pkgname, &info) < 0) { if (get_package_info(pkgname, &info) < 0) {
panic("Package '%s' is unknown\n", pkgname); panic("Package '%s' is unknown\n", pkgname);
return 1;
} }
/* reject system packages */ /* reject system packages */
if (info.uid < AID_APP) { if (info.uid < AID_APP) {
panic("Package '%s' is not an application\n", pkgname); panic("Package '%s' is not an application\n", pkgname);
return 1;
} }
/* reject any non-debuggable package */ /* reject any non-debuggable package */
if (!info.isDebuggable) { if (!info.isDebuggable) {
panic("Package '%s' is not debuggable\n", pkgname); panic("Package '%s' is not debuggable\n", pkgname);
return 1;
} }
/* check that the data directory path is valid */ /* check that the data directory path is valid */
if (check_data_path(info.dataDir, info.uid) < 0) { if (check_data_path(info.dataDir, info.uid) < 0) {
panic("Package '%s' has corrupt installation\n", pkgname); panic("Package '%s' has corrupt installation\n", pkgname);
return 1;
} }
/* Ensure that we change all real/effective/saved IDs at the /* Ensure that we change all real/effective/saved IDs at the
@ -152,38 +163,30 @@ int main(int argc, char **argv)
uid = gid = info.uid; uid = gid = info.uid;
if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
panic("Permission denied\n"); panic("Permission denied\n");
return 1; }
/* Required if caller has uid and gid all non-zero */
memset(&capdata, 0, sizeof(capdata));
if (capset(&capheader, &capdata[0]) < 0) {
panic("Could not clear all capabilities: %s\n", strerror(errno));
} }
if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) { if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
panic("Could not set SELinux security context: %s\n", strerror(errno)); panic("Could not set SELinux security context: %s\n", strerror(errno));
return 1;
} }
/* cd into the data directory */ /* cd into the data directory */
{ if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) {
int ret; panic("Could not cd to package's data directory: %s\n", strerror(errno));
do {
ret = chdir(info.dataDir);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
panic("Could not cd to package's data directory: %s\n", strerror(errno));
return 1;
}
} }
/* User specified command for exec. */ /* User specified command for exec. */
if (argc >= 3 ) { if ((argc >= 3) && (execvp(argv[2], argv+2) < 0)) {
if (execvp(argv[2], argv+2) < 0) { panic("exec failed for %s: %s\n", argv[2], strerror(errno));
panic("exec failed for %s Error:%s\n", argv[2], strerror(errno));
return -errno;
}
} }
/* Default exec shell. */ /* Default exec shell. */
execlp("/system/bin/sh", "sh", NULL); execlp("/system/bin/sh", "sh", NULL);
panic("exec failed\n"); panic("exec failed: %s\n", strerror(errno));
return 1;
} }