blob: 574bbfee93044a7e0f53901685ff52537c376077 [file] [log] [blame]
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -04001// Copyright (C) 2016 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#define LOG_TAG "sdcard"
16
17#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <linux/fuse.h>
21#include <pthread.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/inotify.h>
25#include <sys/mount.h>
26#include <sys/resource.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <unistd.h>
30
Daniel Rosenberg95268192016-08-26 16:54:46 -070031#include <android-base/file.h>
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -040032#include <android-base/logging.h>
Jorge Lucangeli Obesbae15b42016-07-18 13:46:42 -040033#include <android-base/macros.h>
Daniel Rosenberg95268192016-08-26 16:54:46 -070034#include <android-base/stringprintf.h>
35#include <android-base/strings.h>
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -040036
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -040037#include <cutils/fs.h>
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -040038#include <cutils/multiuser.h>
Daniel Rosenberg95268192016-08-26 16:54:46 -070039#include <cutils/properties.h>
40
Jorge Lucangeli Obesc96f53e2016-07-14 14:50:14 -040041#include <libminijail.h>
42#include <scoped_minijail.h>
43
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -040044#include <private/android_filesystem_config.h>
45
Jeff Sharkey68e10932018-01-08 11:22:38 -070046// NOTE: This is a vestigial program that simply exists to mount the in-kernel
47// sdcardfs filesystem. The older FUSE-based design that used to live here has
48// been completely removed to avoid confusion.
Daniel Rosenberg95268192016-08-26 16:54:46 -070049
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -040050/* Supplementary groups to execute with. */
51static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
52
Jorge Lucangeli Obesc96f53e2016-07-14 14:50:14 -040053static void drop_privs(uid_t uid, gid_t gid) {
54 ScopedMinijail j(minijail_new());
Jorge Lucangeli Obesbae15b42016-07-18 13:46:42 -040055 minijail_set_supplementary_gids(j.get(), arraysize(kGroups), kGroups);
Jorge Lucangeli Obesc96f53e2016-07-14 14:50:14 -040056 minijail_change_gid(j.get(), gid);
57 minijail_change_uid(j.get(), uid);
58 /* minijail_enter() will abort if priv-dropping fails. */
59 minijail_enter(j.get());
60}
61
Rom Lemarchand98139142017-09-15 18:47:50 +000062static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path,
63 uid_t fsuid, gid_t fsgid, bool multi_user, userid_t userid, gid_t gid,
Jeff Sharkeye2e36102018-01-08 11:43:46 -070064 mode_t mask, bool derive_gid, bool default_normal) {
65 // Try several attempts, each time with one less option, to gracefully
66 // handle older kernels that aren't updated yet.
67 for (int i = 0; i < 4; i++) {
68 std::string new_opts;
69 if (multi_user && i < 3) new_opts += "multiuser,";
70 if (derive_gid && i < 2) new_opts += "derive_gid,";
71 if (default_normal && i < 1) new_opts += "default_normal,";
Daniel Rosenberg95268192016-08-26 16:54:46 -070072
Jeff Sharkeye2e36102018-01-08 11:43:46 -070073 auto opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
74 fsuid, fsgid, new_opts.c_str(), mask, userid, gid);
75 if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
76 MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
77 PLOG(WARNING) << "Failed to mount sdcardfs with options " << opts;
Rom Lemarchand98139142017-09-15 18:47:50 +000078 } else {
Jeff Sharkeye2e36102018-01-08 11:43:46 -070079 return true;
Rom Lemarchand98139142017-09-15 18:47:50 +000080 }
Daniel Rosenberg95268192016-08-26 16:54:46 -070081 }
Jeff Sharkeye2e36102018-01-08 11:43:46 -070082
83 return false;
Daniel Rosenberg95268192016-08-26 16:54:46 -070084}
85
Daniel Rosenbergfc592322016-10-27 17:43:37 -070086static bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path,
87 gid_t gid, mode_t mask) {
88 std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid);
89
90 if (mount(source_path.c_str(), dest_path.c_str(), nullptr,
91 MS_BIND, nullptr) != 0) {
92 PLOG(ERROR) << "failed to bind mount sdcardfs filesystem";
93 return false;
94 }
95
96 if (mount(source_path.c_str(), dest_path.c_str(), "none",
97 MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
98 PLOG(ERROR) << "failed to mount sdcardfs filesystem";
99 if (umount2(dest_path.c_str(), MNT_DETACH))
100 PLOG(WARNING) << "Failed to unmount bind";
101 return false;
102 }
103
104 return true;
105}
106
Daniel Rosenberg95268192016-08-26 16:54:46 -0700107static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
Rom Lemarchand98139142017-09-15 18:47:50 +0000108 gid_t gid, userid_t userid, bool multi_user, bool full_write,
Jeff Sharkeye2e36102018-01-08 11:43:46 -0700109 bool derive_gid, bool default_normal) {
Daniel Rosenberg95268192016-08-26 16:54:46 -0700110 std::string dest_path_default = "/mnt/runtime/default/" + label;
111 std::string dest_path_read = "/mnt/runtime/read/" + label;
112 std::string dest_path_write = "/mnt/runtime/write/" + label;
113
114 umask(0);
115 if (multi_user) {
116 // Multi-user storage is fully isolated per user, so "other"
117 // permissions are completely masked off.
118 if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
Jeff Sharkeye2e36102018-01-08 11:43:46 -0700119 AID_SDCARD_RW, 0006, derive_gid, default_normal) ||
Rom Lemarchand98139142017-09-15 18:47:50 +0000120 !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027) ||
121 !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
122 full_write ? 0007 : 0027)) {
Daniel Rosenberg95268192016-08-26 16:54:46 -0700123 LOG(FATAL) << "failed to sdcardfs_setup";
124 }
125 } else {
126 // Physical storage is readable by all users on device, but
127 // the Android directories are masked off to a single user
128 // deep inside attr_from_stat().
129 if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
Jeff Sharkeye2e36102018-01-08 11:43:46 -0700130 AID_SDCARD_RW, 0006, derive_gid, default_normal) ||
Rom Lemarchand98139142017-09-15 18:47:50 +0000131 !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY,
132 full_write ? 0027 : 0022) ||
133 !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
134 full_write ? 0007 : 0022)) {
Daniel Rosenberg95268192016-08-26 16:54:46 -0700135 LOG(FATAL) << "failed to sdcardfs_setup";
136 }
137 }
138
139 // Will abort if priv-dropping fails.
140 drop_privs(uid, gid);
141
142 if (multi_user) {
143 std::string obb_path = source_path + "/obb";
144 fs_prepare_dir(obb_path.c_str(), 0775, uid, gid);
145 }
146
147 exit(0);
148}
149
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400150static int usage() {
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -0400151 LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>"
152 << " -u: specify UID to run as"
153 << " -g: specify GID to run as"
154 << " -U: specify user ID that owns device"
155 << " -m: source_path is multi-user"
Rom Lemarchand98139142017-09-15 18:47:50 +0000156 << " -w: runtime write mount has full write access"
157 << " -P preserve owners on the lower file system";
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400158 return 1;
159}
160
161int main(int argc, char **argv) {
162 const char *source_path = NULL;
163 const char *label = NULL;
164 uid_t uid = 0;
165 gid_t gid = 0;
166 userid_t userid = 0;
167 bool multi_user = false;
168 bool full_write = false;
Rom Lemarchand98139142017-09-15 18:47:50 +0000169 bool derive_gid = false;
Jeff Sharkeye2e36102018-01-08 11:43:46 -0700170 bool default_normal = false;
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400171 int i;
172 struct rlimit rlim;
173 int fs_version;
174
Jeff Sharkeye2e36102018-01-08 11:43:46 -0700175 setenv("ANDROID_LOG_TAGS", "*:v", 1);
176 android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
177
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400178 int opt;
Jeff Sharkeye2e36102018-01-08 11:43:46 -0700179 while ((opt = getopt(argc, argv, "u:g:U:mwGi")) != -1) {
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400180 switch (opt) {
181 case 'u':
182 uid = strtoul(optarg, NULL, 10);
183 break;
184 case 'g':
185 gid = strtoul(optarg, NULL, 10);
186 break;
187 case 'U':
188 userid = strtoul(optarg, NULL, 10);
189 break;
190 case 'm':
191 multi_user = true;
192 break;
193 case 'w':
194 full_write = true;
195 break;
Rom Lemarchand98139142017-09-15 18:47:50 +0000196 case 'G':
197 derive_gid = true;
198 break;
Jeff Sharkeye2e36102018-01-08 11:43:46 -0700199 case 'i':
200 default_normal = true;
201 break;
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400202 case '?':
203 default:
204 return usage();
205 }
206 }
207
208 for (i = optind; i < argc; i++) {
209 char* arg = argv[i];
210 if (!source_path) {
211 source_path = arg;
212 } else if (!label) {
213 label = arg;
214 } else {
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -0400215 LOG(ERROR) << "too many arguments";
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400216 return usage();
217 }
218 }
219
220 if (!source_path) {
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -0400221 LOG(ERROR) << "no source path specified";
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400222 return usage();
223 }
224 if (!label) {
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -0400225 LOG(ERROR) << "no label specified";
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400226 return usage();
227 }
228 if (!uid || !gid) {
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -0400229 LOG(ERROR) << "uid and gid must be nonzero";
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400230 return usage();
231 }
232
233 rlim.rlim_cur = 8192;
234 rlim.rlim_max = 8192;
Christopher Ferrisd6b0d372016-10-06 12:51:20 -0700235 if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -0400236 PLOG(ERROR) << "setting RLIMIT_NOFILE failed";
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400237 }
238
239 while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
Jorge Lucangeli Obesc9e17102016-07-12 17:05:32 -0400240 LOG(ERROR) << "installd fs upgrade not yet complete; waiting...";
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400241 sleep(1);
242 }
243
Jeff Sharkey68e10932018-01-08 11:22:38 -0700244 run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write, derive_gid,
245 default_normal);
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400246 return 1;
247}