| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2019 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 | // Note that these check functions cannot check expanded arguments from properties, since they will | 
 | 18 | // not know what those properties would be at runtime.  They will be passed an empty string in the | 
 | 19 | // situation that the input line had a property expansion without a default value, since an empty | 
 | 20 | // string is otherwise an impossible value.  They should therefore disregard checking empty | 
 | 21 | // arguments. | 
 | 22 |  | 
 | 23 | #include "check_builtins.h" | 
 | 24 |  | 
 | 25 | #include <sys/time.h> | 
 | 26 |  | 
 | 27 | #include <android-base/logging.h> | 
| Mark Salyzyn | ffa52e9 | 2020-05-14 09:20:30 -0700 | [diff] [blame] | 28 | #include <android-base/parsedouble.h> | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 29 | #include <android-base/parseint.h> | 
 | 30 | #include <android-base/strings.h> | 
 | 31 |  | 
 | 32 | #include "builtin_arguments.h" | 
| Tom Cherry | b5f2ec0 | 2019-11-08 17:54:27 -0800 | [diff] [blame] | 33 | #include "host_init_verifier.h" | 
| Daniel Norman | d2533c3 | 2019-08-02 15:13:50 -0700 | [diff] [blame] | 34 | #include "interface_utils.h" | 
| Tom Cherry | b5f2ec0 | 2019-11-08 17:54:27 -0800 | [diff] [blame] | 35 | #include "property_type.h" | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 36 | #include "rlimit_parser.h" | 
 | 37 | #include "service.h" | 
 | 38 | #include "util.h" | 
 | 39 |  | 
 | 40 | using android::base::ParseInt; | 
 | 41 | using android::base::StartsWith; | 
 | 42 |  | 
 | 43 | #define ReturnIfAnyArgsEmpty()     \ | 
 | 44 |     for (const auto& arg : args) { \ | 
 | 45 |         if (arg.empty()) {         \ | 
 | 46 |             return {};             \ | 
 | 47 |         }                          \ | 
 | 48 |     } | 
 | 49 |  | 
 | 50 | namespace android { | 
 | 51 | namespace init { | 
 | 52 |  | 
 | 53 | Result<void> check_chown(const BuiltinArguments& args) { | 
 | 54 |     if (!args[1].empty()) { | 
 | 55 |         auto uid = DecodeUid(args[1]); | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 56 |         if (!uid.ok()) { | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 57 |             return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error(); | 
 | 58 |         } | 
 | 59 |     } | 
 | 60 |  | 
 | 61 |     // GID is optional and pushes the index of path out by one if specified. | 
 | 62 |     if (args.size() == 4 && !args[2].empty()) { | 
 | 63 |         auto gid = DecodeUid(args[2]); | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 64 |         if (!gid.ok()) { | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 65 |             return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error(); | 
 | 66 |         } | 
 | 67 |     } | 
 | 68 |  | 
 | 69 |     return {}; | 
 | 70 | } | 
 | 71 |  | 
 | 72 | Result<void> check_exec(const BuiltinArguments& args) { | 
 | 73 |     ReturnIfAnyArgsEmpty(); | 
 | 74 |  | 
 | 75 |     auto result = Service::MakeTemporaryOneshotService(args.args); | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 76 |     if (!result.ok()) { | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 77 |         return result.error(); | 
 | 78 |     } | 
 | 79 |  | 
 | 80 |     return {}; | 
 | 81 | } | 
 | 82 |  | 
 | 83 | Result<void> check_exec_background(const BuiltinArguments& args) { | 
 | 84 |     return check_exec(std::move(args)); | 
 | 85 | } | 
 | 86 |  | 
| Tom Cherry | 7896e7a | 2019-09-04 15:26:52 -0700 | [diff] [blame] | 87 | Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) { | 
 | 88 |     BuiltinArguments remaining_args(args.context); | 
 | 89 |  | 
 | 90 |     remaining_args.args = std::vector<std::string>(args.begin() + 1, args.end()); | 
 | 91 |     remaining_args.args[0] = args[0]; | 
 | 92 |  | 
 | 93 |     return check_exec(remaining_args); | 
 | 94 | } | 
 | 95 |  | 
| Daniel Norman | d2533c3 | 2019-08-02 15:13:50 -0700 | [diff] [blame] | 96 | Result<void> check_interface_restart(const BuiltinArguments& args) { | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 97 |     if (auto result = IsKnownInterface(args[1]); !result.ok()) { | 
| Daniel Norman | d2533c3 | 2019-08-02 15:13:50 -0700 | [diff] [blame] | 98 |         return result.error(); | 
 | 99 |     } | 
 | 100 |     return {}; | 
 | 101 | } | 
 | 102 |  | 
 | 103 | Result<void> check_interface_start(const BuiltinArguments& args) { | 
 | 104 |     return check_interface_restart(std::move(args)); | 
 | 105 | } | 
 | 106 |  | 
 | 107 | Result<void> check_interface_stop(const BuiltinArguments& args) { | 
 | 108 |     return check_interface_restart(std::move(args)); | 
 | 109 | } | 
 | 110 |  | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 111 | Result<void> check_load_system_props(const BuiltinArguments& args) { | 
 | 112 |     return Error() << "'load_system_props' is deprecated"; | 
 | 113 | } | 
 | 114 |  | 
 | 115 | Result<void> check_loglevel(const BuiltinArguments& args) { | 
 | 116 |     ReturnIfAnyArgsEmpty(); | 
 | 117 |  | 
 | 118 |     int log_level = -1; | 
 | 119 |     ParseInt(args[1], &log_level); | 
 | 120 |     if (log_level < 0 || log_level > 7) { | 
 | 121 |         return Error() << "loglevel must be in the range of 0-7"; | 
 | 122 |     } | 
 | 123 |     return {}; | 
 | 124 | } | 
 | 125 |  | 
| Alistair Delva | a2cc1eb | 2020-05-20 16:24:00 -0700 | [diff] [blame] | 126 | Result<void> check_mount_all(const BuiltinArguments& args) { | 
 | 127 |     auto options = ParseMountAll(args.args); | 
 | 128 |     if (!options.ok()) { | 
 | 129 |         return options.error(); | 
 | 130 |     } | 
 | 131 |     return {}; | 
 | 132 | } | 
 | 133 |  | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 134 | Result<void> check_mkdir(const BuiltinArguments& args) { | 
| Paul Crowley | 68258e8 | 2019-10-28 07:55:03 -0700 | [diff] [blame] | 135 |     auto options = ParseMkdir(args.args); | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 136 |     if (!options.ok()) { | 
| Paul Crowley | 68258e8 | 2019-10-28 07:55:03 -0700 | [diff] [blame] | 137 |         return options.error(); | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 138 |     } | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 139 |     return {}; | 
 | 140 | } | 
 | 141 |  | 
 | 142 | Result<void> check_restorecon(const BuiltinArguments& args) { | 
 | 143 |     ReturnIfAnyArgsEmpty(); | 
 | 144 |  | 
 | 145 |     auto restorecon_info = ParseRestorecon(args.args); | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 146 |     if (!restorecon_info.ok()) { | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 147 |         return restorecon_info.error(); | 
 | 148 |     } | 
 | 149 |  | 
 | 150 |     return {}; | 
 | 151 | } | 
 | 152 |  | 
 | 153 | Result<void> check_restorecon_recursive(const BuiltinArguments& args) { | 
 | 154 |     return check_restorecon(std::move(args)); | 
 | 155 | } | 
 | 156 |  | 
 | 157 | Result<void> check_setprop(const BuiltinArguments& args) { | 
 | 158 |     const std::string& name = args[1]; | 
 | 159 |     if (name.empty()) { | 
 | 160 |         return {}; | 
 | 161 |     } | 
 | 162 |     const std::string& value = args[2]; | 
 | 163 |  | 
 | 164 |     if (!IsLegalPropertyName(name)) { | 
 | 165 |         return Error() << "'" << name << "' is not a legal property name"; | 
 | 166 |     } | 
 | 167 |  | 
 | 168 |     if (!value.empty()) { | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 169 |         if (auto result = IsLegalPropertyValue(name, value); !result.ok()) { | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 170 |             return result.error(); | 
 | 171 |         } | 
 | 172 |     } | 
 | 173 |  | 
 | 174 |     if (StartsWith(name, "ctl.")) { | 
 | 175 |         return Error() | 
 | 176 |                << "Do not set ctl. properties from init; call the Service functions directly"; | 
 | 177 |     } | 
 | 178 |  | 
 | 179 |     static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive"; | 
 | 180 |     if (name == kRestoreconProperty) { | 
 | 181 |         return Error() << "Do not set '" << kRestoreconProperty | 
 | 182 |                        << "' from init; use the restorecon builtin directly"; | 
 | 183 |     } | 
 | 184 |  | 
| Tom Cherry | b5f2ec0 | 2019-11-08 17:54:27 -0800 | [diff] [blame] | 185 |     const char* target_context = nullptr; | 
 | 186 |     const char* type = nullptr; | 
 | 187 |     property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type); | 
 | 188 |  | 
 | 189 |     if (!CheckType(type, value)) { | 
 | 190 |         return Error() << "Property type check failed, value doesn't match expected type '" | 
 | 191 |                        << (type ?: "(null)") << "'"; | 
 | 192 |     } | 
 | 193 |  | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 194 |     return {}; | 
 | 195 | } | 
 | 196 |  | 
 | 197 | Result<void> check_setrlimit(const BuiltinArguments& args) { | 
 | 198 |     ReturnIfAnyArgsEmpty(); | 
 | 199 |  | 
 | 200 |     auto rlimit = ParseRlimit(args.args); | 
| Bernie Innocenti | cecebbb | 2020-02-06 03:49:33 +0900 | [diff] [blame] | 201 |     if (!rlimit.ok()) return rlimit.error(); | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 202 |     return {}; | 
 | 203 | } | 
 | 204 |  | 
| Alistair Delva | de28a86 | 2020-06-08 11:04:53 -0700 | [diff] [blame] | 205 | Result<void> check_swapon_all(const BuiltinArguments& args) { | 
 | 206 |     auto options = ParseSwaponAll(args.args); | 
 | 207 |     if (!options.ok()) { | 
 | 208 |         return options.error(); | 
 | 209 |     } | 
 | 210 |     return {}; | 
 | 211 | } | 
 | 212 |  | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 213 | Result<void> check_sysclktz(const BuiltinArguments& args) { | 
 | 214 |     ReturnIfAnyArgsEmpty(); | 
 | 215 |  | 
 | 216 |     struct timezone tz = {}; | 
 | 217 |     if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) { | 
 | 218 |         return Error() << "Unable to parse mins_west_of_gmt"; | 
 | 219 |     } | 
 | 220 |     return {}; | 
 | 221 | } | 
 | 222 |  | 
| Alistair Delva | a2cc1eb | 2020-05-20 16:24:00 -0700 | [diff] [blame] | 223 | Result<void> check_umount_all(const BuiltinArguments& args) { | 
 | 224 |     auto options = ParseUmountAll(args.args); | 
 | 225 |     if (!options.ok()) { | 
 | 226 |         return options.error(); | 
 | 227 |     } | 
 | 228 |     return {}; | 
 | 229 | } | 
 | 230 |  | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 231 | Result<void> check_wait(const BuiltinArguments& args) { | 
 | 232 |     if (args.size() == 3 && !args[2].empty()) { | 
| Mark Salyzyn | ffa52e9 | 2020-05-14 09:20:30 -0700 | [diff] [blame] | 233 |         double timeout_double; | 
 | 234 |         if (!android::base::ParseDouble(args[2], &timeout_double, 0)) { | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 235 |             return Error() << "failed to parse timeout"; | 
 | 236 |         } | 
 | 237 |     } | 
 | 238 |     return {}; | 
 | 239 | } | 
 | 240 |  | 
 | 241 | Result<void> check_wait_for_prop(const BuiltinArguments& args) { | 
 | 242 |     return check_setprop(std::move(args)); | 
 | 243 | } | 
 | 244 |  | 
 | 245 | }  // namespace init | 
 | 246 | }  // namespace android |