mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 20:07:39 +00:00
Support settings gids of su
This commit is contained in:
parent
f95478f1f1
commit
0e36e86dbf
@ -22,3 +22,17 @@ void write_int_be(int fd, int val);
|
|||||||
std::string read_string(int fd);
|
std::string read_string(int fd);
|
||||||
bool read_string(int fd, std::string &str);
|
bool read_string(int fd, std::string &str);
|
||||||
void write_string(int fd, std::string_view 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);
|
||||||
|
}
|
||||||
|
@ -166,7 +166,7 @@ void app_log(const su_context &ctx) {
|
|||||||
vector<Extra> extras;
|
vector<Extra> extras;
|
||||||
extras.reserve(6);
|
extras.reserve(6);
|
||||||
extras.emplace_back("from.uid", ctx.info->uid);
|
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("pid", ctx.pid);
|
||||||
extras.emplace_back("policy", ctx.info->access.policy);
|
extras.emplace_back("policy", ctx.info->access.policy);
|
||||||
extras.emplace_back("command", get_cmd(ctx.req));
|
extras.emplace_back("command", get_cmd(ctx.req));
|
||||||
|
@ -22,12 +22,12 @@
|
|||||||
|
|
||||||
int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 };
|
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;
|
FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
|
||||||
|
|
||||||
fprintf(stream,
|
fprintf(stream,
|
||||||
"MagiskSU\n\n"
|
"MagiskSU\n\n"
|
||||||
"Usage: su [options] [-] [user [argument...]]\n\n"
|
"Usage: su [options] [-] [user[:group,...] [argument...]]\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
|
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
|
||||||
" -h, --help display this help message and exit\n"
|
" -h, --help display this help message and exit\n"
|
||||||
@ -110,7 +110,6 @@ int su_client_main(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(EXIT_SUCCESS);
|
usage(EXIT_SUCCESS);
|
||||||
break;
|
|
||||||
case 'l':
|
case 'l':
|
||||||
su_req.login = true;
|
su_req.login = true;
|
||||||
break;
|
break;
|
||||||
@ -146,12 +145,19 @@ int su_client_main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
/* username or uid */
|
/* username or uid */
|
||||||
if (optind < argc) {
|
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;
|
struct passwd *pw;
|
||||||
pw = getpwnam(argv[optind]);
|
pw = getpwnam(user.data());
|
||||||
if (pw)
|
su_req.uid = pw ? pw->pw_uid : parse_int(user);
|
||||||
su_req.uid = pw->pw_uid;
|
if (sep.size() == 2) {
|
||||||
else
|
for (auto group : split_view(sep[1], ",")) {
|
||||||
su_req.uid = parse_int(argv[optind]);
|
pw = getpwnam(std::string(group).data());
|
||||||
|
su_req.gids.push_back(pw ? pw->pw_gid : parse_int(group));
|
||||||
|
}
|
||||||
|
}
|
||||||
optind++;
|
optind++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +170,7 @@ int su_client_main(int argc, char *argv[]) {
|
|||||||
xwrite(fd, &su_req, sizeof(su_req_base));
|
xwrite(fd, &su_req, sizeof(su_req_base));
|
||||||
write_string(fd, su_req.shell);
|
write_string(fd, su_req.shell);
|
||||||
write_string(fd, su_req.command);
|
write_string(fd, su_req.command);
|
||||||
|
write_vector(fd, su_req.gids);
|
||||||
|
|
||||||
// Wait for ack from daemon
|
// Wait for ack from daemon
|
||||||
if (read_int(fd)) {
|
if (read_int(fd)) {
|
||||||
|
@ -42,7 +42,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct su_req_base {
|
struct su_req_base {
|
||||||
int uid = AID_ROOT;
|
uid_t uid = AID_ROOT;
|
||||||
bool login = false;
|
bool login = false;
|
||||||
bool keepenv = false;
|
bool keepenv = false;
|
||||||
bool mount_master = false;
|
bool mount_master = false;
|
||||||
@ -51,6 +51,7 @@ struct su_req_base {
|
|||||||
struct su_request : public su_req_base {
|
struct su_request : public su_req_base {
|
||||||
std::string shell = DEFAULT_SHELL;
|
std::string shell = DEFAULT_SHELL;
|
||||||
std::string command;
|
std::string command;
|
||||||
|
std::vector<gid_t> gids;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct su_context {
|
struct su_context {
|
||||||
|
@ -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
|
// 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)) {
|
if (seteuid(0)) {
|
||||||
PLOGE("seteuid (root)");
|
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);
|
PLOGE("setresgid (%u)", uid);
|
||||||
}
|
}
|
||||||
if (setresuid(uid, uid, uid)) {
|
if (setresuid(uid, uid, uid)) {
|
||||||
@ -254,7 +263,8 @@ void su_daemon_handler(int client, const sock_cred *cred) {
|
|||||||
// Read su_request
|
// Read su_request
|
||||||
if (xxread(client, &ctx.req, sizeof(su_req_base)) < 0
|
if (xxread(client, &ctx.req, sizeof(su_req_base)) < 0
|
||||||
|| !read_string(client, ctx.req.shell)
|
|| !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");
|
LOGW("su: remote process probably died, abort\n");
|
||||||
ctx.info.reset();
|
ctx.info.reset();
|
||||||
write_int(client, DENY);
|
write_int(client, DENY);
|
||||||
@ -443,7 +453,7 @@ void su_daemon_handler(int client, const sock_cred *cred) {
|
|||||||
sigset_t block_set;
|
sigset_t block_set;
|
||||||
sigemptyset(&block_set);
|
sigemptyset(&block_set);
|
||||||
sigprocmask(SIG_SETMASK, &block_set, nullptr);
|
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);
|
execvp(ctx.req.shell.data(), (char **) argv);
|
||||||
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell.data(), strerror(errno));
|
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell.data(), strerror(errno));
|
||||||
PLOGE("exec");
|
PLOGE("exec");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user