|
15 | 15 | ** limitations under the License.
|
16 | 16 | */
|
17 | 17 |
|
| 18 | +#include <sys/types.h> |
18 | 19 | #include <unistd.h>
|
19 | 20 | #include <stdlib.h>
|
| 21 | +#include <fcntl.h> |
| 22 | +#include <paths.h> |
| 23 | +#include <sys/wait.h> |
20 | 24 |
|
21 | 25 | #include "su.h"
|
22 | 26 |
|
23 | 27 | int send_intent(const struct su_context *ctx,
|
24 | 28 | const char *socket_path, int allow, const char *action)
|
25 | 29 | {
|
26 |
| - char command[PATH_MAX]; |
27 |
| - pid_t euid; |
28 |
| - gid_t egid; |
29 | 30 | int rc;
|
30 | 31 |
|
31 |
| - sprintf(command, "/system/bin/am broadcast -a '%s' --es socket '%s' --ei caller_uid '%d' --ei allow '%d' --ei version_code '%d' > /dev/null", |
32 |
| - action, socket_path, ctx->from.uid, allow, VERSION_CODE); |
| 32 | + pid_t pid = fork(); |
| 33 | + /* Child */ |
| 34 | + if (!pid) { |
| 35 | + char command[ARG_MAX]; |
33 | 36 |
|
34 |
| - // before sending the intent, make sure the (uid and euid) and (gid and egid) match, |
35 |
| - // otherwise LD_LIBRARY_PATH is wiped in Android 4.0+. |
36 |
| - // Also, sanitize all secure environment variables (from linker_environ.c in linker). |
| 37 | + snprintf(command, sizeof(command), |
| 38 | + "exec /system/bin/am broadcast -a %s --es socket '%s' " |
| 39 | + "--ei caller_uid %d --ei allow %d " |
| 40 | + "--ei version_code %d", |
| 41 | + action, socket_path, ctx->from.uid, allow, VERSION_CODE); |
| 42 | + char *args[] = { "sh", "-c", command, NULL, }; |
37 | 43 |
|
38 |
| - /* The same list than GLibc at this point */ |
39 |
| - static const char* const unsec_vars[] = { |
40 |
| - "GCONV_PATH", |
41 |
| - "GETCONF_DIR", |
42 |
| - "HOSTALIASES", |
43 |
| - "LD_AUDIT", |
44 |
| - "LD_DEBUG", |
45 |
| - "LD_DEBUG_OUTPUT", |
46 |
| - "LD_DYNAMIC_WEAK", |
47 |
| - "LD_LIBRARY_PATH", |
48 |
| - "LD_ORIGIN_PATH", |
49 |
| - "LD_PRELOAD", |
50 |
| - "LD_PROFILE", |
51 |
| - "LD_SHOW_AUXV", |
52 |
| - "LD_USE_LOAD_BIAS", |
53 |
| - "LOCALDOMAIN", |
54 |
| - "LOCPATH", |
55 |
| - "MALLOC_TRACE", |
56 |
| - "MALLOC_CHECK_", |
57 |
| - "NIS_PATH", |
58 |
| - "NLSPATH", |
59 |
| - "RESOLV_HOST_CONF", |
60 |
| - "RES_OPTIONS", |
61 |
| - "TMPDIR", |
62 |
| - "TZDIR", |
63 |
| - "LD_AOUT_LIBRARY_PATH", |
64 |
| - "LD_AOUT_PRELOAD", |
65 |
| - // not listed in linker, used due to system() call |
66 |
| - "IFS", |
67 |
| - }; |
68 |
| - const char* const* cp = unsec_vars; |
69 |
| - const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]); |
70 |
| - while (cp < endp) { |
71 |
| - unsetenv(*cp); |
72 |
| - cp++; |
| 44 | + /* |
| 45 | + * before sending the intent, make sure the effective uid/gid match |
| 46 | + * the real uid/gid, otherwise LD_LIBRARY_PATH is wiped |
| 47 | + * in Android 4.0+. |
| 48 | + */ |
| 49 | + set_identity(ctx->from.uid); |
| 50 | + int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC); |
| 51 | + dup2(zero, 0); |
| 52 | + int null = open("/dev/null", O_WRONLY | O_CLOEXEC); |
| 53 | + dup2(null, 1); |
| 54 | + dup2(null, 2); |
| 55 | + LOGD("Executing %s\n", command); |
| 56 | + execv(_PATH_BSHELL, args); |
| 57 | + PLOGE("exec am"); |
| 58 | + _exit(EXIT_FAILURE); |
73 | 59 | }
|
74 |
| - |
75 |
| - // sane value so "am" works |
76 |
| - setenv("LD_LIBRARY_PATH", "/vendor/lib:/system/lib", 1); |
77 |
| - euid = geteuid(); |
78 |
| - egid = getegid(); |
79 |
| - setegid(getgid()); |
80 |
| - seteuid(getuid()); |
81 |
| - rc = system(command); |
82 |
| - seteuid(0); |
83 |
| - setegid(egid); |
84 |
| - seteuid(euid); |
85 |
| - return rc; |
| 60 | + /* Parent */ |
| 61 | + if (pid < 0) { |
| 62 | + PLOGE("fork"); |
| 63 | + return -1; |
| 64 | + } |
| 65 | + pid = waitpid(pid, &rc, 0); |
| 66 | + if (pid < 0) { |
| 67 | + PLOGE("waitpid"); |
| 68 | + return -1; |
| 69 | + } |
| 70 | + if (!WIFEXITED(rc) || WEXITSTATUS(rc)) { |
| 71 | + LOGE("am returned error %d\n", rc); |
| 72 | + return -1; |
| 73 | + } |
| 74 | + return 0; |
86 | 75 | }
|
0 commit comments