1/* 2 * Copyright (C) 2007 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 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.os; 18 19import android.net.Credentials; 20import android.net.LocalSocket; 21import android.os.Process; 22import android.os.SELinux; 23import android.os.SystemProperties; 24import android.util.Log; 25 26import dalvik.system.PathClassLoader; 27import dalvik.system.Zygote; 28 29import java.io.BufferedReader; 30import java.io.DataInputStream; 31import java.io.DataOutputStream; 32import java.io.FileDescriptor; 33import java.io.FileInputStream; 34import java.io.FileOutputStream; 35import java.io.IOException; 36import java.io.InputStreamReader; 37import java.io.PrintStream; 38import java.util.ArrayList; 39 40import libcore.io.ErrnoException; 41import libcore.io.IoUtils; 42import libcore.io.Libcore; 43 44/** 45 * A connection that can make spawn requests. 46 */ 47class ZygoteConnection { 48 private static final String TAG = "Zygote"; 49 50 /** a prototype instance for a future List.toArray() */ 51 private static final int[][] intArray2d = new int[0][0]; 52 53 /** 54 * {@link android.net.LocalSocket#setSoTimeout} value for connections. 55 * Effectively, the amount of time a requestor has between the start of 56 * the request and the completed request. The select-loop mode Zygote 57 * doesn't have the logic to return to the select loop in the middle of 58 * a request, so we need to time out here to avoid being denial-of-serviced. 59 */ 60 private static final int CONNECTION_TIMEOUT_MILLIS = 1000; 61 62 /** max number of arguments that a connection can specify */ 63 private static final int MAX_ZYGOTE_ARGC=1024; 64 65 /** 66 * The command socket. 67 * 68 * mSocket is retained in the child process in "peer wait" mode, so 69 * that it closes when the child process terminates. In other cases, 70 * it is closed in the peer. 71 */ 72 private final LocalSocket mSocket; 73 private final DataOutputStream mSocketOutStream; 74 private final BufferedReader mSocketReader; 75 private final Credentials peer; 76 private final String peerSecurityContext; 77 78 /** 79 * A long-lived reference to the original command socket used to launch 80 * this peer. If "peer wait" mode is specified, the process that requested 81 * the new VM instance intends to track the lifetime of the spawned instance 82 * via the command socket. In this case, the command socket is closed 83 * in the Zygote and placed here in the spawned instance so that it will 84 * not be collected and finalized. This field remains null at all times 85 * in the original Zygote process, and in all spawned processes where 86 * "peer-wait" mode was not requested. 87 */ 88 private static LocalSocket sPeerWaitSocket = null; 89 90 /** 91 * Constructs instance from connected socket. 92 * 93 * @param socket non-null; connected socket 94 * @throws IOException 95 */ 96 ZygoteConnection(LocalSocket socket) throws IOException { 97 mSocket = socket; 98 99 mSocketOutStream 100 = new DataOutputStream(socket.getOutputStream()); 101 102 mSocketReader = new BufferedReader( 103 new InputStreamReader(socket.getInputStream()), 256); 104 105 mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS); 106 107 try { 108 peer = mSocket.getPeerCredentials(); 109 } catch (IOException ex) { 110 Log.e(TAG, "Cannot read peer credentials", ex); 111 throw ex; 112 } 113 114 peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor()); 115 } 116 117 /** 118 * Returns the file descriptor of the associated socket. 119 * 120 * @return null-ok; file descriptor 121 */ 122 FileDescriptor getFileDesciptor() { 123 return mSocket.getFileDescriptor(); 124 } 125 126 /** 127 * Reads start commands from an open command socket. 128 * Start commands are presently a pair of newline-delimited lines 129 * indicating a) class to invoke main() on b) nice name to set argv[0] to. 130 * Continues to read commands and forkAndSpecialize children until 131 * the socket is closed. This method is used in ZYGOTE_FORK_MODE 132 * 133 * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() 134 * method in child process 135 */ 136 void run() throws ZygoteInit.MethodAndArgsCaller { 137 138 int loopCount = ZygoteInit.GC_LOOP_COUNT; 139 140 while (true) { 141 /* 142 * Call gc() before we block in readArgumentList(). 143 * It's work that has to be done anyway, and it's better 144 * to avoid making every child do it. It will also 145 * madvise() any free memory as a side-effect. 146 * 147 * Don't call it every time, because walking the entire 148 * heap is a lot of overhead to free a few hundred bytes. 149 */ 150 if (loopCount <= 0) { 151 ZygoteInit.gc(); 152 loopCount = ZygoteInit.GC_LOOP_COUNT; 153 } else { 154 loopCount--; 155 } 156 157 if (runOnce()) { 158 break; 159 } 160 } 161 } 162 163 /** 164 * Reads one start command from the command socket. If successful, 165 * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller} 166 * exception is thrown in that child while in the parent process, 167 * the method returns normally. On failure, the child is not 168 * spawned and messages are printed to the log and stderr. Returns 169 * a boolean status value indicating whether an end-of-file on the command 170 * socket has been encountered. 171 * 172 * @return false if command socket should continue to be read from, or 173 * true if an end-of-file has been encountered. 174 * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() 175 * method in child process 176 */ 177 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { 178 179 String args[]; 180 Arguments parsedArgs = null; 181 FileDescriptor[] descriptors; 182 183 try { 184 args = readArgumentList(); 185 descriptors = mSocket.getAncillaryFileDescriptors(); 186 } catch (IOException ex) { 187 Log.w(TAG, "IOException on command socket " + ex.getMessage()); 188 closeSocket(); 189 return true; 190 } 191 192 if (args == null) { 193 // EOF reached. 194 closeSocket(); 195 return true; 196 } 197 198 /** the stderr of the most recent request, if avail */ 199 PrintStream newStderr = null; 200 201 if (descriptors != null && descriptors.length >= 3) { 202 newStderr = new PrintStream( 203 new FileOutputStream(descriptors[2])); 204 } 205 206 int pid = -1; 207 FileDescriptor childPipeFd = null; 208 FileDescriptor serverPipeFd = null; 209 210 try { 211 parsedArgs = new Arguments(args); 212 213 applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); 214 applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); 215 applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext); 216 applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); 217 applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); 218 219 applyDebuggerSystemProperty(parsedArgs); 220 applyInvokeWithSystemProperty(parsedArgs); 221 222 int[][] rlimits = null; 223 224 if (parsedArgs.rlimits != null) { 225 rlimits = parsedArgs.rlimits.toArray(intArray2d); 226 } 227 228 if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) { 229 FileDescriptor[] pipeFds = Libcore.os.pipe(); 230 childPipeFd = pipeFds[1]; 231 serverPipeFd = pipeFds[0]; 232 ZygoteInit.setCloseOnExec(serverPipeFd, true); 233 } 234 235 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, 236 parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, 237 parsedArgs.niceName); 238 } catch (IOException ex) { 239 logAndPrintError(newStderr, "Exception creating pipe", ex); 240 } catch (ErrnoException ex) { 241 logAndPrintError(newStderr, "Exception creating pipe", ex); 242 } catch (IllegalArgumentException ex) { 243 logAndPrintError(newStderr, "Invalid zygote arguments", ex); 244 } catch (ZygoteSecurityException ex) { 245 logAndPrintError(newStderr, 246 "Zygote security policy prevents request: ", ex); 247 } 248 249 try { 250 if (pid == 0) { 251 // in child 252 IoUtils.closeQuietly(serverPipeFd); 253 serverPipeFd = null; 254 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); 255 256 // should never get here, the child is expected to either 257 // throw ZygoteInit.MethodAndArgsCaller or exec(). 258 return true; 259 } else { 260 // in parent...pid of < 0 means failure 261 IoUtils.closeQuietly(childPipeFd); 262 childPipeFd = null; 263 return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); 264 } 265 } finally { 266 IoUtils.closeQuietly(childPipeFd); 267 IoUtils.closeQuietly(serverPipeFd); 268 } 269 } 270 271 /** 272 * Closes socket associated with this connection. 273 */ 274 void closeSocket() { 275 try { 276 mSocket.close(); 277 } catch (IOException ex) { 278 Log.e(TAG, "Exception while closing command " 279 + "socket in parent", ex); 280 } 281 } 282 283 /** 284 * Handles argument parsing for args related to the zygote spawner. 285 * 286 * Current recognized args: 287 * <ul> 288 * <li> --setuid=<i>uid of child process, defaults to 0</i> 289 * <li> --setgid=<i>gid of child process, defaults to 0</i> 290 * <li> --setgroups=<i>comma-separated list of supplimentary gid's</i> 291 * <li> --capabilities=<i>a pair of comma-separated integer strings 292 * indicating Linux capabilities(2) set for child. The first string 293 * represents the <code>permitted</code> set, and the second the 294 * <code>effective</code> set. Precede each with 0 or 295 * 0x for octal or hexidecimal value. If unspecified, both default to 0. 296 * This parameter is only applied if the uid of the new process will 297 * be non-0. </i> 298 * <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call. 299 * <code>r</code> is the resource, <code>c</code> and <code>m</code> 300 * are the settings for current and max value.</i> 301 * <li> --peer-wait indicates that the command socket should 302 * be inherited by (and set to close-on-exec in) the spawned process 303 * and used to track the lifetime of that process. The spawning process 304 * then exits. Without this flag, it is retained by the spawning process 305 * (and closed in the child) in expectation of a new spawn request. 306 * <li> --classpath=<i>colon-separated classpath</i> indicates 307 * that the specified class (which must b first non-flag argument) should 308 * be loaded from jar files in the specified classpath. Incompatible with 309 * --runtime-init 310 * <li> --runtime-init indicates that the remaining arg list should 311 * be handed off to com.android.internal.os.RuntimeInit, rather than 312 * processed directly 313 * Android runtime startup (eg, Binder initialization) is also eschewed. 314 * <li> --nice-name=<i>nice name to appear in ps</i> 315 * <li> If <code>--runtime-init</code> is present: 316 * [--] <args for RuntimeInit > 317 * <li> If <code>--runtime-init</code> is absent: 318 * [--] <classname> [args...] 319 * </ul> 320 */ 321 static class Arguments { 322 /** from --setuid */ 323 int uid = 0; 324 boolean uidSpecified; 325 326 /** from --setgid */ 327 int gid = 0; 328 boolean gidSpecified; 329 330 /** from --setgroups */ 331 int[] gids; 332 333 /** from --peer-wait */ 334 boolean peerWait; 335 336 /** 337 * From --enable-debugger, --enable-checkjni, --enable-assert, 338 * --enable-safemode, and --enable-jni-logging. 339 */ 340 int debugFlags; 341 342 /** From --mount-external */ 343 int mountExternal = Zygote.MOUNT_EXTERNAL_NONE; 344 345 /** from --target-sdk-version. */ 346 int targetSdkVersion; 347 boolean targetSdkVersionSpecified; 348 349 /** from --classpath */ 350 String classpath; 351 352 /** from --runtime-init */ 353 boolean runtimeInit; 354 355 /** from --nice-name */ 356 String niceName; 357 358 /** from --capabilities */ 359 boolean capabilitiesSpecified; 360 long permittedCapabilities; 361 long effectiveCapabilities; 362 363 /** from --seinfo */ 364 boolean seInfoSpecified; 365 String seInfo; 366 367 /** from all --rlimit=r,c,m */ 368 ArrayList<int[]> rlimits; 369 370 /** from --invoke-with */ 371 String invokeWith; 372 373 /** 374 * Any args after and including the first non-option arg 375 * (or after a '--') 376 */ 377 String remainingArgs[]; 378 379 /** 380 * Constructs instance and parses args 381 * @param args zygote command-line args 382 * @throws IllegalArgumentException 383 */ 384 Arguments(String args[]) throws IllegalArgumentException { 385 parseArgs(args); 386 } 387 388 /** 389 * Parses the commandline arguments intended for the Zygote spawner 390 * (such as "--setuid=" and "--setgid=") and creates an array 391 * containing the remaining args. 392 * 393 * Per security review bug #1112214, duplicate args are disallowed in 394 * critical cases to make injection harder. 395 */ 396 private void parseArgs(String args[]) 397 throws IllegalArgumentException { 398 int curArg = 0; 399 400 for ( /* curArg */ ; curArg < args.length; curArg++) { 401 String arg = args[curArg]; 402 403 if (arg.equals("--")) { 404 curArg++; 405 break; 406 } else if (arg.startsWith("--setuid=")) { 407 if (uidSpecified) { 408 throw new IllegalArgumentException( 409 "Duplicate arg specified"); 410 } 411 uidSpecified = true; 412 uid = Integer.parseInt( 413 arg.substring(arg.indexOf('=') + 1)); 414 } else if (arg.startsWith("--setgid=")) { 415 if (gidSpecified) { 416 throw new IllegalArgumentException( 417 "Duplicate arg specified"); 418 } 419 gidSpecified = true; 420 gid = Integer.parseInt( 421 arg.substring(arg.indexOf('=') + 1)); 422 } else if (arg.startsWith("--target-sdk-version=")) { 423 if (targetSdkVersionSpecified) { 424 throw new IllegalArgumentException( 425 "Duplicate target-sdk-version specified"); 426 } 427 targetSdkVersionSpecified = true; 428 targetSdkVersion = Integer.parseInt( 429 arg.substring(arg.indexOf('=') + 1)); 430 } else if (arg.equals("--enable-debugger")) { 431 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; 432 } else if (arg.equals("--enable-safemode")) { 433 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE; 434 } else if (arg.equals("--enable-checkjni")) { 435 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; 436 } else if (arg.equals("--enable-jni-logging")) { 437 debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING; 438 } else if (arg.equals("--enable-assert")) { 439 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; 440 } else if (arg.equals("--peer-wait")) { 441 peerWait = true; 442 } else if (arg.equals("--runtime-init")) { 443 runtimeInit = true; 444 } else if (arg.startsWith("--seinfo=")) { 445 if (seInfoSpecified) { 446 throw new IllegalArgumentException( 447 "Duplicate arg specified"); 448 } 449 seInfoSpecified = true; 450 seInfo = arg.substring(arg.indexOf('=') + 1); 451 } else if (arg.startsWith("--capabilities=")) { 452 if (capabilitiesSpecified) { 453 throw new IllegalArgumentException( 454 "Duplicate arg specified"); 455 } 456 capabilitiesSpecified = true; 457 String capString = arg.substring(arg.indexOf('=')+1); 458 459 String[] capStrings = capString.split(",", 2); 460 461 if (capStrings.length == 1) { 462 effectiveCapabilities = Long.decode(capStrings[0]); 463 permittedCapabilities = effectiveCapabilities; 464 } else { 465 permittedCapabilities = Long.decode(capStrings[0]); 466 effectiveCapabilities = Long.decode(capStrings[1]); 467 } 468 } else if (arg.startsWith("--rlimit=")) { 469 // Duplicate --rlimit arguments are specifically allowed. 470 String[] limitStrings 471 = arg.substring(arg.indexOf('=')+1).split(","); 472 473 if (limitStrings.length != 3) { 474 throw new IllegalArgumentException( 475 "--rlimit= should have 3 comma-delimited ints"); 476 } 477 int[] rlimitTuple = new int[limitStrings.length]; 478 479 for(int i=0; i < limitStrings.length; i++) { 480 rlimitTuple[i] = Integer.parseInt(limitStrings[i]); 481 } 482 483 if (rlimits == null) { 484 rlimits = new ArrayList(); 485 } 486 487 rlimits.add(rlimitTuple); 488 } else if (arg.equals("-classpath")) { 489 if (classpath != null) { 490 throw new IllegalArgumentException( 491 "Duplicate arg specified"); 492 } 493 try { 494 classpath = args[++curArg]; 495 } catch (IndexOutOfBoundsException ex) { 496 throw new IllegalArgumentException( 497 "-classpath requires argument"); 498 } 499 } else if (arg.startsWith("--setgroups=")) { 500 if (gids != null) { 501 throw new IllegalArgumentException( 502 "Duplicate arg specified"); 503 } 504 505 String[] params 506 = arg.substring(arg.indexOf('=') + 1).split(","); 507 508 gids = new int[params.length]; 509 510 for (int i = params.length - 1; i >= 0 ; i--) { 511 gids[i] = Integer.parseInt(params[i]); 512 } 513 } else if (arg.equals("--invoke-with")) { 514 if (invokeWith != null) { 515 throw new IllegalArgumentException( 516 "Duplicate arg specified"); 517 } 518 try { 519 invokeWith = args[++curArg]; 520 } catch (IndexOutOfBoundsException ex) { 521 throw new IllegalArgumentException( 522 "--invoke-with requires argument"); 523 } 524 } else if (arg.startsWith("--nice-name=")) { 525 if (niceName != null) { 526 throw new IllegalArgumentException( 527 "Duplicate arg specified"); 528 } 529 niceName = arg.substring(arg.indexOf('=') + 1); 530 } else if (arg.equals("--mount-external-multiuser")) { 531 mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER; 532 } else if (arg.equals("--mount-external-multiuser-all")) { 533 mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL; 534 } else { 535 break; 536 } 537 } 538 539 if (runtimeInit && classpath != null) { 540 throw new IllegalArgumentException( 541 "--runtime-init and -classpath are incompatible"); 542 } 543 544 remainingArgs = new String[args.length - curArg]; 545 546 System.arraycopy(args, curArg, remainingArgs, 0, 547 remainingArgs.length); 548 } 549 } 550 551 /** 552 * Reads an argument list from the command socket/ 553 * @return Argument list or null if EOF is reached 554 * @throws IOException passed straight through 555 */ 556 private String[] readArgumentList() 557 throws IOException { 558 559 /** 560 * See android.os.Process.zygoteSendArgsAndGetPid() 561 * Presently the wire format to the zygote process is: 562 * a) a count of arguments (argc, in essence) 563 * b) a number of newline-separated argument strings equal to count 564 * 565 * After the zygote process reads these it will write the pid of 566 * the child or -1 on failure. 567 */ 568 569 int argc; 570 571 try { 572 String s = mSocketReader.readLine(); 573 574 if (s == null) { 575 // EOF reached. 576 return null; 577 } 578 argc = Integer.parseInt(s); 579 } catch (NumberFormatException ex) { 580 Log.e(TAG, "invalid Zygote wire format: non-int at argc"); 581 throw new IOException("invalid wire format"); 582 } 583 584 // See bug 1092107: large argc can be used for a DOS attack 585 if (argc > MAX_ZYGOTE_ARGC) { 586 throw new IOException("max arg count exceeded"); 587 } 588 589 String[] result = new String[argc]; 590 for (int i = 0; i < argc; i++) { 591 result[i] = mSocketReader.readLine(); 592 if (result[i] == null) { 593 // We got an unexpected EOF. 594 throw new IOException("truncated request"); 595 } 596 } 597 598 return result; 599 } 600 601 /** 602 * Applies zygote security policy per bugs #875058 and #1082165. 603 * Based on the credentials of the process issuing a zygote command: 604 * <ol> 605 * <li> uid 0 (root) may specify any uid, gid, and setgroups() list 606 * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal 607 * operation. It may also specify any gid and setgroups() list it chooses. 608 * In factory test mode, it may specify any UID. 609 * <li> Any other uid may not specify any uid, gid, or setgroups list. The 610 * uid and gid will be inherited from the requesting process. 611 * </ul> 612 * 613 * @param args non-null; zygote spawner arguments 614 * @param peer non-null; peer credentials 615 * @throws ZygoteSecurityException 616 */ 617 private static void applyUidSecurityPolicy(Arguments args, Credentials peer, 618 String peerSecurityContext) 619 throws ZygoteSecurityException { 620 621 int peerUid = peer.getUid(); 622 623 if (peerUid == 0) { 624 // Root can do what it wants 625 } else if (peerUid == Process.SYSTEM_UID ) { 626 // System UID is restricted, except in factory test mode 627 String factoryTest = SystemProperties.get("ro.factorytest"); 628 boolean uidRestricted; 629 630 /* In normal operation, SYSTEM_UID can only specify a restricted 631 * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid. 632 */ 633 uidRestricted 634 = !(factoryTest.equals("1") || factoryTest.equals("2")); 635 636 if (uidRestricted 637 && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) { 638 throw new ZygoteSecurityException( 639 "System UID may not launch process with UID < " 640 + Process.SYSTEM_UID); 641 } 642 } else { 643 // Everything else 644 if (args.uidSpecified || args.gidSpecified 645 || args.gids != null) { 646 throw new ZygoteSecurityException( 647 "App UIDs may not specify uid's or gid's"); 648 } 649 } 650 651 if (args.uidSpecified || args.gidSpecified || args.gids != null) { 652 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 653 peerSecurityContext, 654 "zygote", 655 "specifyids"); 656 if (!allowed) { 657 throw new ZygoteSecurityException( 658 "Peer may not specify uid's or gid's"); 659 } 660 } 661 662 // If not otherwise specified, uid and gid are inherited from peer 663 if (!args.uidSpecified) { 664 args.uid = peer.getUid(); 665 args.uidSpecified = true; 666 } 667 if (!args.gidSpecified) { 668 args.gid = peer.getGid(); 669 args.gidSpecified = true; 670 } 671 } 672 673 674 /** 675 * Applies debugger system properties to the zygote arguments. 676 * 677 * If "ro.debuggable" is "1", all apps are debuggable. Otherwise, 678 * the debugger state is specified via the "--enable-debugger" flag 679 * in the spawn request. 680 * 681 * @param args non-null; zygote spawner args 682 */ 683 public static void applyDebuggerSystemProperty(Arguments args) { 684 if ("1".equals(SystemProperties.get("ro.debuggable"))) { 685 args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; 686 } 687 } 688 689 /** 690 * Applies zygote security policy per bug #1042973. Based on the credentials 691 * of the process issuing a zygote command: 692 * <ol> 693 * <li> peers of uid 0 (root) and uid 1000 (Process.SYSTEM_UID) 694 * may specify any rlimits. 695 * <li> All other uids may not specify rlimits. 696 * </ul> 697 * @param args non-null; zygote spawner arguments 698 * @param peer non-null; peer credentials 699 * @throws ZygoteSecurityException 700 */ 701 private static void applyRlimitSecurityPolicy( 702 Arguments args, Credentials peer, String peerSecurityContext) 703 throws ZygoteSecurityException { 704 705 int peerUid = peer.getUid(); 706 707 if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { 708 // All peers with UID other than root or SYSTEM_UID 709 if (args.rlimits != null) { 710 throw new ZygoteSecurityException( 711 "This UID may not specify rlimits."); 712 } 713 } 714 715 if (args.rlimits != null) { 716 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 717 peerSecurityContext, 718 "zygote", 719 "specifyrlimits"); 720 if (!allowed) { 721 throw new ZygoteSecurityException( 722 "Peer may not specify rlimits"); 723 } 724 } 725 } 726 727 /** 728 * Applies zygote security policy per bug #1042973. A root peer may 729 * spawn an instance with any capabilities. All other uids may spawn 730 * instances with any of the capabilities in the peer's permitted set 731 * but no more. 732 * 733 * @param args non-null; zygote spawner arguments 734 * @param peer non-null; peer credentials 735 * @throws ZygoteSecurityException 736 */ 737 private static void applyCapabilitiesSecurityPolicy( 738 Arguments args, Credentials peer, String peerSecurityContext) 739 throws ZygoteSecurityException { 740 741 if (args.permittedCapabilities == 0 742 && args.effectiveCapabilities == 0) { 743 // nothing to check 744 return; 745 } 746 747 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 748 peerSecurityContext, 749 "zygote", 750 "specifycapabilities"); 751 if (!allowed) { 752 throw new ZygoteSecurityException( 753 "Peer may not specify capabilities"); 754 } 755 756 if (peer.getUid() == 0) { 757 // root may specify anything 758 return; 759 } 760 761 long permittedCaps; 762 763 try { 764 permittedCaps = ZygoteInit.capgetPermitted(peer.getPid()); 765 } catch (IOException ex) { 766 throw new ZygoteSecurityException( 767 "Error retrieving peer's capabilities."); 768 } 769 770 /* 771 * Ensure that the client did not specify an effective set larger 772 * than the permitted set. The kernel will enforce this too, but we 773 * do it here to make the following check easier. 774 */ 775 if (((~args.permittedCapabilities) & args.effectiveCapabilities) != 0) { 776 throw new ZygoteSecurityException( 777 "Effective capabilities cannot be superset of " 778 + " permitted capabilities" ); 779 } 780 781 /* 782 * Ensure that the new permitted (and thus the new effective) set is 783 * a subset of the peer process's permitted set 784 */ 785 786 if (((~permittedCaps) & args.permittedCapabilities) != 0) { 787 throw new ZygoteSecurityException( 788 "Peer specified unpermitted capabilities" ); 789 } 790 } 791 792 /** 793 * Applies zygote security policy. 794 * Based on the credentials of the process issuing a zygote command: 795 * <ol> 796 * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a 797 * wrapper command. 798 * <li> Any other uid may not specify any invoke-with argument. 799 * </ul> 800 * 801 * @param args non-null; zygote spawner arguments 802 * @param peer non-null; peer credentials 803 * @throws ZygoteSecurityException 804 */ 805 private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer, 806 String peerSecurityContext) 807 throws ZygoteSecurityException { 808 int peerUid = peer.getUid(); 809 810 if (args.invokeWith != null && peerUid != 0) { 811 throw new ZygoteSecurityException("Peer is not permitted to specify " 812 + "an explicit invoke-with wrapper command"); 813 } 814 815 if (args.invokeWith != null) { 816 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 817 peerSecurityContext, 818 "zygote", 819 "specifyinvokewith"); 820 if (!allowed) { 821 throw new ZygoteSecurityException("Peer is not permitted to specify " 822 + "an explicit invoke-with wrapper command"); 823 } 824 } 825 } 826 827 /** 828 * Applies zygote security policy for SEAndroid information. 829 * 830 * @param args non-null; zygote spawner arguments 831 * @param peer non-null; peer credentials 832 * @throws ZygoteSecurityException 833 */ 834 private static void applyseInfoSecurityPolicy( 835 Arguments args, Credentials peer, String peerSecurityContext) 836 throws ZygoteSecurityException { 837 int peerUid = peer.getUid(); 838 839 if (args.seInfo == null) { 840 // nothing to check 841 return; 842 } 843 844 if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { 845 // All peers with UID other than root or SYSTEM_UID 846 throw new ZygoteSecurityException( 847 "This UID may not specify SEAndroid info."); 848 } 849 850 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 851 peerSecurityContext, 852 "zygote", 853 "specifyseinfo"); 854 if (!allowed) { 855 throw new ZygoteSecurityException( 856 "Peer may not specify SEAndroid info"); 857 } 858 859 return; 860 } 861 862 /** 863 * Applies invoke-with system properties to the zygote arguments. 864 * 865 * @param parsedArgs non-null; zygote args 866 */ 867 public static void applyInvokeWithSystemProperty(Arguments args) { 868 if (args.invokeWith == null && args.niceName != null) { 869 if (args.niceName != null) { 870 String property = "wrap." + args.niceName; 871 if (property.length() > 31) { 872 property = property.substring(0, 31); 873 } 874 args.invokeWith = SystemProperties.get(property); 875 if (args.invokeWith != null && args.invokeWith.length() == 0) { 876 args.invokeWith = null; 877 } 878 } 879 } 880 } 881 882 /** 883 * Handles post-fork setup of child proc, closing sockets as appropriate, 884 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller 885 * if successful or returning if failed. 886 * 887 * @param parsedArgs non-null; zygote args 888 * @param descriptors null-ok; new file descriptors for stdio if available. 889 * @param pipeFd null-ok; pipe for communication back to Zygote. 890 * @param newStderr null-ok; stream to use for stderr until stdio 891 * is reopened. 892 * 893 * @throws ZygoteInit.MethodAndArgsCaller on success to 894 * trampoline to code that invokes static main. 895 */ 896 private void handleChildProc(Arguments parsedArgs, 897 FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) 898 throws ZygoteInit.MethodAndArgsCaller { 899 900 /* 901 * Close the socket, unless we're in "peer wait" mode, in which 902 * case it's used to track the liveness of this process. 903 */ 904 905 if (parsedArgs.peerWait) { 906 try { 907 ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true); 908 sPeerWaitSocket = mSocket; 909 } catch (IOException ex) { 910 Log.e(TAG, "Zygote Child: error setting peer wait " 911 + "socket to be close-on-exec", ex); 912 } 913 } else { 914 closeSocket(); 915 ZygoteInit.closeServerSocket(); 916 } 917 918 if (descriptors != null) { 919 try { 920 ZygoteInit.reopenStdio(descriptors[0], 921 descriptors[1], descriptors[2]); 922 923 for (FileDescriptor fd: descriptors) { 924 IoUtils.closeQuietly(fd); 925 } 926 newStderr = System.err; 927 } catch (IOException ex) { 928 Log.e(TAG, "Error reopening stdio", ex); 929 } 930 } 931 932 if (parsedArgs.niceName != null) { 933 Process.setArgV0(parsedArgs.niceName); 934 } 935 936 if (parsedArgs.runtimeInit) { 937 if (parsedArgs.invokeWith != null) { 938 WrapperInit.execApplication(parsedArgs.invokeWith, 939 parsedArgs.niceName, parsedArgs.targetSdkVersion, 940 pipeFd, parsedArgs.remainingArgs); 941 } else { 942 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, 943 parsedArgs.remainingArgs); 944 } 945 } else { 946 String className; 947 try { 948 className = parsedArgs.remainingArgs[0]; 949 } catch (ArrayIndexOutOfBoundsException ex) { 950 logAndPrintError(newStderr, 951 "Missing required class name argument", null); 952 return; 953 } 954 955 String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1]; 956 System.arraycopy(parsedArgs.remainingArgs, 1, 957 mainArgs, 0, mainArgs.length); 958 959 if (parsedArgs.invokeWith != null) { 960 WrapperInit.execStandalone(parsedArgs.invokeWith, 961 parsedArgs.classpath, className, mainArgs); 962 } else { 963 ClassLoader cloader; 964 if (parsedArgs.classpath != null) { 965 cloader = new PathClassLoader(parsedArgs.classpath, 966 ClassLoader.getSystemClassLoader()); 967 } else { 968 cloader = ClassLoader.getSystemClassLoader(); 969 } 970 971 try { 972 ZygoteInit.invokeStaticMain(cloader, className, mainArgs); 973 } catch (RuntimeException ex) { 974 logAndPrintError(newStderr, "Error starting.", ex); 975 } 976 } 977 } 978 } 979 980 /** 981 * Handles post-fork cleanup of parent proc 982 * 983 * @param pid != 0; pid of child if > 0 or indication of failed fork 984 * if < 0; 985 * @param descriptors null-ok; file descriptors for child's new stdio if 986 * specified. 987 * @param pipeFd null-ok; pipe for communication with child. 988 * @param parsedArgs non-null; zygote args 989 * @return true for "exit command loop" and false for "continue command 990 * loop" 991 */ 992 private boolean handleParentProc(int pid, 993 FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) { 994 995 if (pid > 0) { 996 setChildPgid(pid); 997 } 998 999 if (descriptors != null) { 1000 for (FileDescriptor fd: descriptors) { 1001 IoUtils.closeQuietly(fd); 1002 } 1003 } 1004 1005 boolean usingWrapper = false; 1006 if (pipeFd != null && pid > 0) { 1007 DataInputStream is = new DataInputStream(new FileInputStream(pipeFd)); 1008 int innerPid = -1; 1009 try { 1010 innerPid = is.readInt(); 1011 } catch (IOException ex) { 1012 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex); 1013 } finally { 1014 try { 1015 is.close(); 1016 } catch (IOException ex) { 1017 } 1018 } 1019 1020 // Ensure that the pid reported by the wrapped process is either the 1021 // child process that we forked, or a descendant of it. 1022 if (innerPid > 0) { 1023 int parentPid = innerPid; 1024 while (parentPid > 0 && parentPid != pid) { 1025 parentPid = Process.getParentPid(parentPid); 1026 } 1027 if (parentPid > 0) { 1028 Log.i(TAG, "Wrapped process has pid " + innerPid); 1029 pid = innerPid; 1030 usingWrapper = true; 1031 } else { 1032 Log.w(TAG, "Wrapped process reported a pid that is not a child of " 1033 + "the process that we forked: childPid=" + pid 1034 + " innerPid=" + innerPid); 1035 } 1036 } 1037 } 1038 1039 try { 1040 mSocketOutStream.writeInt(pid); 1041 mSocketOutStream.writeBoolean(usingWrapper); 1042 } catch (IOException ex) { 1043 Log.e(TAG, "Error reading from command socket", ex); 1044 return true; 1045 } 1046 1047 /* 1048 * If the peer wants to use the socket to wait on the 1049 * newly spawned process, then we're all done. 1050 */ 1051 if (parsedArgs.peerWait) { 1052 try { 1053 mSocket.close(); 1054 } catch (IOException ex) { 1055 Log.e(TAG, "Zygote: error closing sockets", ex); 1056 } 1057 return true; 1058 } 1059 return false; 1060 } 1061 1062 private void setChildPgid(int pid) { 1063 // Try to move the new child into the peer's process group. 1064 try { 1065 ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid())); 1066 } catch (IOException ex) { 1067 // This exception is expected in the case where 1068 // the peer is not in our session 1069 // TODO get rid of this log message in the case where 1070 // getsid(0) != getsid(peer.getPid()) 1071 Log.i(TAG, "Zygote: setpgid failed. This is " 1072 + "normal if peer is not in our session"); 1073 } 1074 } 1075 1076 /** 1077 * Logs an error message and prints it to the specified stream, if 1078 * provided 1079 * 1080 * @param newStderr null-ok; a standard error stream 1081 * @param message non-null; error message 1082 * @param ex null-ok an exception 1083 */ 1084 private static void logAndPrintError (PrintStream newStderr, 1085 String message, Throwable ex) { 1086 Log.e(TAG, message, ex); 1087 if (newStderr != null) { 1088 newStderr.println(message + (ex == null ? "" : ex)); 1089 } 1090 } 1091} 1092