Home | History | Annotate | Download | only in dumpstate
      1 /*
      2  * Copyright (C) 2016 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 #define LOG_TAG "dumpstate"
     18 
     19 #include "DumpstateInternal.h"
     20 
     21 #include <grp.h>
     22 #include <pwd.h>
     23 #include <stdint.h>
     24 #include <stdio.h>
     25 #include <string.h>
     26 #include <sys/capability.h>
     27 #include <sys/prctl.h>
     28 #include <sys/stat.h>
     29 #include <sys/types.h>
     30 #include <unistd.h>
     31 
     32 #include <cstdint>
     33 #include <string>
     34 #include <vector>
     35 
     36 #include <android-base/file.h>
     37 #include <log/log.h>
     38 
     39 uint64_t Nanotime() {
     40     timespec ts;
     41     clock_gettime(CLOCK_MONOTONIC, &ts);
     42     return static_cast<uint64_t>(ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec);
     43 }
     44 
     45 // Switches to non-root user and group.
     46 bool DropRootUser() {
     47     struct group* grp = getgrnam("shell");
     48     gid_t shell_gid = grp != nullptr ? grp->gr_gid : 0;
     49     struct passwd* pwd = getpwnam("shell");
     50     uid_t shell_uid = pwd != nullptr ? pwd->pw_uid : 0;
     51 
     52     if (!shell_gid || !shell_uid) {
     53         MYLOGE("Unable to get AID_SHELL: %s\n", strerror(errno));
     54         return false;
     55     }
     56 
     57     if (getgid() == shell_gid && getuid() == shell_uid) {
     58         MYLOGD("drop_root_user(): already running as Shell\n");
     59         return true;
     60     }
     61     /* ensure we will keep capabilities when we drop root */
     62     if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
     63         MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
     64         return false;
     65     }
     66 
     67     static const std::vector<std::string> group_names{
     68         "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats", "readproc", "bluetooth"};
     69     std::vector<gid_t> groups(group_names.size(), 0);
     70     for (size_t i = 0; i < group_names.size(); ++i) {
     71         grp = getgrnam(group_names[i].c_str());
     72         groups[i] = grp != nullptr ? grp->gr_gid : 0;
     73         if (groups[i] == 0) {
     74             MYLOGE("Unable to get required gid '%s': %s\n", group_names[i].c_str(),
     75                    strerror(errno));
     76             return false;
     77         }
     78     }
     79 
     80     if (setgroups(groups.size(), groups.data()) != 0) {
     81         MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
     82         return false;
     83     }
     84     if (setgid(shell_gid) != 0) {
     85         MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
     86         return false;
     87     }
     88     if (setuid(shell_uid) != 0) {
     89         MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
     90         return false;
     91     }
     92 
     93     struct __user_cap_header_struct capheader;
     94     struct __user_cap_data_struct capdata[2];
     95     memset(&capheader, 0, sizeof(capheader));
     96     memset(&capdata, 0, sizeof(capdata));
     97     capheader.version = _LINUX_CAPABILITY_VERSION_3;
     98     capheader.pid = 0;
     99 
    100     capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
    101     capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
    102     capdata[0].inheritable = 0;
    103     capdata[1].inheritable = 0;
    104 
    105     if (capset(&capheader, &capdata[0]) < 0) {
    106         MYLOGE("capset failed: %s\n", strerror(errno));
    107         return false;
    108     }
    109 
    110     return true;
    111 }
    112 
    113 int DumpFileFromFdToFd(const std::string& title, const std::string& path_string, int fd, int out_fd,
    114                        bool dry_run) {
    115     const char* path = path_string.c_str();
    116     if (!title.empty()) {
    117         dprintf(out_fd, "------ %s (%s", title.c_str(), path);
    118 
    119         struct stat st;
    120         // Only show the modification time of non-device files.
    121         size_t path_len = strlen(path);
    122         if ((path_len < 6 || memcmp(path, "/proc/", 6)) &&
    123             (path_len < 5 || memcmp(path, "/sys/", 5)) &&
    124             (path_len < 3 || memcmp(path, "/d/", 3)) && !fstat(fd, &st)) {
    125             char stamp[80];
    126             time_t mtime = st.st_mtime;
    127             strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
    128             dprintf(out_fd, ": %s", stamp);
    129         }
    130         dprintf(out_fd, ") ------\n");
    131         fsync(out_fd);
    132     }
    133     if (dry_run) {
    134         if (out_fd != STDOUT_FILENO) {
    135             // There is no title, but we should still print a dry-run message
    136             dprintf(out_fd, "%s: skipped on dry run\n", path);
    137         } else if (!title.empty()) {
    138             dprintf(out_fd, "\t(skipped on dry run)\n");
    139         }
    140         fsync(out_fd);
    141         return 0;
    142     }
    143     bool newline = false;
    144     fd_set read_set;
    145     timeval tm;
    146     while (true) {
    147         FD_ZERO(&read_set);
    148         FD_SET(fd, &read_set);
    149         /* Timeout if no data is read for 30 seconds. */
    150         tm.tv_sec = 30;
    151         tm.tv_usec = 0;
    152         uint64_t elapsed = Nanotime();
    153         int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, nullptr, nullptr, &tm));
    154         if (ret == -1) {
    155             dprintf(out_fd, "*** %s: select failed: %s\n", path, strerror(errno));
    156             newline = true;
    157             break;
    158         } else if (ret == 0) {
    159             elapsed = Nanotime() - elapsed;
    160             dprintf(out_fd, "*** %s: Timed out after %.3fs\n", path, (float)elapsed / NANOS_PER_SEC);
    161             newline = true;
    162             break;
    163         } else {
    164             char buffer[65536];
    165             ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
    166             if (bytes_read > 0) {
    167                 android::base::WriteFully(out_fd, buffer, bytes_read);
    168                 newline = (buffer[bytes_read - 1] == '\n');
    169             } else {
    170                 if (bytes_read == -1) {
    171                     dprintf(out_fd, "*** %s: Failed to read from fd: %s", path, strerror(errno));
    172                     newline = true;
    173                 }
    174                 break;
    175             }
    176         }
    177     }
    178     close(fd);
    179 
    180     if (!newline) dprintf(out_fd, "\n");
    181     if (!title.empty()) dprintf(out_fd, "\n");
    182     return 0;
    183 }
    184