| 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> | 
|  | 28 | #include <android-base/parseint.h> | 
|  | 29 | #include <android-base/strings.h> | 
|  | 30 |  | 
|  | 31 | #include "builtin_arguments.h" | 
| Daniel Norman | d2533c3 | 2019-08-02 15:13:50 -0700 | [diff] [blame] | 32 | #include "interface_utils.h" | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 33 | #include "rlimit_parser.h" | 
|  | 34 | #include "service.h" | 
|  | 35 | #include "util.h" | 
|  | 36 |  | 
|  | 37 | using android::base::ParseInt; | 
|  | 38 | using android::base::StartsWith; | 
|  | 39 |  | 
|  | 40 | #define ReturnIfAnyArgsEmpty()     \ | 
|  | 41 | for (const auto& arg : args) { \ | 
|  | 42 | if (arg.empty()) {         \ | 
|  | 43 | return {};             \ | 
|  | 44 | }                          \ | 
|  | 45 | } | 
|  | 46 |  | 
|  | 47 | namespace android { | 
|  | 48 | namespace init { | 
|  | 49 |  | 
|  | 50 | Result<void> check_chown(const BuiltinArguments& args) { | 
|  | 51 | if (!args[1].empty()) { | 
|  | 52 | auto uid = DecodeUid(args[1]); | 
|  | 53 | if (!uid) { | 
|  | 54 | return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error(); | 
|  | 55 | } | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | // GID is optional and pushes the index of path out by one if specified. | 
|  | 59 | if (args.size() == 4 && !args[2].empty()) { | 
|  | 60 | auto gid = DecodeUid(args[2]); | 
|  | 61 | if (!gid) { | 
|  | 62 | return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error(); | 
|  | 63 | } | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | return {}; | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | Result<void> check_exec(const BuiltinArguments& args) { | 
|  | 70 | ReturnIfAnyArgsEmpty(); | 
|  | 71 |  | 
|  | 72 | auto result = Service::MakeTemporaryOneshotService(args.args); | 
|  | 73 | if (!result) { | 
|  | 74 | return result.error(); | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | return {}; | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | Result<void> check_exec_background(const BuiltinArguments& args) { | 
|  | 81 | return check_exec(std::move(args)); | 
|  | 82 | } | 
|  | 83 |  | 
| Tom Cherry | 7896e7a | 2019-09-04 15:26:52 -0700 | [diff] [blame] | 84 | Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) { | 
|  | 85 | BuiltinArguments remaining_args(args.context); | 
|  | 86 |  | 
|  | 87 | remaining_args.args = std::vector<std::string>(args.begin() + 1, args.end()); | 
|  | 88 | remaining_args.args[0] = args[0]; | 
|  | 89 |  | 
|  | 90 | return check_exec(remaining_args); | 
|  | 91 | } | 
|  | 92 |  | 
| Daniel Norman | d2533c3 | 2019-08-02 15:13:50 -0700 | [diff] [blame] | 93 | Result<void> check_interface_restart(const BuiltinArguments& args) { | 
|  | 94 | if (auto result = IsKnownInterface(args[1]); !result) { | 
|  | 95 | return result.error(); | 
|  | 96 | } | 
|  | 97 | return {}; | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | Result<void> check_interface_start(const BuiltinArguments& args) { | 
|  | 101 | return check_interface_restart(std::move(args)); | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | Result<void> check_interface_stop(const BuiltinArguments& args) { | 
|  | 105 | return check_interface_restart(std::move(args)); | 
|  | 106 | } | 
|  | 107 |  | 
| Tom Cherry | 4772f1d | 2019-07-30 09:34:41 -0700 | [diff] [blame] | 108 | Result<void> check_load_system_props(const BuiltinArguments& args) { | 
|  | 109 | return Error() << "'load_system_props' is deprecated"; | 
|  | 110 | } | 
|  | 111 |  | 
|  | 112 | Result<void> check_loglevel(const BuiltinArguments& args) { | 
|  | 113 | ReturnIfAnyArgsEmpty(); | 
|  | 114 |  | 
|  | 115 | int log_level = -1; | 
|  | 116 | ParseInt(args[1], &log_level); | 
|  | 117 | if (log_level < 0 || log_level > 7) { | 
|  | 118 | return Error() << "loglevel must be in the range of 0-7"; | 
|  | 119 | } | 
|  | 120 | return {}; | 
|  | 121 | } | 
|  | 122 |  | 
|  | 123 | 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 | } | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 | return {}; | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 | Result<void> check_restorecon(const BuiltinArguments& args) { | 
|  | 144 | ReturnIfAnyArgsEmpty(); | 
|  | 145 |  | 
|  | 146 | auto restorecon_info = ParseRestorecon(args.args); | 
|  | 147 | if (!restorecon_info) { | 
|  | 148 | return restorecon_info.error(); | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | return {}; | 
|  | 152 | } | 
|  | 153 |  | 
|  | 154 | Result<void> check_restorecon_recursive(const BuiltinArguments& args) { | 
|  | 155 | return check_restorecon(std::move(args)); | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | Result<void> check_setprop(const BuiltinArguments& args) { | 
|  | 159 | const std::string& name = args[1]; | 
|  | 160 | if (name.empty()) { | 
|  | 161 | return {}; | 
|  | 162 | } | 
|  | 163 | const std::string& value = args[2]; | 
|  | 164 |  | 
|  | 165 | if (!IsLegalPropertyName(name)) { | 
|  | 166 | return Error() << "'" << name << "' is not a legal property name"; | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | if (!value.empty()) { | 
|  | 170 | if (auto result = IsLegalPropertyValue(name, value); !result) { | 
|  | 171 | return result.error(); | 
|  | 172 | } | 
|  | 173 | } | 
|  | 174 |  | 
|  | 175 | if (StartsWith(name, "ctl.")) { | 
|  | 176 | return Error() | 
|  | 177 | << "Do not set ctl. properties from init; call the Service functions directly"; | 
|  | 178 | } | 
|  | 179 |  | 
|  | 180 | static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive"; | 
|  | 181 | if (name == kRestoreconProperty) { | 
|  | 182 | return Error() << "Do not set '" << kRestoreconProperty | 
|  | 183 | << "' from init; use the restorecon builtin directly"; | 
|  | 184 | } | 
|  | 185 |  | 
|  | 186 | return {}; | 
|  | 187 | } | 
|  | 188 |  | 
|  | 189 | Result<void> check_setrlimit(const BuiltinArguments& args) { | 
|  | 190 | ReturnIfAnyArgsEmpty(); | 
|  | 191 |  | 
|  | 192 | auto rlimit = ParseRlimit(args.args); | 
|  | 193 | if (!rlimit) return rlimit.error(); | 
|  | 194 | return {}; | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | Result<void> check_sysclktz(const BuiltinArguments& args) { | 
|  | 198 | ReturnIfAnyArgsEmpty(); | 
|  | 199 |  | 
|  | 200 | struct timezone tz = {}; | 
|  | 201 | if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) { | 
|  | 202 | return Error() << "Unable to parse mins_west_of_gmt"; | 
|  | 203 | } | 
|  | 204 | return {}; | 
|  | 205 | } | 
|  | 206 |  | 
|  | 207 | Result<void> check_wait(const BuiltinArguments& args) { | 
|  | 208 | if (args.size() == 3 && !args[2].empty()) { | 
|  | 209 | int timeout_int; | 
|  | 210 | if (!android::base::ParseInt(args[2], &timeout_int)) { | 
|  | 211 | return Error() << "failed to parse timeout"; | 
|  | 212 | } | 
|  | 213 | } | 
|  | 214 | return {}; | 
|  | 215 | } | 
|  | 216 |  | 
|  | 217 | Result<void> check_wait_for_prop(const BuiltinArguments& args) { | 
|  | 218 | return check_setprop(std::move(args)); | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 | }  // namespace init | 
|  | 222 | }  // namespace android |