Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 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  * 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 
     17 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
     18 #include <sys/mount.h>
     19 #include <linux/fs.h>
     20 
     21 #include <grp.h>
     22 #include <paths.h>
     23 #include <signal.h>
     24 #include <stdlib.h>
     25 #include <sys/types.h>
     26 #include <sys/wait.h>
     27 #include <unistd.h>
     28 
     29 #include "cutils/fs.h"
     30 #include "cutils/multiuser.h"
     31 #include "cutils/sched_policy.h"
     32 #include "debugger.h"
     33 #include "jni_internal.h"
     34 #include "JNIHelp.h"
     35 #include "ScopedLocalRef.h"
     36 #include "ScopedPrimitiveArray.h"
     37 #include "ScopedUtfChars.h"
     38 #include "thread.h"
     39 
     40 #if defined(HAVE_PRCTL)
     41 #include <sys/prctl.h>
     42 #endif
     43 
     44 #include <selinux/android.h>
     45 
     46 #if defined(__linux__)
     47 #include <sys/personality.h>
     48 #include <sys/utsname.h>
     49 #include <sys/capability.h>
     50 #endif
     51 
     52 namespace art {
     53 
     54 static pid_t gSystemServerPid = 0;
     55 
     56 // Must match values in dalvik.system.Zygote.
     57 enum MountExternalKind {
     58   MOUNT_EXTERNAL_NONE = 0,
     59   MOUNT_EXTERNAL_SINGLEUSER = 1,
     60   MOUNT_EXTERNAL_MULTIUSER = 2,
     61   MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
     62 };
     63 
     64 // This signal handler is for zygote mode, since the zygote must reap its children
     65 static void SigChldHandler(int /*signal_number*/) {
     66   pid_t pid;
     67   int status;
     68 
     69   while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
     70      // Log process-death status that we care about.  In general it is
     71      // not safe to call LOG(...) from a signal handler because of
     72      // possible reentrancy.  However, we know a priori that the
     73      // current implementation of LOG() is safe to call from a SIGCHLD
     74      // handler in the zygote process.  If the LOG() implementation
     75      // changes its locking strategy or its use of syscalls within the
     76      // lazy-init critical section, its use here may become unsafe.
     77     if (WIFEXITED(status)) {
     78       if (WEXITSTATUS(status)) {
     79         LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
     80       } else if (false) {
     81         LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
     82       }
     83     } else if (WIFSIGNALED(status)) {
     84       if (WTERMSIG(status) != SIGKILL) {
     85         LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
     86       } else if (false) {
     87         LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
     88       }
     89 #ifdef WCOREDUMP
     90       if (WCOREDUMP(status)) {
     91         LOG(INFO) << "Process " << pid << " dumped core";
     92       }
     93 #endif /* ifdef WCOREDUMP */
     94     }
     95 
     96     // If the just-crashed process is the system_server, bring down zygote
     97     // so that it is restarted by init and system server will be restarted
     98     // from there.
     99     if (pid == gSystemServerPid) {
    100       LOG(ERROR) << "Exit zygote because system server (" << pid << ") has terminated";
    101       kill(getpid(), SIGKILL);
    102     }
    103   }
    104 
    105   if (pid < 0) {
    106     PLOG(WARNING) << "Zygote SIGCHLD error in waitpid";
    107   }
    108 }
    109 
    110 // Configures the SIGCHLD handler for the zygote process. This is configured
    111 // very late, because earlier in the runtime we may fork() and exec()
    112 // other processes, and we want to waitpid() for those rather than
    113 // have them be harvested immediately.
    114 //
    115 // This ends up being called repeatedly before each fork(), but there's
    116 // no real harm in that.
    117 static void SetSigChldHandler() {
    118   struct sigaction sa;
    119   memset(&sa, 0, sizeof(sa));
    120   sa.sa_handler = SigChldHandler;
    121 
    122   int err = sigaction(SIGCHLD, &sa, NULL);
    123   if (err < 0) {
    124     PLOG(WARNING) << "Error setting SIGCHLD handler";
    125   }
    126 }
    127 
    128 // Sets the SIGCHLD handler back to default behavior in zygote children.
    129 static void UnsetSigChldHandler() {
    130   struct sigaction sa;
    131   memset(&sa, 0, sizeof(sa));
    132   sa.sa_handler = SIG_DFL;
    133 
    134   int err = sigaction(SIGCHLD, &sa, NULL);
    135   if (err < 0) {
    136     PLOG(WARNING) << "Error unsetting SIGCHLD handler";
    137   }
    138 }
    139 
    140 // Calls POSIX setgroups() using the int[] object as an argument.
    141 // A NULL argument is tolerated.
    142 static void SetGids(JNIEnv* env, jintArray javaGids) {
    143   if (javaGids == NULL) {
    144     return;
    145   }
    146 
    147   COMPILE_ASSERT(sizeof(gid_t) == sizeof(jint), sizeof_gid_and_jint_are_differerent);
    148   ScopedIntArrayRO gids(env, javaGids);
    149   CHECK(gids.get() != NULL);
    150   int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
    151   if (rc == -1) {
    152     PLOG(FATAL) << "setgroups failed";
    153   }
    154 }
    155 
    156 // Sets the resource limits via setrlimit(2) for the values in the
    157 // two-dimensional array of integers that's passed in. The second dimension
    158 // contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
    159 // treated as an empty array.
    160 static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
    161   if (javaRlimits == NULL) {
    162     return;
    163   }
    164 
    165   rlimit rlim;
    166   memset(&rlim, 0, sizeof(rlim));
    167 
    168   for (int i = 0; i < env->GetArrayLength(javaRlimits); ++i) {
    169     ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
    170     ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
    171     if (javaRlimit.size() != 3) {
    172       LOG(FATAL) << "rlimits array must have a second dimension of size 3";
    173     }
    174 
    175     rlim.rlim_cur = javaRlimit[1];
    176     rlim.rlim_max = javaRlimit[2];
    177 
    178     int rc = setrlimit(javaRlimit[0], &rlim);
    179     if (rc == -1) {
    180       PLOG(FATAL) << "setrlimit(" << javaRlimit[0] << ", "
    181                   << "{" << rlim.rlim_cur << ", " << rlim.rlim_max << "}) failed";
    182     }
    183   }
    184 }
    185 
    186 #if defined(HAVE_ANDROID_OS)
    187 
    188 // The debug malloc library needs to know whether it's the zygote or a child.
    189 extern "C" int gMallocLeakZygoteChild;
    190 
    191 static void EnableDebugger() {
    192   // To let a non-privileged gdbserver attach to this
    193   // process, we must set our dumpable flag.
    194   if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
    195     PLOG(ERROR) << "prctl(PR_SET_DUMPABLE) failed for pid " << getpid();
    196   }
    197   // We don't want core dumps, though, so set the core dump size to 0.
    198   rlimit rl;
    199   rl.rlim_cur = 0;
    200   rl.rlim_max = RLIM_INFINITY;
    201   if (setrlimit(RLIMIT_CORE, &rl) == -1) {
    202     PLOG(ERROR) << "setrlimit(RLIMIT_CORE) failed for pid " << getpid();
    203   }
    204 }
    205 
    206 static void EnableKeepCapabilities() {
    207   int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
    208   if (rc == -1) {
    209     PLOG(FATAL) << "prctl(PR_SET_KEEPCAPS) failed";
    210   }
    211 }
    212 
    213 static void DropCapabilitiesBoundingSet() {
    214   for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
    215     if (i == CAP_NET_RAW) {
    216       // Don't break /system/bin/ping
    217       continue;
    218     }
    219     int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
    220     if (rc == -1) {
    221       if (errno == EINVAL) {
    222         PLOG(ERROR) << "prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
    223                     << "your kernel is compiled with file capabilities support";
    224       } else {
    225         PLOG(FATAL) << "prctl(PR_CAPBSET_DROP) failed";
    226       }
    227     }
    228   }
    229 }
    230 
    231 static void SetCapabilities(int64_t permitted, int64_t effective) {
    232   __user_cap_header_struct capheader;
    233   __user_cap_data_struct capdata;
    234 
    235   memset(&capheader, 0, sizeof(capheader));
    236   memset(&capdata, 0, sizeof(capdata));
    237 
    238   capheader.version = _LINUX_CAPABILITY_VERSION;
    239   capheader.pid = 0;
    240 
    241   capdata.effective = effective;
    242   capdata.permitted = permitted;
    243 
    244   if (capset(&capheader, &capdata) != 0) {
    245     PLOG(FATAL) << "capset(" << permitted << ", " << effective << ") failed";
    246   }
    247 }
    248 
    249 static void SetSchedulerPolicy() {
    250   errno = -set_sched_policy(0, SP_DEFAULT);
    251   if (errno != 0) {
    252     PLOG(FATAL) << "set_sched_policy(0, SP_DEFAULT) failed";
    253   }
    254 }
    255 
    256 #else
    257 
    258 static int gMallocLeakZygoteChild = 0;
    259 
    260 static void EnableDebugger() {}
    261 static void EnableKeepCapabilities() {}
    262 static void DropCapabilitiesBoundingSet() {}
    263 static void SetCapabilities(int64_t, int64_t) {}
    264 static void SetSchedulerPolicy() {}
    265 
    266 #endif
    267 
    268 static void EnableDebugFeatures(uint32_t debug_flags) {
    269   // Must match values in dalvik.system.Zygote.
    270   enum {
    271     DEBUG_ENABLE_DEBUGGER           = 1,
    272     DEBUG_ENABLE_CHECKJNI           = 1 << 1,
    273     DEBUG_ENABLE_ASSERT             = 1 << 2,
    274     DEBUG_ENABLE_SAFEMODE           = 1 << 3,
    275     DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
    276   };
    277 
    278   if ((debug_flags & DEBUG_ENABLE_CHECKJNI) != 0) {
    279     Runtime* runtime = Runtime::Current();
    280     JavaVMExt* vm = runtime->GetJavaVM();
    281     if (!vm->check_jni) {
    282       LOG(DEBUG) << "Late-enabling -Xcheck:jni";
    283       vm->SetCheckJniEnabled(true);
    284       // There's only one thread running at this point, so only one JNIEnv to fix up.
    285       Thread::Current()->GetJniEnv()->SetCheckJniEnabled(true);
    286     } else {
    287       LOG(DEBUG) << "Not late-enabling -Xcheck:jni (already on)";
    288     }
    289     debug_flags &= ~DEBUG_ENABLE_CHECKJNI;
    290   }
    291 
    292   if ((debug_flags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
    293     gLogVerbosity.third_party_jni = true;
    294     debug_flags &= ~DEBUG_ENABLE_JNI_LOGGING;
    295   }
    296 
    297   Dbg::SetJdwpAllowed((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0);
    298   if ((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0) {
    299     EnableDebugger();
    300   }
    301   debug_flags &= ~DEBUG_ENABLE_DEBUGGER;
    302 
    303   // These two are for backwards compatibility with Dalvik.
    304   debug_flags &= ~DEBUG_ENABLE_ASSERT;
    305   debug_flags &= ~DEBUG_ENABLE_SAFEMODE;
    306 
    307   if (debug_flags != 0) {
    308     LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
    309   }
    310 }
    311 
    312 // Create a private mount namespace and bind mount appropriate emulated
    313 // storage for the given user.
    314 static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
    315   if (mount_mode == MOUNT_EXTERNAL_NONE) {
    316     return true;
    317   }
    318 
    319   // See storage config details at http://source.android.com/tech/storage/
    320   userid_t user_id = multiuser_get_user_id(uid);
    321 
    322   // Create a second private mount namespace for our process
    323   if (unshare(CLONE_NEWNS) == -1) {
    324       PLOG(WARNING) << "Failed to unshare()";
    325       return false;
    326   }
    327 
    328   // Create bind mounts to expose external storage
    329   if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
    330     // These paths must already be created by init.rc
    331     const char* source = getenv("EMULATED_STORAGE_SOURCE");
    332     const char* target = getenv("EMULATED_STORAGE_TARGET");
    333     const char* legacy = getenv("EXTERNAL_STORAGE");
    334     if (source == NULL || target == NULL || legacy == NULL) {
    335       LOG(WARNING) << "Storage environment undefined; unable to provide external storage";
    336       return false;
    337     }
    338 
    339     // Prepare source paths
    340 
    341     // /mnt/shell/emulated/0
    342     std::string source_user(StringPrintf("%s/%d", source, user_id));
    343     // /storage/emulated/0
    344     std::string target_user(StringPrintf("%s/%d", target, user_id));
    345 
    346     if (fs_prepare_dir(source_user.c_str(), 0000, 0, 0) == -1
    347         || fs_prepare_dir(target_user.c_str(), 0000, 0, 0) == -1) {
    348       return false;
    349     }
    350 
    351     if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
    352       // Mount entire external storage tree for all users
    353       if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
    354         PLOG(WARNING) << "Failed to mount " << source << " to " << target;
    355         return false;
    356       }
    357     } else {
    358       // Only mount user-specific external storage
    359       if (mount(source_user.c_str(), target_user.c_str(), NULL, MS_BIND, NULL) == -1) {
    360         PLOG(WARNING) << "Failed to mount " << source_user << " to " << target_user;
    361         return false;
    362       }
    363     }
    364 
    365     if (fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
    366         return false;
    367     }
    368 
    369     // Finally, mount user-specific path into place for legacy users
    370     if (mount(target_user.c_str(), legacy, NULL, MS_BIND | MS_REC, NULL) == -1) {
    371       PLOG(WARNING) << "Failed to mount " << target_user << " to " << legacy;
    372       return false;
    373     }
    374   } else {
    375     LOG(WARNING) << "Mount mode " << mount_mode << " unsupported";
    376     return false;
    377   }
    378 
    379   return true;
    380 }
    381 
    382 #if defined(__linux__)
    383 static bool NeedsNoRandomizeWorkaround() {
    384 #if !defined(__arm__)
    385     return false;
    386 #else
    387     int major;
    388     int minor;
    389     struct utsname uts;
    390     if (uname(&uts) == -1) {
    391         return false;
    392     }
    393 
    394     if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
    395         return false;
    396     }
    397 
    398     // Kernels before 3.4.* need the workaround.
    399     return (major < 3) || ((major == 3) && (minor < 4));
    400 #endif
    401 }
    402 #endif
    403 
    404 // Utility routine to fork zygote and specialize the child process.
    405 static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
    406                                      jint debug_flags, jobjectArray javaRlimits,
    407                                      jlong permittedCapabilities, jlong effectiveCapabilities,
    408                                      jint mount_external,
    409                                      jstring java_se_info, jstring java_se_name, bool is_system_server) {
    410   Runtime* runtime = Runtime::Current();
    411   CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
    412   if (!runtime->PreZygoteFork()) {
    413     LOG(FATAL) << "pre-fork heap failed";
    414   }
    415 
    416   SetSigChldHandler();
    417 
    418   // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
    419   Thread* self = Thread::Current();
    420 
    421   // dvmDumpLoaderStats("zygote");  // TODO: ?
    422   pid_t pid = fork();
    423 
    424   if (pid == 0) {
    425     // The child process.
    426     gMallocLeakZygoteChild = 1;
    427 
    428     // Keep capabilities across UID change, unless we're staying root.
    429     if (uid != 0) {
    430       EnableKeepCapabilities();
    431     }
    432 
    433     DropCapabilitiesBoundingSet();
    434 
    435     if (!MountEmulatedStorage(uid, mount_external)) {
    436       PLOG(WARNING) << "Failed to mount emulated storage";
    437       if (errno == ENOTCONN || errno == EROFS) {
    438         // When device is actively encrypting, we get ENOTCONN here
    439         // since FUSE was mounted before the framework restarted.
    440         // When encrypted device is booting, we get EROFS since
    441         // FUSE hasn't been created yet by init.
    442         // In either case, continue without external storage.
    443       } else {
    444         LOG(FATAL) << "Cannot continue without emulated storage";
    445       }
    446     }
    447 
    448     SetGids(env, javaGids);
    449 
    450     SetRLimits(env, javaRlimits);
    451 
    452     int rc = setresgid(gid, gid, gid);
    453     if (rc == -1) {
    454       PLOG(FATAL) << "setresgid(" << gid << ") failed";
    455     }
    456 
    457     rc = setresuid(uid, uid, uid);
    458     if (rc == -1) {
    459       PLOG(FATAL) << "setresuid(" << uid << ") failed";
    460     }
    461 
    462 #if defined(__linux__)
    463     if (NeedsNoRandomizeWorkaround()) {
    464         // Work around ARM kernel ASLR lossage (http://b/5817320).
    465         int old_personality = personality(0xffffffff);
    466         int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
    467         if (new_personality == -1) {
    468             PLOG(WARNING) << "personality(" << new_personality << ") failed";
    469         }
    470     }
    471 #endif
    472 
    473     SetCapabilities(permittedCapabilities, effectiveCapabilities);
    474 
    475     SetSchedulerPolicy();
    476 
    477 #if defined(HAVE_ANDROID_OS)
    478     {  // NOLINT(whitespace/braces)
    479       const char* se_info_c_str = NULL;
    480       UniquePtr<ScopedUtfChars> se_info;
    481       if (java_se_info != NULL) {
    482           se_info.reset(new ScopedUtfChars(env, java_se_info));
    483           se_info_c_str = se_info->c_str();
    484           CHECK(se_info_c_str != NULL);
    485       }
    486       const char* se_name_c_str = NULL;
    487       UniquePtr<ScopedUtfChars> se_name;
    488       if (java_se_name != NULL) {
    489           se_name.reset(new ScopedUtfChars(env, java_se_name));
    490           se_name_c_str = se_name->c_str();
    491           CHECK(se_name_c_str != NULL);
    492       }
    493       rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
    494       if (rc == -1) {
    495         PLOG(FATAL) << "selinux_android_setcontext(" << uid << ", "
    496                     << (is_system_server ? "true" : "false") << ", "
    497                     << "\"" << se_info_c_str << "\", \"" << se_name_c_str << "\") failed";
    498       }
    499     }
    500 #else
    501     UNUSED(is_system_server);
    502     UNUSED(java_se_info);
    503     UNUSED(java_se_name);
    504 #endif
    505 
    506     // Our system thread ID, etc, has changed so reset Thread state.
    507     self->InitAfterFork();
    508 
    509     EnableDebugFeatures(debug_flags);
    510 
    511     UnsetSigChldHandler();
    512     runtime->DidForkFromZygote();
    513   } else if (pid > 0) {
    514     // the parent process
    515   }
    516   return pid;
    517 }
    518 
    519 static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
    520                                            jint debug_flags, jobjectArray rlimits, jint mount_external,
    521                                            jstring se_info, jstring se_name) {
    522   return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external, se_info, se_name, false);
    523 }
    524 
    525 static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
    526                                           jint debug_flags, jobjectArray rlimits,
    527                                           jlong permittedCapabilities, jlong effectiveCapabilities) {
    528   pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
    529                                       debug_flags, rlimits,
    530                                       permittedCapabilities, effectiveCapabilities,
    531                                       MOUNT_EXTERNAL_NONE, NULL, NULL, true);
    532   if (pid > 0) {
    533       // The zygote process checks whether the child process has died or not.
    534       LOG(INFO) << "System server process " << pid << " has been created";
    535       gSystemServerPid = pid;
    536       // There is a slight window that the system server process has crashed
    537       // but it went unnoticed because we haven't published its pid yet. So
    538       // we recheck here just to make sure that all is well.
    539       int status;
    540       if (waitpid(pid, &status, WNOHANG) == pid) {
    541           LOG(FATAL) << "System server process " << pid << " has died. Restarting Zygote!";
    542       }
    543   }
    544   return pid;
    545 }
    546 
    547 static JNINativeMethod gMethods[] = {
    548   NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[IILjava/lang/String;Ljava/lang/String;)I"),
    549   NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
    550 };
    551 
    552 void register_dalvik_system_Zygote(JNIEnv* env) {
    553   REGISTER_NATIVE_METHODS("dalvik/system/Zygote");
    554 }
    555 
    556 }  // namespace art
    557