Skip to content

Commit d80df98

Browse files
committed
su: pass all unknown options
1 parent 608786e commit d80df98

4 files changed

Lines changed: 49 additions & 61 deletions

File tree

native/src/core/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,8 @@ pub mod ffi {
115115
struct SuRequest {
116116
target_uid: i32,
117117
target_pid: i32,
118-
login: bool,
119118
keep_env: bool,
120-
shell: String,
121-
command: String,
119+
command: Vec<String>,
122120
context: String,
123121
gids: Vec<u32>,
124122
}

native/src/core/su/connect.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,11 @@ static void exec_cmd(const char *action, vector<Extra> &data,
165165
void app_log(const SuAppRequest &info, SuPolicy policy, bool notify) {
166166
if (fork_dont_care() == 0) {
167167
string context = (string) info.request.context;
168-
string command = info.request.command.empty()
169-
? (string) info.request.shell
170-
: (string) info.request.command;
168+
string command;
169+
for (auto &str: info.request.command) {
170+
if (!command.empty()) command += " ";
171+
command += str.data();
172+
}
171173

172174
vector<Extra> extras;
173175
extras.reserve(9);

native/src/core/su/daemon.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@ use std::os::unix::net::UnixStream;
1313
use std::sync::{Arc, Mutex};
1414
use std::time::{Duration, Instant};
1515

16-
const DEFAULT_SHELL: &str = "/system/bin/sh";
17-
1816
impl Default for SuRequest {
1917
fn default() -> Self {
2018
SuRequest {
2119
target_uid: AID_ROOT,
2220
target_pid: -1,
23-
login: false,
2421
keep_env: false,
25-
shell: DEFAULT_SHELL.to_string(),
26-
command: "".to_string(),
22+
command: vec![],
2723
context: "".to_string(),
2824
gids: vec![],
2925
}

native/src/core/su/su.cpp

Lines changed: 42 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,20 @@ int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGI
3838
"MagiskSU\n\n"
3939
"Usage: su [options] [-] [user [argument...]]\n\n"
4040
"Options:\n"
41-
" -c, --command COMMAND Pass COMMAND to the invoked shell\n"
42-
" -i, --interactive Force pseudo-terminal allocation when using -c\n"
41+
" -s, --shell SHELL Use SHELL instead of the default " DEFAULT_SHELL "\n"
42+
" -i, --interactive Force pseudo-terminal allocation\n"
4343
" -g, --group GROUP Specify the primary group\n"
4444
" -G, --supp-group GROUP Specify a supplementary group\n"
4545
" The first specified supplementary group is also used\n"
4646
" as a primary group if the option -g is not specified\n"
4747
" -Z, --context CONTEXT Change SELinux context\n"
4848
" -t, --target PID PID to take mount namespace from\n"
49-
" -h, --help Display this help message and exit\n"
50-
" -, -l, --login Pretend the shell to be a login shell\n"
49+
" pid 0 means magisk global mount namespace"
5150
" -m, -p,\n"
5251
" --preserve-environment Preserve the entire environment\n"
53-
" -s, --shell SHELL Use SHELL instead of the default " DEFAULT_SHELL "\n"
5452
" -v, --version Display version number and exit\n"
5553
" -V Display version code and exit\n"
56-
" -mm, -M,\n"
57-
" --mount-master Force run in the global mount namespace\n\n");
54+
" -h, --help Display this help message and exit\n\n");
5855
exit(status);
5956
}
6057

@@ -92,10 +89,9 @@ static void setup_sighandlers(void (*handler)(int)) {
9289

9390
int su_client_main(int argc, char *argv[]) {
9491
int c;
92+
opterr = 0;
9593
struct option long_opts[] = {
96-
{ "command", required_argument, nullptr, 'c' },
9794
{ "help", no_argument, nullptr, 'h' },
98-
{ "login", no_argument, nullptr, 'l' },
9995
{ "preserve-environment", no_argument, nullptr, 'p' },
10096
{ "shell", required_argument, nullptr, 's' },
10197
{ "version", no_argument, nullptr, 'v' },
@@ -120,34 +116,21 @@ int su_client_main(int argc, char *argv[]) {
120116
}
121117

122118
bool interactive = false;
119+
string shell = DEFAULT_SHELL;
123120

124-
while ((c = getopt_long(argc, argv, "c:hlimps:VvuZ:Mt:g:G:", long_opts, nullptr)) != -1) {
121+
while ((c = getopt_long(argc, argv, "+:himps:VvuZ:Mt:g:G:", long_opts, nullptr)) != -1) {
125122
switch (c) {
126-
case 'c': {
127-
string command;
128-
for (int i = optind - 1; i < argc; ++i) {
129-
if (!command.empty())
130-
command += ' ';
131-
command += argv[i];
132-
}
133-
req.command = command;
134-
optind = argc;
135-
break;
136-
}
137123
case 'h':
138124
usage(EXIT_SUCCESS);
139125
case 'i':
140126
interactive = true;
141127
break;
142-
case 'l':
143-
req.login = true;
144-
break;
145128
case 'm':
146129
case 'p':
147130
req.keep_env = true;
148131
break;
149132
case 's':
150-
req.shell = optarg;
133+
shell = optarg;
151134
break;
152135
case 'V':
153136
printf("%d\n", MAGISK_VER_CODE);
@@ -176,36 +159,48 @@ int su_client_main(int argc, char *argv[]) {
176159
break;
177160
case 'g':
178161
case 'G': {
179-
vector<gid_t> gids;
180162
if (int gid = parse_int(optarg); gid >= 0) {
181-
gids.insert(c == 'g' ? gids.begin() : gids.end(), gid);
163+
if (c == 'g' && !req.gids.empty()) {
164+
req.gids.push_back(req.gids[0]);
165+
req.gids[0] = gid;
166+
} else {
167+
req.gids.push_back(gid);
168+
}
182169
} else {
183170
fprintf(stderr, "Invalid GID: %s\n", optarg);
184171
usage(EXIT_FAILURE);
185172
}
186-
std::copy(gids.begin(), gids.end(), std::back_inserter(req.gids));
187173
break;
188174
}
189-
default:
190-
/* Bionic getopt_long doesn't terminate its error output by newline */
191-
fprintf(stderr, "\n");
175+
case ':':
176+
fprintf(stderr, "option '%s' requires an argument\n", argv[optind - 1]);
192177
usage(2);
178+
case '?':
179+
optind--;
180+
goto end;
193181
}
194182
}
195183

196-
if (optind < argc && strcmp(argv[optind], "-") == 0) {
197-
req.login = true;
198-
optind++;
199-
}
184+
end:
200185
/* username or uid */
201186
if (optind < argc) {
202187
struct passwd *pw;
203188
pw = getpwnam(argv[optind]);
204-
if (pw)
189+
if (pw) {
205190
req.target_uid = pw->pw_uid;
206-
else
207-
req.target_uid = parse_int(argv[optind]);
208-
optind++;
191+
optind++;
192+
} else if (int uid = parse_int(argv[optind]); uid >= 0) {
193+
req.target_uid = uid;
194+
optind++;
195+
}
196+
}
197+
198+
req.command.emplace_back(shell.c_str());
199+
if (optind < argc) {
200+
for (int i = optind; i < argc; ++i) {
201+
req.command.push_back(argv[i]);
202+
}
203+
optind = argc;
209204
}
210205

211206
int ptmx, fd;
@@ -224,7 +219,7 @@ int su_client_main(int argc, char *argv[]) {
224219
}
225220

226221
// Determine which one of our streams are attached to a TTY
227-
interactive |= req.command.empty();
222+
interactive |= req.command.size() == 1;
228223
int atty = 0;
229224
if (isatty(STDIN_FILENO) && interactive) atty |= ATTY_IN;
230225
if (isatty(STDOUT_FILENO) && interactive) atty |= ATTY_OUT;
@@ -368,14 +363,11 @@ void exec_root_shell(int client, int pid, SuRequest &req, MntNsMode mode) {
368363
break;
369364
}
370365

371-
const char *argv[4] = { nullptr };
372-
373-
argv[0] = req.login ? "-" : req.shell.c_str();
374-
375-
if (!req.command.empty()) {
376-
argv[1] = "-c";
377-
argv[2] = req.command.c_str();
366+
vector<const char *> argv;
367+
for (auto &str: req.command) {
368+
argv.push_back(str.c_str());
378369
}
370+
argv.push_back(nullptr);
379371

380372
// Setup environment
381373
umask(022);
@@ -400,7 +392,7 @@ void exec_root_shell(int client, int pid, SuRequest &req, MntNsMode mode) {
400392
setenv("HOME", pw->pw_dir, 1);
401393
setenv("USER", pw->pw_name, 1);
402394
setenv("LOGNAME", pw->pw_name, 1);
403-
setenv("SHELL", req.shell.c_str(), 1);
395+
setenv("SHELL", argv[0], 1);
404396
}
405397
}
406398

@@ -413,7 +405,7 @@ void exec_root_shell(int client, int pid, SuRequest &req, MntNsMode mode) {
413405
if (f) fprintf(f.get(), "%s", req.context.c_str());
414406
}
415407
set_identity(req.target_uid, req.gids);
416-
execvp(req.shell.c_str(), (char **) argv);
417-
fprintf(stderr, "Cannot execute %s: %s\n", req.shell.c_str(), strerror(errno));
408+
execvp(argv[0], const_cast<char* const*>(argv.data()));
409+
fprintf(stderr, "Cannot execute %s: %s\n", argv[0], strerror(errno));
418410
PLOGE("exec");
419411
}

0 commit comments

Comments
 (0)