summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner2010-03-02 20:05:23 -0600
committerDavid 'Digit' Turner2010-03-17 13:02:08 -0500
commit1f4d95296acf34a93128332441782a80c10845b4 (patch)
tree2b8cf38a4716b2c622c564d3a7da82022cdaf9c9
parent5fc070be8593f39f5140ab63fb6f5eccceb1dc83 (diff)
downloadplatform-system-core-1f4d95296acf34a93128332441782a80c10845b4.tar.gz
platform-system-core-1f4d95296acf34a93128332441782a80c10845b4.tar.xz
platform-system-core-1f4d95296acf34a93128332441782a80c10845b4.zip
Add 'run-as' command implementation as set-uid program.
Typical usage is 'run-as <package-name> <command>' to run <command> in the data directory, and the user id, of <package-name> if, and only if <package-name> is the name of an installed and debuggable application. This relies on the /data/system/packages.list file generated by the PackageManager service. BEWARE: This is intended to be available on production devices !
-rw-r--r--include/private/android_filesystem_config.h5
-rw-r--r--run-as/Android.mk12
-rw-r--r--run-as/NOTICE190
-rw-r--r--run-as/package.c471
-rw-r--r--run-as/package.h41
-rw-r--r--run-as/run-as.c178
6 files changed, 896 insertions, 1 deletions
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index f2a5fe1af..4cab96a40 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -169,7 +169,7 @@ static struct fs_path_config android_files[] = {
169 * Do not change. */ 169 * Do not change. */
170 { 02755, AID_ROOT, AID_NET_RAW, "system/bin/ping" }, 170 { 02755, AID_ROOT, AID_NET_RAW, "system/bin/ping" },
171 { 02750, AID_ROOT, AID_INET, "system/bin/netcfg" }, 171 { 02750, AID_ROOT, AID_INET, "system/bin/netcfg" },
172 /* the following four files are INTENTIONALLY set-uid, but they 172 /* the following five files are INTENTIONALLY set-uid, but they
173 * are NOT included on user builds. */ 173 * are NOT included on user builds. */
174 { 06755, AID_ROOT, AID_ROOT, "system/xbin/su" }, 174 { 06755, AID_ROOT, AID_ROOT, "system/xbin/su" },
175 { 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" }, 175 { 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" },
@@ -177,6 +177,9 @@ static struct fs_path_config android_files[] = {
177 { 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" }, 177 { 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" },
178 { 06755, AID_ROOT, AID_ROOT, "system/xbin/tcpdump" }, 178 { 06755, AID_ROOT, AID_ROOT, "system/xbin/tcpdump" },
179 { 04770, AID_ROOT, AID_RADIO, "system/bin/pppd-ril" }, 179 { 04770, AID_ROOT, AID_RADIO, "system/bin/pppd-ril" },
180 /* the following file is INTENTIONALLY set-uid, and IS included
181 * in user builds. */
182 { 06750, AID_ROOT, AID_SHELL, "system/bin/run-as" },
180 { 00755, AID_ROOT, AID_SHELL, "system/bin/*" }, 183 { 00755, AID_ROOT, AID_SHELL, "system/bin/*" },
181 { 00755, AID_ROOT, AID_SHELL, "system/xbin/*" }, 184 { 00755, AID_ROOT, AID_SHELL, "system/xbin/*" },
182 { 00750, AID_ROOT, AID_SHELL, "sbin/*" }, 185 { 00750, AID_ROOT, AID_SHELL, "sbin/*" },
diff --git a/run-as/Android.mk b/run-as/Android.mk
new file mode 100644
index 000000000..326f5afeb
--- /dev/null
+++ b/run-as/Android.mk
@@ -0,0 +1,12 @@
1LOCAL_PATH:= $(call my-dir)
2include $(CLEAR_VARS)
3
4LOCAL_SRC_FILES:= run-as.c package.c
5
6LOCAL_MODULE:= run-as
7
8LOCAL_FORCE_STATIC_EXECUTABLE := true
9
10LOCAL_STATIC_LIBRARIES := libc
11
12include $(BUILD_EXECUTABLE)
diff --git a/run-as/NOTICE b/run-as/NOTICE
new file mode 100644
index 000000000..c5b1efa7a
--- /dev/null
+++ b/run-as/NOTICE
@@ -0,0 +1,190 @@
1
2 Copyright (c) 2005-2008, The Android Open Source Project
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
12
13
14 Apache License
15 Version 2.0, January 2004
16 http://www.apache.org/licenses/
17
18 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
19
20 1. Definitions.
21
22 "License" shall mean the terms and conditions for use, reproduction,
23 and distribution as defined by Sections 1 through 9 of this document.
24
25 "Licensor" shall mean the copyright owner or entity authorized by
26 the copyright owner that is granting the License.
27
28 "Legal Entity" shall mean the union of the acting entity and all
29 other entities that control, are controlled by, or are under common
30 control with that entity. For the purposes of this definition,
31 "control" means (i) the power, direct or indirect, to cause the
32 direction or management of such entity, whether by contract or
33 otherwise, or (ii) ownership of fifty percent (50%) or more of the
34 outstanding shares, or (iii) beneficial ownership of such entity.
35
36 "You" (or "Your") shall mean an individual or Legal Entity
37 exercising permissions granted by this License.
38
39 "Source" form shall mean the preferred form for making modifications,
40 including but not limited to software source code, documentation
41 source, and configuration files.
42
43 "Object" form shall mean any form resulting from mechanical
44 transformation or translation of a Source form, including but
45 not limited to compiled object code, generated documentation,
46 and conversions to other media types.
47
48 "Work" shall mean the work of authorship, whether in Source or
49 Object form, made available under the License, as indicated by a
50 copyright notice that is included in or attached to the work
51 (an example is provided in the Appendix below).
52
53 "Derivative Works" shall mean any work, whether in Source or Object
54 form, that is based on (or derived from) the Work and for which the
55 editorial revisions, annotations, elaborations, or other modifications
56 represent, as a whole, an original work of authorship. For the purposes
57 of this License, Derivative Works shall not include works that remain
58 separable from, or merely link (or bind by name) to the interfaces of,
59 the Work and Derivative Works thereof.
60
61 "Contribution" shall mean any work of authorship, including
62 the original version of the Work and any modifications or additions
63 to that Work or Derivative Works thereof, that is intentionally
64 submitted to Licensor for inclusion in the Work by the copyright owner
65 or by an individual or Legal Entity authorized to submit on behalf of
66 the copyright owner. For the purposes of this definition, "submitted"
67 means any form of electronic, verbal, or written communication sent
68 to the Licensor or its representatives, including but not limited to
69 communication on electronic mailing lists, source code control systems,
70 and issue tracking systems that are managed by, or on behalf of, the
71 Licensor for the purpose of discussing and improving the Work, but
72 excluding communication that is conspicuously marked or otherwise
73 designated in writing by the copyright owner as "Not a Contribution."
74
75 "Contributor" shall mean Licensor and any individual or Legal Entity
76 on behalf of whom a Contribution has been received by Licensor and
77 subsequently incorporated within the Work.
78
79 2. Grant of Copyright License. Subject to the terms and conditions of
80 this License, each Contributor hereby grants to You a perpetual,
81 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
82 copyright license to reproduce, prepare Derivative Works of,
83 publicly display, publicly perform, sublicense, and distribute the
84 Work and such Derivative Works in Source or Object form.
85
86 3. Grant of Patent License. Subject to the terms and conditions of
87 this License, each Contributor hereby grants to You a perpetual,
88 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
89 (except as stated in this section) patent license to make, have made,
90 use, offer to sell, sell, import, and otherwise transfer the Work,
91 where such license applies only to those patent claims licensable
92 by such Contributor that are necessarily infringed by their
93 Contribution(s) alone or by combination of their Contribution(s)
94 with the Work to which such Contribution(s) was submitted. If You
95 institute patent litigation against any entity (including a
96 cross-claim or counterclaim in a lawsuit) alleging that the Work
97 or a Contribution incorporated within the Work constitutes direct
98 or contributory patent infringement, then any patent licenses
99 granted to You under this License for that Work shall terminate
100 as of the date such litigation is filed.
101
102 4. Redistribution. You may reproduce and distribute copies of the
103 Work or Derivative Works thereof in any medium, with or without
104 modifications, and in Source or Object form, provided that You
105 meet the following conditions:
106
107 (a) You must give any other recipients of the Work or
108 Derivative Works a copy of this License; and
109
110 (b) You must cause any modified files to carry prominent notices
111 stating that You changed the files; and
112
113 (c) You must retain, in the Source form of any Derivative Works
114 that You distribute, all copyright, patent, trademark, and
115 attribution notices from the Source form of the Work,
116 excluding those notices that do not pertain to any part of
117 the Derivative Works; and
118
119 (d) If the Work includes a "NOTICE" text file as part of its
120 distribution, then any Derivative Works that You distribute must
121 include a readable copy of the attribution notices contained
122 within such NOTICE file, excluding those notices that do not
123 pertain to any part of the Derivative Works, in at least one
124 of the following places: within a NOTICE text file distributed
125 as part of the Derivative Works; within the Source form or
126 documentation, if provided along with the Derivative Works; or,
127 within a display generated by the Derivative Works, if and
128 wherever such third-party notices normally appear. The contents
129 of the NOTICE file are for informational purposes only and
130 do not modify the License. You may add Your own attribution
131 notices within Derivative Works that You distribute, alongside
132 or as an addendum to the NOTICE text from the Work, provided
133 that such additional attribution notices cannot be construed
134 as modifying the License.
135
136 You may add Your own copyright statement to Your modifications and
137 may provide additional or different license terms and conditions
138 for use, reproduction, or distribution of Your modifications, or
139 for any such Derivative Works as a whole, provided Your use,
140 reproduction, and distribution of the Work otherwise complies with
141 the conditions stated in this License.
142
143 5. Submission of Contributions. Unless You explicitly state otherwise,
144 any Contribution intentionally submitted for inclusion in the Work
145 by You to the Licensor shall be under the terms and conditions of
146 this License, without any additional terms or conditions.
147 Notwithstanding the above, nothing herein shall supersede or modify
148 the terms of any separate license agreement you may have executed
149 with Licensor regarding such Contributions.
150
151 6. Trademarks. This License does not grant permission to use the trade
152 names, trademarks, service marks, or product names of the Licensor,
153 except as required for reasonable and customary use in describing the
154 origin of the Work and reproducing the content of the NOTICE file.
155
156 7. Disclaimer of Warranty. Unless required by applicable law or
157 agreed to in writing, Licensor provides the Work (and each
158 Contributor provides its Contributions) on an "AS IS" BASIS,
159 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
160 implied, including, without limitation, any warranties or conditions
161 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
162 PARTICULAR PURPOSE. You are solely responsible for determining the
163 appropriateness of using or redistributing the Work and assume any
164 risks associated with Your exercise of permissions under this License.
165
166 8. Limitation of Liability. In no event and under no legal theory,
167 whether in tort (including negligence), contract, or otherwise,
168 unless required by applicable law (such as deliberate and grossly
169 negligent acts) or agreed to in writing, shall any Contributor be
170 liable to You for damages, including any direct, indirect, special,
171 incidental, or consequential damages of any character arising as a
172 result of this License or out of the use or inability to use the
173 Work (including but not limited to damages for loss of goodwill,
174 work stoppage, computer failure or malfunction, or any and all
175 other commercial damages or losses), even if such Contributor
176 has been advised of the possibility of such damages.
177
178 9. Accepting Warranty or Additional Liability. While redistributing
179 the Work or Derivative Works thereof, You may choose to offer,
180 and charge a fee for, acceptance of support, warranty, indemnity,
181 or other liability obligations and/or rights consistent with this
182 License. However, in accepting such obligations, You may act only
183 on Your own behalf and on Your sole responsibility, not on behalf
184 of any other Contributor, and only if You agree to indemnify,
185 defend, and hold each Contributor harmless for any liability
186 incurred by, or claims asserted against, such Contributor by reason
187 of your accepting any such warranty or additional liability.
188
189 END OF TERMS AND CONDITIONS
190
diff --git a/run-as/package.c b/run-as/package.c
new file mode 100644
index 000000000..46f8239c3
--- /dev/null
+++ b/run-as/package.c
@@ -0,0 +1,471 @@
1/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17#include <errno.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <sys/stat.h>
21#include <private/android_filesystem_config.h>
22#include "package.h"
23
24/*
25 * WARNING WARNING WARNING WARNING
26 *
27 * The following code runs as root on production devices, before
28 * the run-as command has dropped the uid/gid. Hence be very
29 * conservative and keep in mind the following:
30 *
31 * - Performance does not matter here, clarity and safety of the code
32 * does however. Documentation is a must.
33 *
34 * - Avoid calling C library functions with complex implementations
35 * like malloc() and printf(). You want to depend on simple system
36 * calls instead, which behaviour is not going to be altered in
37 * unpredictible ways by environment variables or system properties.
38 *
39 * - Do not trust user input and/or the filesystem whenever possible.
40 *
41 */
42
43/* The file containing the list of installed packages on the system */
44#define PACKAGES_LIST_FILE "/data/system/packages.list"
45
46/* This should be large enough to hold the content of the package database file */
47#define PACKAGES_LIST_BUFFER_SIZE 8192
48
49/* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
50 * This function always zero-terminate the destination buffer unless
51 * 'dstlen' is 0, even in case of overflow.
52 */
53static void
54string_copy(char* dst, size_t dstlen, const char* src, size_t srclen)
55{
56 const char* srcend = src + srclen;
57 const char* dstend = dst + dstlen;
58
59 if (dstlen == 0)
60 return;
61
62 dstend--; /* make room for terminating zero */
63
64 while (dst < dstend && src < srcend && *src != '\0')
65 *dst++ = *src++;
66
67 *dst = '\0'; /* zero-terminate result */
68}
69
70/* Read up to 'buffsize' bytes into 'buff' from the file
71 * named 'filename'. Return byte length on success, or -1
72 * on error.
73 */
74static int
75read_file(const char* filename, char* buff, size_t buffsize)
76{
77 int fd, len, old_errno;
78
79 /* check the input buffer size */
80 if (buffsize >= INT_MAX) {
81 errno = EINVAL;
82 return -1;
83 }
84
85 /* open the file for reading */
86 do {
87 fd = open(filename, O_RDONLY);
88 } while (fd < 0 && errno == EINTR);
89
90 if (fd < 0)
91 return -1;
92
93 /* read the content */
94 do {
95 len = read(fd, buff, buffsize);
96 } while (len < 0 && errno == EINTR);
97
98 /* close the file, preserve old errno for better diagnostics */
99 old_errno = errno;
100 close(fd);
101 errno = old_errno;
102
103 return len;
104}
105
106/* Check that a given directory:
107 * - exists
108 * - is owned by a given uid/gid
109 * - is a real directory, not a symlink
110 * - isn't readable or writable by others
111 *
112 * Return 0 on success, or -1 on error.
113 * errno is set to EINVAL in case of failed check.
114 */
115static int
116check_directory_ownership(const char* path, uid_t uid)
117{
118 int ret;
119 struct stat st;
120
121 do {
122 ret = lstat(path, &st);
123 } while (ret < 0 && errno == EINTR);
124
125 if (ret < 0)
126 return -1;
127
128 /* must be a real directory, not a symlink */
129 if (!S_ISDIR(st.st_mode))
130 goto BAD;
131
132 /* must be owned by specific uid/gid */
133 if (st.st_uid != uid || st.st_gid != uid)
134 goto BAD;
135
136 /* must not be readable or writable by others */
137 if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0)
138 goto BAD;
139
140 /* everything ok */
141 return 0;
142
143BAD:
144 errno = EINVAL;
145 return -1;
146}
147
148/* This function is used to check the data directory path for safety.
149 * We check that every sub-directory is owned by the 'system' user
150 * and exists and is not a symlink. We also check that the full directory
151 * path is properly owned by the user ID.
152 *
153 * Return 0 on success, -1 on error.
154 */
155int
156check_data_path(const char* dataPath, uid_t uid)
157{
158 int nn;
159
160 /* the path should be absolute */
161 if (dataPath[0] != '/') {
162 errno = EINVAL;
163 return -1;
164 }
165
166 /* look for all sub-paths, we do that by finding
167 * directory separators in the input path and
168 * checking each sub-path independently
169 */
170 for (nn = 1; dataPath[nn] != '\0'; nn++)
171 {
172 char subpath[PATH_MAX];
173
174 /* skip non-separator characters */
175 if (dataPath[nn] != '/')
176 continue;
177
178 /* handle trailing separator case */
179 if (dataPath[nn+1] == '\0') {
180 break;
181 }
182
183 /* found a separator, check that dataPath is not too long. */
184 if (nn >= (int)(sizeof subpath)) {
185 errno = EINVAL;
186 return -1;
187 }
188
189 /* reject any '..' subpath */
190 if (nn >= 3 &&
191 dataPath[nn-3] == '/' &&
192 dataPath[nn-2] == '.' &&
193 dataPath[nn-1] == '.') {
194 errno = EINVAL;
195 return -1;
196 }
197
198 /* copy to 'subpath', then check ownership */
199 memcpy(subpath, dataPath, nn);
200 subpath[nn] = '\0';
201
202 if (check_directory_ownership(subpath, AID_SYSTEM) < 0)
203 return -1;
204 }
205
206 /* All sub-paths were checked, now verify that the full data
207 * directory is owned by the application uid
208 */
209 if (check_directory_ownership(dataPath, uid) < 0)
210 return -1;
211
212 /* all clear */
213 return 0;
214}
215
216/* Return TRUE iff a character is a space or tab */
217static inline int
218is_space(char c)
219{
220 return (c == ' ' || c == '\t');
221}
222
223/* Skip any space or tab character from 'p' until 'end' is reached.
224 * Return new position.
225 */
226static const char*
227skip_spaces(const char* p, const char* end)
228{
229 while (p < end && is_space(*p))
230 p++;
231
232 return p;
233}
234
235/* Skip any non-space and non-tab character from 'p' until 'end'.
236 * Return new position.
237 */
238static const char*
239skip_non_spaces(const char* p, const char* end)
240{
241 while (p < end && !is_space(*p))
242 p++;
243
244 return p;
245}
246
247/* Find the first occurence of 'ch' between 'p' and 'end'
248 * Return its position, or 'end' if none is found.
249 */
250static const char*
251find_first(const char* p, const char* end, char ch)
252{
253 while (p < end && *p != ch)
254 p++;
255
256 return p;
257}
258
259/* Check that the non-space string starting at 'p' and eventually
260 * ending at 'end' equals 'name'. Return new position (after name)
261 * on success, or NULL on failure.
262 *
263 * This function fails is 'name' is NULL, empty or contains any space.
264 */
265static const char*
266compare_name(const char* p, const char* end, const char* name)
267{
268 /* 'name' must not be NULL or empty */
269 if (name == NULL || name[0] == '\0' || p == end)
270 return NULL;
271
272 /* compare characters to those in 'name', excluding spaces */
273 while (*name) {
274 /* note, we don't check for *p == '\0' since
275 * it will be caught in the next conditional.
276 */
277 if (p >= end || is_space(*p))
278 goto BAD;
279
280 if (*p != *name)
281 goto BAD;
282
283 p++;
284 name++;
285 }
286
287 /* must be followed by end of line or space */
288 if (p < end && !is_space(*p))
289 goto BAD;
290
291 return p;
292
293BAD:
294 return NULL;
295}
296
297/* Parse one or more whitespace characters starting from '*pp'
298 * until 'end' is reached. Updates '*pp' on exit.
299 *
300 * Return 0 on success, -1 on failure.
301 */
302static int
303parse_spaces(const char** pp, const char* end)
304{
305 const char* p = *pp;
306
307 if (p >= end || !is_space(*p)) {
308 errno = EINVAL;
309 return -1;
310 }
311 p = skip_spaces(p, end);
312 *pp = p;
313 return 0;
314}
315
316/* Parse a positive decimal number starting from '*pp' until 'end'
317 * is reached. Adjust '*pp' on exit. Return decimal value or -1
318 * in case of error.
319 *
320 * If the value is larger than INT_MAX, -1 will be returned,
321 * and errno set to EOVERFLOW.
322 *
323 * If '*pp' does not start with a decimal digit, -1 is returned
324 * and errno set to EINVAL.
325 */
326static int
327parse_positive_decimal(const char** pp, const char* end)
328{
329 const char* p = *pp;
330 int value = 0;
331 int overflow = 0;
332
333 if (p >= end || *p < '0' || *p > '9') {
334 errno = EINVAL;
335 return -1;
336 }
337
338 while (p < end) {
339 int ch = *p;
340 unsigned d = (unsigned)(ch - '0');
341 int val2;
342
343 if (d >= 10U) /* d is unsigned, no lower bound check */
344 break;
345
346 val2 = value*10 + (int)d;
347 if (val2 < value)
348 overflow = 1;
349 value = val2;
350 p++;
351 }
352 *pp = p;
353
354 if (overflow) {
355 errno = EOVERFLOW;
356 value = -1;
357 }
358 return value;
359
360BAD:
361 *pp = p;
362 return -1;
363}
364
365/* Read the system's package database and extract information about
366 * 'pkgname'. Return 0 in case of success, or -1 in case of error.
367 *
368 * If the package is unknown, return -1 and set errno to ENOENT
369 * If the package database is corrupted, return -1 and set errno to EINVAL
370 */
371int
372get_package_info(const char* pkgName, PackageInfo *info)
373{
374 static char buffer[PACKAGES_LIST_BUFFER_SIZE];
375 int buffer_len;
376 const char* p;
377 const char* buffer_end;
378 int result;
379
380 info->uid = 0;
381 info->isDebuggable = 0;
382 info->dataDir[0] = '\0';
383
384 buffer_len = read_file(PACKAGES_LIST_FILE, buffer, sizeof buffer);
385 if (buffer_len < 0)
386 return -1;
387
388 p = buffer;
389 buffer_end = buffer + buffer_len;
390
391 /* expect the following format on each line of the control file:
392 *
393 * <pkgName> <uid> <debugFlag> <dataDir>
394 *
395 * where:
396 * <pkgName> is the package's name
397 * <uid> is the application-specific user Id (decimal)
398 * <debugFlag> is 1 if the package is debuggable, or 0 otherwise
399 * <dataDir> is the path to the package's data directory (e.g. /data/data/com.example.foo)
400 *
401 * The file is generated in com.android.server.PackageManagerService.Settings.writeLP()
402 */
403
404 while (p < buffer_end) {
405 /* find end of current line and start of next one */
406 const char* end = find_first(p, buffer_end, '\n');
407 const char* next = (end < buffer_end) ? end + 1 : buffer_end;
408 const char* q;
409 int uid, debugFlag;
410
411 /* first field is the package name */
412 p = compare_name(p, end, pkgName);
413 if (p == NULL)
414 goto NEXT_LINE;
415
416 /* skip spaces */
417 if (parse_spaces(&p, end) < 0)
418 goto BAD_FORMAT;
419
420 /* second field is the pid */
421 uid = parse_positive_decimal(&p, end);
422 if (uid < 0)
423 return -1;
424
425 info->uid = (uid_t) uid;
426
427 /* skip spaces */
428 if (parse_spaces(&p, end) < 0)
429 goto BAD_FORMAT;
430
431 /* third field is debug flag (0 or 1) */
432 debugFlag = parse_positive_decimal(&p, end);
433 switch (debugFlag) {
434 case 0:
435 info->isDebuggable = 0;
436 break;
437 case 1:
438 info->isDebuggable = 1;
439 break;
440 default:
441 goto BAD_FORMAT;
442 }
443
444 /* skip spaces */
445 if (parse_spaces(&p, end) < 0)
446 goto BAD_FORMAT;
447
448 /* fourth field is data directory path and must not contain
449 * spaces.
450 */
451 q = skip_non_spaces(p, end);
452 if (q == p)
453 goto BAD_FORMAT;
454
455 string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
456
457 /* Ignore the rest */
458 return 0;
459
460 NEXT_LINE:
461 p = next;
462 }
463
464 /* the package is unknown */
465 errno = ENOENT;
466 return -1;
467
468BAD_FORMAT:
469 errno = EINVAL;
470 return -1;
471}
diff --git a/run-as/package.h b/run-as/package.h
new file mode 100644
index 000000000..852af0632
--- /dev/null
+++ b/run-as/package.h
@@ -0,0 +1,41 @@
1/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17#ifndef RUN_AS_PACKAGE_H
18#define RUN_AS_PACKAGE_H
19
20#include <limits.h>
21#include <sys/types.h>
22
23typedef enum {
24 PACKAGE_IS_DEBUGGABLE = 0,
25 PACKAGE_IS_NOT_DEBUGGABLE,
26 PACKAGE_IS_UNKNOWN,
27} PackageStatus;
28
29typedef struct {
30 uid_t uid;
31 char isDebuggable;
32 char dataDir[PATH_MAX];
33} PackageInfo;
34
35/* see documentation in package.c for these functiosn */
36
37extern int get_package_info(const char* packageName, PackageInfo* info);
38
39extern int check_data_path(const char* dataDir, uid_t uid);
40
41#endif /* RUN_AS_PACKAGE_H */
diff --git a/run-as/run-as.c b/run-as/run-as.c
new file mode 100644
index 000000000..d2a44e1b5
--- /dev/null
+++ b/run-as/run-as.c
@@ -0,0 +1,178 @@
1/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define PROGNAME "run-as"
19#define LOG_TAG PROGNAME
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <dirent.h>
27#include <errno.h>
28#include <unistd.h>
29#include <time.h>
30#include <stdarg.h>
31
32#include <private/android_filesystem_config.h>
33#include "package.h"
34
35/*
36 * WARNING WARNING WARNING WARNING
37 *
38 * This program runs as set-uid root on Android production devices.
39 * Be very conservative when modifying it to avoid any serious
40 * security issue. Keep in mind the following:
41 *
42 * - This program should only run for the 'root' or 'shell' users
43 *
44 * - Statically link against the C library, and avoid anything that
45 * is more complex than simple system calls until the uid/gid has
46 * been dropped to that of a normal user or you are sure to exit.
47 *
48 * This avoids depending on environment variables, system properties
49 * and other external factors that may affect the C library in
50 * unpredictable ways.
51 *
52 * - Do not trust user input and/or the filesystem whenever possible.
53 *
54 * Read README.TXT for more details.
55 *
56 *
57 *
58 * The purpose of this program is to run a command as a specific
59 * application user-id. Typical usage is:
60 *
61 * run-as <package-name> <command> <args>
62 *
63 * The 'run-as' binary is setuid, but will check the following:
64 *
65 * - that it is invoked from the 'shell' or 'root' user (abort otherwise)
66 * - that '<package-name>' is the name of an installed and debuggable package
67 * - that the package's data directory is well-formed (see package.c)
68 *
69 * If so, it will cd to the package's data directory, drop to the application's
70 * user id / group id then run the command there.
71 *
72 * This can be useful for a number of different things on production devices:
73 *
74 * - Allow application developers to look at their own applicative data
75 * during development.
76 *
77 * - Run the 'gdbserver' binary executable to allow native debugging
78 */
79
80static void
81usage(void)
82{
83 const char* str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n";
84 write(1, str, strlen(str));
85 exit(1);
86}
87
88
89static void
90panic(const char* format, ...)
91{
92 va_list args;
93
94 fprintf(stderr, "%s: ", PROGNAME);
95 va_start(args, format);
96 vfprintf(stderr, format, args);
97 va_end(args);
98 exit(1);
99}
100
101
102int main(int argc, char **argv)
103{
104 const char* pkgname;
105 int myuid, uid, gid;
106 PackageInfo info;
107
108 /* check arguments */
109 if (argc < 2)
110 usage();
111
112 /* check userid of caller - must be 'shell' or 'root' */
113 myuid = getuid();
114 if (myuid != AID_SHELL && myuid != AID_ROOT) {
115 panic("only 'shell' or 'root' users can run this program\n");
116 }
117
118 /* retrieve package information from system */
119 pkgname = argv[1];
120 if (get_package_info(pkgname, &info) < 0) {
121 panic("Package '%s' is unknown\n", pkgname);
122 return 1;
123 }
124
125 /* reject system packages */
126 if (info.uid < AID_APP) {
127 panic("Package '%s' is not an application\n", pkgname);
128 return 1;
129 }
130
131 /* reject any non-debuggable package */
132 if (!info.isDebuggable) {
133 panic("Package '%s' is not debuggable\n", pkgname);
134 return 1;
135 }
136
137 /* check that the data directory path is valid */
138 if (check_data_path(info.dataDir, info.uid) < 0) {
139 panic("Package '%s' has corrupt installation\n", pkgname);
140 return 1;
141 }
142
143 /* then move to it */
144 {
145 int ret;
146 do {
147 ret = chdir(info.dataDir);
148 } while (ret < 0 && errno == EINTR);
149
150 if (ret < 0) {
151 panic("Could not cd to package's data directory: %s\n", strerror(errno));
152 return 1;
153 }
154 }
155
156 /* Ensure that we change all real/effective/saved IDs at the
157 * same time to avoid nasty surprises.
158 */
159 uid = gid = info.uid;
160 if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
161 panic("Permission denied\n");
162 return 1;
163 }
164
165 /* User specified command for exec. */
166 if (argc >= 3 ) {
167 if (execvp(argv[2], argv+2) < 0) {
168 panic("exec failed for %s Error:%s\n", argv[2], strerror(errno));
169 return -errno;
170 }
171 }
172
173 /* Default exec shell. */
174 execlp("/system/bin/sh", "sh", NULL);
175
176 panic("exec failed\n");
177 return 1;
178}