Skip to content

Commit 418ec8b

Browse files
author
git-core
committed
Pass the rest of arguments in the command line to a callee
Thus, someone may invoke su as su -s shell uid args... For example, su -s /system/xbin/busybox root mount -o rw,remount /system
1 parent ac59b39 commit 418ec8b

File tree

4 files changed

+65
-53
lines changed

4 files changed

+65
-53
lines changed

activity.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,10 @@ int send_intent(struct su_initiator *from, struct su_request *to, const char *so
110110
data.writeInt32(VAL_STRING);
111111
data.writeString16(String16("desired_cmd"));
112112
data.writeInt32(VAL_STRING);
113-
data.writeString16(String16(to->command));
113+
if (to->command)
114+
data.writeString16(String16(to->command));
115+
else
116+
data.writeString16(String16(to->shell));
114117

115118
data.writeInt32(VAL_STRING);
116119
data.writeString16(String16("socket"));

db.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static int db_check(sqlite3 *db, struct su_initiator *from, struct su_request *t
5252
sqlite3_snprintf(
5353
sizeof(sql), sql,
5454
"SELECT _id,name,allow FROM apps WHERE uid=%u AND exec_uid=%u AND exec_cmd='%q';",
55-
(unsigned)from->uid, to->uid, to->command
55+
(unsigned)from->uid, to->uid, (to->command) ? to->command : to->shell
5656
);
5757

5858
if (strlen(sql) >= sizeof(sql)-1)

su.c

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ static struct su_initiator su_from = {
5353
static struct su_request su_to = {
5454
.uid = AID_ROOT,
5555
.login = 0,
56-
.doshell = 1,
57-
.command = DEFAULT_COMMAND,
56+
.shell = DEFAULT_SHELL,
57+
.command = NULL,
58+
.argv = NULL,
59+
.argc = 0,
60+
.optind = 0,
5861
};
5962

6063
static int from_init(struct su_initiator *from)
@@ -206,6 +209,7 @@ static int socket_send_request(int fd, struct su_initiator *from, struct su_requ
206209
{
207210
size_t len;
208211
size_t bin_size, cmd_size;
212+
char *cmd;
209213

210214
#define write_token(fd, data) \
211215
do { \
@@ -230,9 +234,10 @@ do { \
230234
PLOGE("write(bin)");
231235
return -1;
232236
}
233-
cmd_size = strlen(to->command) + 1;
237+
cmd = (to->command) ? to->command : to->shell;
238+
cmd_size = strlen(cmd) + 1;
234239
write_token(fd, cmd_size);
235-
len = write(fd, to->command, cmd_size);
240+
len = write(fd, cmd, cmd_size);
236241
if (len != cmd_size) {
237242
PLOGE("write(cmd)");
238243
return -1;
@@ -259,13 +264,13 @@ static void usage(int status)
259264
FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
260265

261266
fprintf(stream,
262-
"Usage: su [options] [LOGIN]\n\n"
267+
"Usage: su [options] [--] [-] [LOGIN] [--] [args...]\n\n"
263268
"Options:\n"
264269
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
265270
" -h, --help display this help message and exit\n"
266271
" -, -l, --login, -m, -p,\n"
267272
" --preserve-environment do nothing, kept for compatibility\n"
268-
" -s, --shell SHELL use SHELL instead of the default " DEFAULT_COMMAND "\n"
273+
" -s, --shell SHELL use SHELL instead of the default " DEFAULT_SHELL "\n"
269274
" -v, --version display version number and exit\n"
270275
" -V display version code and exit,\n"
271276
" this is used almost exclusively by Superuser.apk\n");
@@ -276,40 +281,36 @@ static void deny(void)
276281
{
277282
struct su_initiator *from = &su_from;
278283
struct su_request *to = &su_to;
284+
char *cmd = (to->command) ? to->command : to->shell;
279285

280286
send_intent(&su_from, &su_to, "", 0, 1);
281-
LOGW("request rejected (%u->%u %s)", from->uid, to->uid, to->command);
287+
LOGW("request rejected (%u->%u %s)", from->uid, to->uid, cmd);
282288
fprintf(stderr, "%s\n", strerror(EACCES));
283289
exit(EXIT_FAILURE);
284290
}
285291

286-
static void allow(char *shell, mode_t mask)
292+
static void allow(void)
287293
{
288294
struct su_initiator *from = &su_from;
289295
struct su_request *to = &su_to;
290-
char *exe = NULL;
291-
char *argv[4];
292-
int argc = 0;
293-
int err;
296+
char *arg0;
297+
int argc, err;
294298

295-
umask(mask);
299+
umask(to->umask);
296300
send_intent(&su_from, &su_to, "", 1, 1);
297301

298-
if (!shell) {
299-
shell = DEFAULT_COMMAND;
300-
}
301-
exe = strrchr (shell, '/');
302-
exe = (exe) ? exe + 1 : shell;
302+
arg0 = strrchr (to->shell, '/');
303+
arg0 = (arg0) ? arg0 + 1 : to->shell;
303304
if (to->login) {
304-
int s = strlen(exe) + 2;
305+
int s = strlen(arg0) + 2;
305306
char *p = malloc(s);
306307

307308
if (!p)
308309
exit(EXIT_FAILURE);
309310

310311
*p = '-';
311-
strcpy(p + 1, exe);
312-
exe = p;
312+
strcpy(p + 1, arg0);
313+
arg0 = p;
313314
}
314315
if (setresgid(to->uid, to->uid, to->uid)) {
315316
PLOGE("setresgid (%u)", to->uid);
@@ -319,30 +320,34 @@ static void allow(char *shell, mode_t mask)
319320
PLOGE("setresuid (%u)", to->uid);
320321
exit(EXIT_FAILURE);
321322
}
322-
LOGD("%u %s executing %u %s using shell %s : %s", from->uid, from->bin,
323-
to->uid, to->command, shell, exe);
324-
argv[argc++] = exe;
325-
if (to->doshell) {
326-
argv[argc++] = "-";
327-
} else {
328-
argv[argc++] = "-c";
329-
argv[argc++] = to->command;
323+
324+
#define PARG(arg) (to->optind + (arg) < to->argc) ? " " : "", \
325+
(to->optind + (arg) < to->argc) ? to->argv[to->optind + (arg)] : ""
326+
LOGD("%u %s executing %u %s using shell %s : %s%s%s%s%s%s%s%s%s%s%s%s%s%s",
327+
from->uid, from->bin,
328+
to->uid, (to->command) ? to->command : to->shell, to->shell,
329+
arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5),
330+
(to->optind + 6 < to->argc) ? " ..." : "");
331+
332+
argc = to->optind;
333+
if (to->command) {
334+
to->argv[--argc] = to->command;
335+
to->argv[--argc] = "-c";
330336
}
331-
argv[argc] = NULL;
332-
execv(shell, argv);
337+
to->argv[--argc] = arg0;
338+
execv(to->shell, to->argv + argc);
333339
err = errno;
334340
PLOGE("exec");
335-
fprintf(stderr, "Cannot execute %s: %s\n", shell, strerror(err));
341+
fprintf(stderr, "Cannot execute %s: %s\n", to->shell, strerror(err));
336342
exit(EXIT_FAILURE);
337343
}
338344

339345
int main(int argc, char *argv[])
340346
{
341347
struct stat st;
342348
int socket_serv_fd, fd;
343-
char buf[64], *shell = NULL, *result;
349+
char buf[64], *result;
344350
int c, dballow;
345-
mode_t orig_umask;
346351
struct option long_opts[] = {
347352
{ "command", required_argument, NULL, 'c' },
348353
{ "help", no_argument, NULL, 'h' },
@@ -353,11 +358,10 @@ int main(int argc, char *argv[])
353358
{ NULL, 0, NULL, 0 },
354359
};
355360

356-
while ((c = getopt_long(argc, argv, "c:hlmps:Vv", long_opts, NULL)) != -1) {
361+
while ((c = getopt_long(argc, argv, "+c:hlmps:Vv", long_opts, NULL)) != -1) {
357362
switch(c) {
358363
case 'c':
359364
su_to.command = optarg;
360-
su_to.doshell = 0;
361365
break;
362366
case 'h':
363367
usage(EXIT_SUCCESS);
@@ -369,7 +373,7 @@ int main(int argc, char *argv[])
369373
case 'p':
370374
break;
371375
case 's':
372-
shell = optarg;
376+
su_to.shell = optarg;
373377
break;
374378
case 'V':
375379
printf("%d\n", VERSION_CODE);
@@ -387,14 +391,8 @@ int main(int argc, char *argv[])
387391
su_to.login = 1;
388392
optind++;
389393
}
390-
/*
391-
* Other su implementations pass the remaining args to the shell.
392-
* -- maybe implement this later
393-
*/
394-
if (optind < argc - 1) {
395-
usage(2);
396-
}
397-
if (optind == argc - 1) {
394+
/* username or uid */
395+
if (optind < argc && strcmp(argv[optind], "--")) {
398396
struct passwd *pw;
399397
pw = getpwnam(argv[optind]);
400398
if (!pw) {
@@ -411,16 +409,23 @@ int main(int argc, char *argv[])
411409
} else {
412410
su_to.uid = pw->pw_uid;
413411
}
412+
optind++;
413+
}
414+
if (optind < argc && !strcmp(argv[optind], "--")) {
415+
optind++;
414416
}
417+
su_to.argv = argv;
418+
su_to.argc = argc;
419+
su_to.optind = optind;
415420

416421
if (from_init(&su_from) < 0) {
417422
deny();
418423
}
419424

420-
orig_umask = umask(027);
425+
su_to.umask = umask(027);
421426

422427
if (su_from.uid == AID_ROOT || su_from.uid == AID_SHELL)
423-
allow(shell, orig_umask);
428+
allow();
424429

425430
if (stat(REQUESTOR_DATA_PATH, &st) < 0) {
426431
PLOGE("stat");
@@ -456,7 +461,7 @@ int main(int argc, char *argv[])
456461
dballow = database_check(&su_from, &su_to);
457462
switch (dballow) {
458463
case DB_DENY: deny();
459-
case DB_ALLOW: allow(shell, orig_umask);
464+
case DB_ALLOW: allow();
460465
case DB_INTERACTIVE: break;
461466
default: deny();
462467
}
@@ -504,7 +509,7 @@ int main(int argc, char *argv[])
504509
if (!strcmp(result, "DENY")) {
505510
deny();
506511
} else if (!strcmp(result, "ALLOW")) {
507-
allow(shell, orig_umask);
512+
allow();
508513
} else {
509514
LOGE("unknown response from Superuser Requestor: %s", result);
510515
deny();

su.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#define REQUESTOR_DATABASES_PATH REQUESTOR_DATA_PATH "/databases"
2626
#define REQUESTOR_DATABASE_PATH REQUESTOR_DATABASES_PATH "/permissions.sqlite"
2727

28-
#define DEFAULT_COMMAND "/system/bin/sh"
28+
#define DEFAULT_SHELL "/system/bin/sh"
2929

3030
#ifdef SU_LEGACY_BUILD
3131
#define VERSION_EXTRA "l"
@@ -49,8 +49,12 @@ struct su_initiator {
4949
struct su_request {
5050
unsigned uid;
5151
int login;
52-
int doshell;
52+
mode_t umask;
53+
char *shell;
5354
char *command;
55+
char **argv;
56+
int argc;
57+
int optind;
5458
};
5559

5660
enum {

0 commit comments

Comments
 (0)