Skip to content

Commit 68258e8

Browse files
committed
Make encryption action an argument to mkdir
FscryptSetDirectoryPolicy no longer tries to infer the action from the filename. Well mostly; it still assumes top-level directories in /data should be encrypted unless the mkdir arguments say otherwise, but it warns. Bug: 26641735 Test: boot, check log messages Change-Id: Id6d2cea7fb856f17323897d85cf6190c981b443c
1 parent 4645210 commit 68258e8

9 files changed

+289
-196
lines changed

init/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,12 +505,23 @@ Commands
505505
> Used to mark the point right after /data is mounted. Used to implement the
506506
`class_reset_post_data` and `class_start_post_data` commands.
507507

508-
`mkdir <path> [mode] [owner] [group]`
508+
`mkdir <path> [<mode>] [<owner>] [<group>] [encryption=<action>] [key=<key>]`
509509
> Create a directory at _path_, optionally with the given mode, owner, and
510510
group. If not provided, the directory is created with permissions 755 and
511511
owned by the root user and root group. If provided, the mode, owner and group
512512
will be updated if the directory exists already.
513513

514+
> _action_ can be one of:
515+
* `None`: take no encryption action; directory will be encrypted if parent is.
516+
* `Require`: encrypt directory, abort boot process if encryption fails
517+
* `Attempt`: try to set an encryption policy, but continue if it fails
518+
* `DeleteIfNecessary`: recursively delete directory if necessary to set
519+
encryption policy.
520+
521+
> _key_ can be one of:
522+
* `ref`: use the systemwide DE key
523+
* `per_boot_ref`: use the key freshly generated on each boot.
524+
514525
`mount_all <fstab> [ <path> ]\* [--<option>]`
515526
> Calls fs\_mgr\_mount\_all on the given fs\_mgr-format fstab with optional
516527
options "early" and "late".

init/builtins.cpp

Lines changed: 34 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -364,67 +364,52 @@ static Result<void> do_interface_stop(const BuiltinArguments& args) {
364364
return {};
365365
}
366366

367-
// mkdir <path> [mode] [owner] [group]
367+
// mkdir <path> [mode] [owner] [group] [<option> ...]
368368
static Result<void> do_mkdir(const BuiltinArguments& args) {
369-
mode_t mode = 0755;
370-
Result<uid_t> uid = -1;
371-
Result<gid_t> gid = -1;
372-
373-
switch (args.size()) {
374-
case 5:
375-
gid = DecodeUid(args[4]);
376-
if (!gid) {
377-
return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
378-
}
379-
FALLTHROUGH_INTENDED;
380-
case 4:
381-
uid = DecodeUid(args[3]);
382-
if (!uid) {
383-
return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
384-
}
385-
FALLTHROUGH_INTENDED;
386-
case 3:
387-
mode = std::strtoul(args[2].c_str(), 0, 8);
388-
FALLTHROUGH_INTENDED;
389-
case 2:
390-
break;
391-
default:
392-
return Error() << "Unexpected argument count: " << args.size();
369+
auto options = ParseMkdir(args.args);
370+
if (!options) return options.error();
371+
std::string ref_basename;
372+
if (options->ref_option == "ref") {
373+
ref_basename = fscrypt_key_ref;
374+
} else if (options->ref_option == "per_boot_ref") {
375+
ref_basename = fscrypt_key_per_boot_ref;
376+
} else {
377+
return Error() << "Unknown key option: '" << options->ref_option << "'";
393378
}
394-
std::string target = args[1];
379+
395380
struct stat mstat;
396-
if (lstat(target.c_str(), &mstat) != 0) {
381+
if (lstat(options->target.c_str(), &mstat) != 0) {
397382
if (errno != ENOENT) {
398-
return ErrnoError() << "lstat() failed on " << target;
383+
return ErrnoError() << "lstat() failed on " << options->target;
399384
}
400-
if (!make_dir(target, mode)) {
401-
return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << target;
385+
if (!make_dir(options->target, options->mode)) {
386+
return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << options->target;
402387
}
403-
if (lstat(target.c_str(), &mstat) != 0) {
404-
return ErrnoError() << "lstat() failed on new " << target;
388+
if (lstat(options->target.c_str(), &mstat) != 0) {
389+
return ErrnoError() << "lstat() failed on new " << options->target;
405390
}
406391
}
407392
if (!S_ISDIR(mstat.st_mode)) {
408-
return Error() << "Not a directory on " << target;
393+
return Error() << "Not a directory on " << options->target;
409394
}
410-
bool needs_chmod = (mstat.st_mode & ~S_IFMT) != mode;
411-
if ((*uid != static_cast<uid_t>(-1) && *uid != mstat.st_uid) ||
412-
(*gid != static_cast<gid_t>(-1) && *gid != mstat.st_gid)) {
413-
if (lchown(target.c_str(), *uid, *gid) == -1) {
414-
return ErrnoError() << "lchown failed on " << target;
395+
bool needs_chmod = (mstat.st_mode & ~S_IFMT) != options->mode;
396+
if ((options->uid != static_cast<uid_t>(-1) && options->uid != mstat.st_uid) ||
397+
(options->gid != static_cast<gid_t>(-1) && options->gid != mstat.st_gid)) {
398+
if (lchown(options->target.c_str(), options->uid, options->gid) == -1) {
399+
return ErrnoError() << "lchown failed on " << options->target;
415400
}
416401
// chown may have cleared S_ISUID and S_ISGID, chmod again
417402
needs_chmod = true;
418403
}
419404
if (needs_chmod) {
420-
if (fchmodat(AT_FDCWD, target.c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
421-
return ErrnoError() << "fchmodat() failed on " << target;
405+
if (fchmodat(AT_FDCWD, options->target.c_str(), options->mode, AT_SYMLINK_NOFOLLOW) == -1) {
406+
return ErrnoError() << "fchmodat() failed on " << options->target;
422407
}
423408
}
424409
if (fscrypt_is_native()) {
425-
if (fscrypt_set_directory_policy(target)) {
410+
if (!FscryptSetDirectoryPolicy(ref_basename, options->fscrypt_action, options->target)) {
426411
return reboot_into_recovery(
427-
{"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + target});
412+
{"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options->target});
428413
}
429414
}
430415
return {};
@@ -589,8 +574,8 @@ static Result<void> queue_fs_event(int code) {
589574
return reboot_into_recovery(options);
590575
/* If reboot worked, there is no return. */
591576
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
592-
if (fscrypt_install_keyring()) {
593-
return Error() << "fscrypt_install_keyring() failed";
577+
if (!FscryptInstallKeyring()) {
578+
return Error() << "FscryptInstallKeyring() failed";
594579
}
595580
property_set("ro.crypto.state", "encrypted");
596581
property_set("ro.crypto.type", "file");
@@ -600,8 +585,8 @@ static Result<void> queue_fs_event(int code) {
600585
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
601586
return {};
602587
} else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
603-
if (fscrypt_install_keyring()) {
604-
return Error() << "fscrypt_install_keyring() failed";
588+
if (!FscryptInstallKeyring()) {
589+
return Error() << "FscryptInstallKeyring() failed";
605590
}
606591
property_set("ro.crypto.state", "encrypted");
607592
property_set("ro.crypto.type", "file");
@@ -611,8 +596,8 @@ static Result<void> queue_fs_event(int code) {
611596
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
612597
return {};
613598
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
614-
if (fscrypt_install_keyring()) {
615-
return Error() << "fscrypt_install_keyring() failed";
599+
if (!FscryptInstallKeyring()) {
600+
return Error() << "FscryptInstallKeyring() failed";
616601
}
617602
property_set("ro.crypto.state", "encrypted");
618603
property_set("ro.crypto.type", "file");
@@ -1257,7 +1242,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
12571242
{"load_system_props", {0, 0, {false, do_load_system_props}}},
12581243
{"loglevel", {1, 1, {false, do_loglevel}}},
12591244
{"mark_post_data", {0, 0, {false, do_mark_post_data}}},
1260-
{"mkdir", {1, 4, {true, do_mkdir}}},
1245+
{"mkdir", {1, 6, {true, do_mkdir}}},
12611246
// TODO: Do mount operations in vendor_init.
12621247
// mount_all is currently too complex to run in vendor_init as it queues action triggers,
12631248
// imports rc scripts, etc. It should be simplified and run in vendor_init context.

init/check_builtins.cpp

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,22 +121,10 @@ Result<void> check_loglevel(const BuiltinArguments& args) {
121121
}
122122

123123
Result<void> check_mkdir(const BuiltinArguments& args) {
124-
if (args.size() >= 4) {
125-
if (!args[3].empty()) {
126-
auto uid = DecodeUid(args[3]);
127-
if (!uid) {
128-
return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
129-
}
130-
}
131-
132-
if (args.size() == 5 && !args[4].empty()) {
133-
auto gid = DecodeUid(args[4]);
134-
if (!gid) {
135-
return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
136-
}
137-
}
124+
auto options = ParseMkdir(args.args);
125+
if (!options) {
126+
return options.error();
138127
}
139-
140128
return {};
141129
}
142130

init/fscrypt_init_extensions.cpp

Lines changed: 38 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,15 @@
4141

4242
using namespace android::fscrypt;
4343

44-
static int set_policy_on(const std::string& ref_basename, const std::string& dir);
45-
46-
int fscrypt_install_keyring() {
44+
bool FscryptInstallKeyring() {
4745
key_serial_t device_keyring = add_key("keyring", "fscrypt", 0, 0, KEY_SPEC_SESSION_KEYRING);
4846

4947
if (device_keyring == -1) {
5048
PLOG(ERROR) << "Failed to create keyring";
51-
return -1;
49+
return false;
5250
}
53-
5451
LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid();
55-
56-
return 0;
52+
return true;
5753
}
5854

5955
// TODO(b/139378601): use a single central implementation of this.
@@ -97,102 +93,57 @@ static void delete_dir_contents(const std::string& dir) {
9793
}
9894
}
9995

100-
int fscrypt_set_directory_policy(const std::string& dir) {
101-
const std::string prefix = "/data/";
102-
103-
if (!android::base::StartsWith(dir, prefix)) {
104-
return 0;
105-
}
106-
107-
// Special-case /data/media/obb per b/64566063
108-
if (dir == "/data/media/obb") {
109-
// Try to set policy on this directory, but if it is non-empty this may fail.
110-
set_policy_on(fscrypt_key_ref, dir);
111-
return 0;
112-
}
113-
114-
// Only set policy on first level /data directories
115-
// To make this less restrictive, consider using a policy file.
116-
// However this is overkill for as long as the policy is simply
117-
// to apply a global policy to all /data folders created via makedir
118-
if (dir.find_first_of('/', prefix.size()) != std::string::npos) {
119-
return 0;
120-
}
121-
122-
// Special case various directories that must not be encrypted,
123-
// often because their subdirectories must be encrypted.
124-
// This isn't a nice way to do this, see b/26641735
125-
std::vector<std::string> directories_to_exclude = {
126-
"lost+found",
127-
"system_ce", "system_de",
128-
"misc_ce", "misc_de",
129-
"vendor_ce", "vendor_de",
130-
"media",
131-
"data", "user", "user_de",
132-
"apex", "preloads", "app-staging",
133-
"gsi",
134-
};
135-
for (const auto& d : directories_to_exclude) {
136-
if ((prefix + d) == dir) {
137-
LOG(INFO) << "Not setting policy on " << dir;
138-
return 0;
139-
}
140-
}
141-
std::vector<std::string> per_boot_directories = {
142-
"per_boot",
143-
};
144-
for (const auto& d : per_boot_directories) {
145-
if ((prefix + d) == dir) {
146-
LOG(INFO) << "Setting per_boot key on " << dir;
147-
return set_policy_on(fscrypt_key_per_boot_ref, dir);
148-
}
149-
}
150-
int err = set_policy_on(fscrypt_key_ref, dir);
151-
if (err == 0) {
152-
return 0;
153-
}
154-
// Empty these directories if policy setting fails.
155-
std::vector<std::string> wipe_on_failure = {
156-
"rollback", "rollback-observer", // b/139193659
157-
};
158-
for (const auto& d : wipe_on_failure) {
159-
if ((prefix + d) == dir) {
160-
LOG(ERROR) << "Setting policy failed, deleting: " << dir;
161-
delete_dir_contents(dir);
162-
err = set_policy_on(fscrypt_key_ref, dir);
163-
break;
164-
}
165-
}
166-
return err;
167-
}
168-
169-
// Set an encryption policy on the given directory. The policy (key reference
96+
// Look up an encryption policy The policy (key reference
17097
// and encryption options) to use is read from files that were written by vold.
171-
static int set_policy_on(const std::string& ref_basename, const std::string& dir) {
172-
EncryptionPolicy policy;
98+
static bool LookupPolicy(const std::string& ref_basename, EncryptionPolicy* policy) {
17399
std::string ref_filename = std::string("/data") + ref_basename;
174-
if (!android::base::ReadFileToString(ref_filename, &policy.key_raw_ref)) {
175-
LOG(ERROR) << "Unable to read system policy to set on " << dir;
176-
return -1;
100+
if (!android::base::ReadFileToString(ref_filename, &policy->key_raw_ref)) {
101+
LOG(ERROR) << "Unable to read system policy with name " << ref_filename;
102+
return false;
177103
}
178104

179105
auto options_filename = std::string("/data") + fscrypt_key_mode;
180106
std::string options_string;
181107
if (!android::base::ReadFileToString(options_filename, &options_string)) {
182108
LOG(ERROR) << "Cannot read encryption options string";
183-
return -1;
109+
return false;
184110
}
185-
if (!ParseOptions(options_string, &policy.options)) {
111+
if (!ParseOptions(options_string, &policy->options)) {
186112
LOG(ERROR) << "Invalid encryption options string: " << options_string;
187-
return -1;
113+
return false;
188114
}
115+
return true;
116+
}
189117

118+
static bool EnsurePolicyOrLog(const EncryptionPolicy& policy, const std::string& dir) {
190119
if (!EnsurePolicy(policy, dir)) {
191120
std::string ref_hex;
192121
BytesToHex(policy.key_raw_ref, &ref_hex);
193122
LOG(ERROR) << "Setting " << ref_hex << " policy on " << dir << " failed!";
194-
return -1;
123+
return false;
195124
}
125+
return true;
126+
}
127+
128+
static bool SetPolicyOn(const std::string& ref_basename, const std::string& dir) {
129+
EncryptionPolicy policy;
130+
if (!LookupPolicy(ref_basename, &policy)) return false;
131+
if (!EnsurePolicyOrLog(policy, dir)) return false;
132+
return true;
133+
}
196134

197-
return 0;
135+
bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
136+
const std::string& dir) {
137+
if (action == FscryptAction::kNone) {
138+
return true;
139+
}
140+
if (SetPolicyOn(ref_basename, dir) || action == FscryptAction::kAttempt) {
141+
return true;
142+
}
143+
if (action == FscryptAction::kDeleteIfNecessary) {
144+
LOG(ERROR) << "Setting policy failed, deleting: " << dir;
145+
delete_dir_contents(dir);
146+
return SetPolicyOn(ref_basename, dir);
147+
}
148+
return false;
198149
}

init/fscrypt_init_extensions.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,13 @@
1818

1919
#include <string>
2020

21-
int fscrypt_install_keyring();
22-
int fscrypt_set_directory_policy(const std::string& dir);
21+
enum class FscryptAction {
22+
kNone,
23+
kAttempt,
24+
kRequire,
25+
kDeleteIfNecessary,
26+
};
27+
28+
bool FscryptInstallKeyring();
29+
bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
30+
const std::string& dir);

0 commit comments

Comments
 (0)