Support settings gids of su

This commit is contained in:
LoveSy 2023-05-16 19:26:44 +08:00 committed by John Wu
parent f95478f1f1
commit 0e36e86dbf
5 changed files with 46 additions and 14 deletions

View File

@ -22,3 +22,17 @@ void write_int_be(int fd, int val);
std::string read_string(int fd);
bool read_string(int fd, std::string &str);
void write_string(int fd, std::string_view str);
template<typename T> requires(std::is_trivially_copyable_v<T>)
void write_vector(int fd, const std::vector<T> &vec) {
write_int(fd, static_cast<int>(vec.size()));
xwrite(fd, vec.data(), vec.size() * sizeof(T));
}
template<typename T> requires(std::is_trivially_copyable_v<T>)
bool read_vector(int fd, std::vector<T> &vec) {
int size = read_int(fd);
if (size == -1) return false;
vec.resize(size);
return xread(fd, vec.data(), size * sizeof(T)) == size * sizeof(T);
}

View File

@ -166,7 +166,7 @@ void app_log(const su_context &ctx) {
vector<Extra> extras;
extras.reserve(6);
extras.emplace_back("from.uid", ctx.info->uid);
extras.emplace_back("to.uid", ctx.req.uid);
extras.emplace_back("to.uid", static_cast<int>(ctx.req.uid));
extras.emplace_back("pid", ctx.pid);
extras.emplace_back("policy", ctx.info->access.policy);
extras.emplace_back("command", get_cmd(ctx.req));

View File

@ -22,12 +22,12 @@
int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 };
static void usage(int status) {
[[noreturn]] static void usage(int status) {
FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
fprintf(stream,
"MagiskSU\n\n"
"Usage: su [options] [-] [user [argument...]]\n\n"
"Usage: su [options] [-] [user[:group,...] [argument...]]\n\n"
"Options:\n"
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
" -h, --help display this help message and exit\n"
@ -110,7 +110,6 @@ int su_client_main(int argc, char *argv[]) {
break;
case 'h':
usage(EXIT_SUCCESS);
break;
case 'l':
su_req.login = true;
break;
@ -146,12 +145,19 @@ int su_client_main(int argc, char *argv[]) {
}
/* username or uid */
if (optind < argc) {
std::string_view uidgid = argv[optind];
auto sep = split_view(uidgid, ":");
if (sep.size() > 2) usage(EXIT_FAILURE);
auto user = std::string(sep[0]);
struct passwd *pw;
pw = getpwnam(argv[optind]);
if (pw)
su_req.uid = pw->pw_uid;
else
su_req.uid = parse_int(argv[optind]);
pw = getpwnam(user.data());
su_req.uid = pw ? pw->pw_uid : parse_int(user);
if (sep.size() == 2) {
for (auto group : split_view(sep[1], ",")) {
pw = getpwnam(std::string(group).data());
su_req.gids.push_back(pw ? pw->pw_gid : parse_int(group));
}
}
optind++;
}
@ -164,6 +170,7 @@ int su_client_main(int argc, char *argv[]) {
xwrite(fd, &su_req, sizeof(su_req_base));
write_string(fd, su_req.shell);
write_string(fd, su_req.command);
write_vector(fd, su_req.gids);
// Wait for ack from daemon
if (read_int(fd)) {

View File

@ -42,7 +42,7 @@ private:
};
struct su_req_base {
int uid = AID_ROOT;
uid_t uid = AID_ROOT;
bool login = false;
bool keepenv = false;
bool mount_master = false;
@ -51,6 +51,7 @@ struct su_req_base {
struct su_request : public su_req_base {
std::string shell = DEFAULT_SHELL;
std::string command;
std::vector<gid_t> gids;
};
struct su_context {

View File

@ -230,11 +230,20 @@ static shared_ptr<su_info> get_su_info(unsigned uid) {
}
// Set effective uid back to root, otherwise setres[ug]id will fail if uid isn't root
static void set_identity(unsigned uid) {
static void set_identity(uid_t uid, const std::vector<uid_t> &groups) {
if (seteuid(0)) {
PLOGE("seteuid (root)");
}
if (setresgid(uid, uid, uid)) {
gid_t gid;
if (groups.size() > 0) {
if (setgroups(groups.size(), groups.data())) {
PLOGE("setgroups");
}
gid = groups[0];
} else {
gid = uid;
}
if (setresgid(gid, gid, gid)) {
PLOGE("setresgid (%u)", uid);
}
if (setresuid(uid, uid, uid)) {
@ -254,7 +263,8 @@ void su_daemon_handler(int client, const sock_cred *cred) {
// Read su_request
if (xxread(client, &ctx.req, sizeof(su_req_base)) < 0
|| !read_string(client, ctx.req.shell)
|| !read_string(client, ctx.req.command)) {
|| !read_string(client, ctx.req.command)
|| !read_vector(client, ctx.req.gids)) {
LOGW("su: remote process probably died, abort\n");
ctx.info.reset();
write_int(client, DENY);
@ -443,7 +453,7 @@ void su_daemon_handler(int client, const sock_cred *cred) {
sigset_t block_set;
sigemptyset(&block_set);
sigprocmask(SIG_SETMASK, &block_set, nullptr);
set_identity(ctx.req.uid);
set_identity(ctx.req.uid, ctx.req.gids);
execvp(ctx.req.shell.data(), (char **) argv);
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell.data(), strerror(errno));
PLOGE("exec");