Пример #1
0
static void drop_privileges(int server_port) {
    std::unique_ptr<minijail, void (*)(minijail*)> jail(minijail_new(),
                                                        &minijail_destroy);

    // Add extra groups:
    // AID_ADB to access the USB driver
    // AID_LOG to read system logs (adb logcat)
    // AID_INPUT to diagnose input issues (getevent)
    // AID_INET to diagnose network issues (ping)
    // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
    // AID_SDCARD_R to allow reading from the SD card
    // AID_SDCARD_RW to allow writing to the SD card
    // AID_NET_BW_STATS to read out qtaguid statistics
    // AID_READPROC for reading /proc entries across UID boundaries
    gid_t groups[] = {AID_ADB,      AID_LOG,       AID_INPUT,
                      AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
                      AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
                      AID_READPROC};
    if (minijail_set_supplementary_gids(
            jail.get(),
            sizeof(groups) / sizeof(groups[0]),
            groups) != 0) {
        LOG(FATAL) << "Could not configure supplementary groups";
    }

    // Don't listen on a port (default 5037) if running in secure mode.
    // Don't run as root if running in secure mode.
    if (should_drop_privileges()) {
        drop_capabilities_bounding_set_if_needed();

        minijail_change_gid(jail.get(), AID_SHELL);
        minijail_change_uid(jail.get(), AID_SHELL);
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());

        D("Local port disabled");
    } else {
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());

        if (root_seclabel != nullptr) {
            if (selinux_android_setcon(root_seclabel) < 0) {
                LOG(FATAL) << "Could not set SELinux context";
            }
        }
        std::string error;
        std::string local_name =
            android::base::StringPrintf("tcp:%d", server_port);
        if (install_listener(local_name, "*smartsocket*", nullptr, 0,
                             &error)) {
            LOG(FATAL) << "Could not install *smartsocket* listener: "
                       << error;
        }
    }
}
Пример #2
0
static void drop_privs(uid_t uid, gid_t gid) {
    ScopedMinijail j(minijail_new());
    minijail_set_supplementary_gids(j.get(), arraysize(kGroups), kGroups);
    minijail_change_gid(j.get(), gid);
    minijail_change_uid(j.get(), uid);
    /* minijail_enter() will abort if priv-dropping fails. */
    minijail_enter(j.get());
}
Пример #3
0
/** @brief Fake main(), spliced in before the real call to main() by
 *         __libc_start_main (see below).
 *  We get serialized commands from our invoking process over an fd specified
 *  by an environment variable (kFdEnvVar). The environment variable is a list
 *  of key=value pairs (see move_commands_to_env); we use them to construct a
 *  jail, then enter it.
 */
static int fake_main(int argc, char **argv, char **envp)
{
	char *fd_name = getenv(kFdEnvVar);
	int fd = -1;
	struct minijail *j;
	if (geteuid() != getuid() || getegid() != getgid())
		/* If we didn't do this check, an attacker could set kFdEnvVar
		 * for any setuid program that uses libminijail to cause it to
		 * get capabilities or a uid it did not expect.
		 */
		/* TODO(wad) why would libminijail interact here? */
		return MINIJAIL_ERR_PRELOAD;
	if (!fd_name)
		return MINIJAIL_ERR_PRELOAD;
	fd = atoi(fd_name);
	if (fd < 0)
		return MINIJAIL_ERR_PRELOAD;
	// Even if the process cannot use that fd, avoid divulging stuff.
	unsetenv(kFdEnvVar);

	j = minijail_new();
	if (!j)
		die("preload: out of memory");
	if (minijail_from_fd(fd, j))
		die("preload: failed to parse minijail from parent");
	close(fd);

	/* TODO(ellyjones): this trashes existing preloads, so one can't do:
	 * LD_PRELOAD="/tmp/test.so libminijailpreload.so" prog; the
	 * descendants of prog will have no LD_PRELOAD set at all.
	 */
	unset_in_env(envp, kLdPreloadEnvVar);
	/* Strip out flags meant for the parent. */
	minijail_preenter(j);
	minijail_enter(j);
	minijail_destroy(j);
	dlclose(libc_handle);
	return real_main(argc, argv, envp);
}
Пример #4
0
int main(int argc, char* argv[]) {
  // Check arguments.
  if (argc < 2) {
    error(1, 0, "usage: run-as <package-name> [--user <uid>] <command> [<args>]\n");
  }

  // This program runs with CAP_SETUID and CAP_SETGID capabilities on Android
  // production devices. Check user id of caller --- must be 'shell' or 'root'.
  if (getuid() != AID_SHELL && getuid() != AID_ROOT) {
    error(1, 0, "only 'shell' or 'root' users can run this program");
  }

  // Some devices can disable running run-as, such as Chrome OS when running in
  // non-developer mode.
  if (android::base::GetBoolProperty("ro.boot.disable_runas", false)) {
    error(1, 0, "run-as is disabled from the kernel commandline");
  }

  char* pkgname = argv[1];
  int cmd_argv_offset = 2;

  // Get user_id from command line if provided.
  int userId = 0;
  if ((argc >= 4) && !strcmp(argv[2], "--user")) {
    userId = atoi(argv[3]);
    if (userId < 0) error(1, 0, "negative user id: %d", userId);
    cmd_argv_offset += 2;
  }

  // Retrieve package information from system, switching egid so we can read the file.
  gid_t old_egid = getegid();
  if (setegid(AID_PACKAGE_INFO) == -1) error(1, errno, "setegid(AID_PACKAGE_INFO) failed");
  pkg_info info;
  memset(&info, 0, sizeof(info));
  info.name = pkgname;
  if (!packagelist_parse(packagelist_parse_callback, &info)) {
    error(1, errno, "packagelist_parse failed");
  }

  // Handle a multi-user data path
  if (userId > 0) {
    free(info.data_dir);
    if (asprintf(&info.data_dir, "/data/user/%d/%s", userId, pkgname) == -1) {
      error(1, errno, "asprintf failed");
    }
  }

  if (info.uid == 0) {
    error(1, 0, "unknown package: %s", pkgname);
  }
  if (setegid(old_egid) == -1) error(1, errno, "couldn't restore egid");

  // Verify that user id is not too big.
  if ((UID_MAX - info.uid) / AID_USER_OFFSET < (uid_t)userId) {
    error(1, 0, "user id too big: %d", userId);
  }

  // Calculate user app ID.
  uid_t userAppId = (AID_USER_OFFSET * userId) + info.uid;

  // Reject system packages.
  if (userAppId < AID_APP) {
    error(1, 0, "package not an application: %s", pkgname);
  }

  // Reject any non-debuggable package.
  if (!info.debuggable) {
    error(1, 0, "package not debuggable: %s", pkgname);
  }

  // Check that the data directory path is valid.
  if (!check_data_path(info.data_dir, userAppId)) {
    error(1, 0, "package has corrupt installation: %s", pkgname);
  }

  // Ensure that we change all real/effective/saved IDs at the
  // same time to avoid nasty surprises.
  uid_t uid = userAppId;
  uid_t gid = userAppId;
  ScopedMinijail j(minijail_new());
  minijail_change_uid(j.get(), uid);
  minijail_change_gid(j.get(), gid);
  minijail_keep_supplementary_gids(j.get());
  minijail_enter(j.get());

  std::string seinfo = std::string(info.seinfo) + ":fromRunAs";
  if (selinux_android_setcontext(uid, 0, seinfo.c_str(), pkgname) < 0) {
    error(1, errno, "couldn't set SELinux security context");
  }

  // cd into the data directory, and set $HOME correspondingly.
  if (TEMP_FAILURE_RETRY(chdir(info.data_dir)) == -1) {
    error(1, errno, "couldn't chdir to package's data directory");
  }
  setenv("HOME", info.data_dir, 1);

  // Reset parts of the environment, like su would.
  setenv("PATH", _PATH_DEFPATH, 1);
  unsetenv("IFS");

  // Set the user-specific parts for this user.
  passwd* pw = getpwuid(uid);
  setenv("LOGNAME", pw->pw_name, 1);
  setenv("SHELL", pw->pw_shell, 1);
  setenv("USER", pw->pw_name, 1);

  // User specified command for exec.
  if ((argc >= cmd_argv_offset + 1) &&
      (execvp(argv[cmd_argv_offset], argv+cmd_argv_offset) == -1)) {
    error(1, errno, "exec failed for %s", argv[cmd_argv_offset]);
  }

  // Default exec shell.
  execlp(_PATH_BSHELL, "sh", NULL);
  error(1, errno, "exec failed");
}