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 #include "fscrypt_init_extensions.h"
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fts.h>
22 #include <sys/mount.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25
26 #include <string>
27 #include <vector>
28
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/parseint.h>
32 #include <android-base/stringprintf.h>
33 #include <android-base/strings.h>
34 #include <cutils/properties.h>
35 #include <cutils/sockets.h>
36 #include <fscrypt/fscrypt.h>
37 #include <logwrap/logwrap.h>
38
39 #define TAG "fscrypt"
40
41 using namespace android::fscrypt;
42
43 // TODO(b/139378601): use a single central implementation of this.
delete_dir_contents(const std::string & dir)44 static void delete_dir_contents(const std::string& dir) {
45 char* const paths[2] = {const_cast<char*>(dir.c_str()), nullptr};
46 FTS* fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr);
47 FTSENT* cur;
48 while ((cur = fts_read(fts)) != nullptr) {
49 if (cur->fts_info == FTS_ERR) {
50 PLOG(ERROR) << "fts_read";
51 break;
52 }
53 if (dir == cur->fts_path) {
54 continue;
55 }
56 switch (cur->fts_info) {
57 case FTS_D:
58 break; // Ignore these
59 case FTS_DP:
60 if (rmdir(cur->fts_path) == -1) {
61 PLOG(ERROR) << "rmdir " << cur->fts_path;
62 }
63 break;
64 default:
65 PLOG(ERROR) << "FTS unexpected type " << cur->fts_info << " at " << cur->fts_path;
66 if (rmdir(cur->fts_path) != -1) break;
67 // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
68 FALLTHROUGH_INTENDED;
69 case FTS_F:
70 case FTS_SL:
71 case FTS_SLNONE:
72 if (unlink(cur->fts_path) == -1) {
73 PLOG(ERROR) << "unlink " << cur->fts_path;
74 }
75 break;
76 }
77 }
78
79 if (fts_close(fts) != 0) {
80 PLOG(ERROR) << "fts_close";
81 }
82 }
83
84 // Look up an encryption policy The policy (key reference
85 // and encryption options) to use is read from files that were written by vold.
LookupPolicy(const std::string & ref_basename,EncryptionPolicy * policy)86 static bool LookupPolicy(const std::string& ref_basename, EncryptionPolicy* policy) {
87 std::string ref_filename = std::string("/data") + ref_basename;
88 if (!android::base::ReadFileToString(ref_filename, &policy->key_raw_ref)) {
89 LOG(ERROR) << "Unable to read system policy with name " << ref_filename;
90 return false;
91 }
92
93 auto options_filename = std::string("/data") + fscrypt_key_mode;
94 std::string options_string;
95 if (!android::base::ReadFileToString(options_filename, &options_string)) {
96 LOG(ERROR) << "Cannot read encryption options string";
97 return false;
98 }
99 if (!ParseOptions(options_string, &policy->options)) {
100 LOG(ERROR) << "Invalid encryption options string: " << options_string;
101 return false;
102 }
103 return true;
104 }
105
EnsurePolicyOrLog(const EncryptionPolicy & policy,const std::string & dir)106 static bool EnsurePolicyOrLog(const EncryptionPolicy& policy, const std::string& dir) {
107 if (!EnsurePolicy(policy, dir)) {
108 std::string ref_hex;
109 BytesToHex(policy.key_raw_ref, &ref_hex);
110 LOG(ERROR) << "Setting " << ref_hex << " policy on " << dir << " failed!";
111 return false;
112 }
113 return true;
114 }
115
SetPolicyOn(const std::string & ref_basename,const std::string & dir)116 static bool SetPolicyOn(const std::string& ref_basename, const std::string& dir) {
117 EncryptionPolicy policy;
118 if (!LookupPolicy(ref_basename, &policy)) return false;
119 if (!EnsurePolicyOrLog(policy, dir)) return false;
120 return true;
121 }
122
FscryptSetDirectoryPolicy(const std::string & ref_basename,FscryptAction action,const std::string & dir)123 bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
124 const std::string& dir) {
125 if (action == FscryptAction::kNone) {
126 return true;
127 }
128 if (SetPolicyOn(ref_basename, dir) || action == FscryptAction::kAttempt) {
129 return true;
130 }
131 if (action == FscryptAction::kDeleteIfNecessary) {
132 LOG(ERROR) << "Setting policy failed, deleting: " << dir;
133 delete_dir_contents(dir);
134 return SetPolicyOn(ref_basename, dir);
135 }
136 return false;
137 }
138