summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Cherry2018-03-01 16:54:24 -0600
committerGerrit Code Review2018-03-01 16:54:24 -0600
commitfe6cc42de4bdc754483e14f683e7d3640a34e405 (patch)
tree5b19ebe0da3968ffc52f5a587d9b437d6c225d4c
parent10f62351eb35ed9a6df09a010ef588504d5f9290 (diff)
parent69d47aa829fa5a48baeadeff0e04d03e58f147b7 (diff)
downloadplatform-system-core-fe6cc42de4bdc754483e14f683e7d3640a34e405.tar.gz
platform-system-core-fe6cc42de4bdc754483e14f683e7d3640a34e405.tar.xz
platform-system-core-fe6cc42de4bdc754483e14f683e7d3640a34e405.zip
Merge "Clean up property set error handling"
-rw-r--r--init/host_init_stubs.cpp4
-rw-r--r--init/host_init_stubs.h2
-rw-r--r--init/property_service.cpp97
-rw-r--r--init/property_service.h2
-rw-r--r--init/subcontext.cpp6
5 files changed, 64 insertions, 47 deletions
diff --git a/init/host_init_stubs.cpp b/init/host_init_stubs.cpp
index cde747de0..e6cc08a9a 100644
--- a/init/host_init_stubs.cpp
+++ b/init/host_init_stubs.cpp
@@ -43,8 +43,8 @@ std::string default_console = "/dev/console";
43 43
44// property_service.h 44// property_service.h
45uint32_t (*property_set)(const std::string& name, const std::string& value) = nullptr; 45uint32_t (*property_set)(const std::string& name, const std::string& value) = nullptr;
46uint32_t HandlePropertySet(const std::string&, const std::string&, const std::string&, 46uint32_t HandlePropertySet(const std::string&, const std::string&, const std::string&, const ucred&,
47 const ucred&) { 47 std::string*) {
48 return 0; 48 return 0;
49} 49}
50 50
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index af96aea15..f31ece60c 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -48,7 +48,7 @@ extern std::string default_console;
48// property_service.h 48// property_service.h
49extern uint32_t (*property_set)(const std::string& name, const std::string& value); 49extern uint32_t (*property_set)(const std::string& name, const std::string& value);
50uint32_t HandlePropertySet(const std::string& name, const std::string& value, 50uint32_t HandlePropertySet(const std::string& name, const std::string& value,
51 const std::string& source_context, const ucred& cr); 51 const std::string& source_context, const ucred& cr, std::string* error);
52 52
53// selinux.h 53// selinux.h
54void SelabelInitialize(); 54void SelabelInitialize();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 338c05aec..624780f64 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -117,23 +117,21 @@ static bool CheckMacPerms(const std::string& name, const char* target_context,
117 return has_access; 117 return has_access;
118} 118}
119 119
120static uint32_t PropertySetImpl(const std::string& name, const std::string& value) { 120static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
121 size_t valuelen = value.size(); 121 size_t valuelen = value.size();
122 122
123 if (!IsLegalPropertyName(name)) { 123 if (!IsLegalPropertyName(name)) {
124 LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name"; 124 *error = "Illegal property name";
125 return PROP_ERROR_INVALID_NAME; 125 return PROP_ERROR_INVALID_NAME;
126 } 126 }
127 127
128 if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) { 128 if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
129 LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " 129 *error = "Property value too long";
130 << "value too long";
131 return PROP_ERROR_INVALID_VALUE; 130 return PROP_ERROR_INVALID_VALUE;
132 } 131 }
133 132
134 if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) { 133 if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
135 LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " 134 *error = "Value is not a UTF8 encoded string";
136 << "value not a UTF8 encoded string";
137 return PROP_ERROR_INVALID_VALUE; 135 return PROP_ERROR_INVALID_VALUE;
138 } 136 }
139 137
@@ -141,8 +139,7 @@ static uint32_t PropertySetImpl(const std::string& name, const std::string& valu
141 if (pi != nullptr) { 139 if (pi != nullptr) {
142 // ro.* properties are actually "write-once". 140 // ro.* properties are actually "write-once".
143 if (StartsWith(name, "ro.")) { 141 if (StartsWith(name, "ro.")) {
144 LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " 142 *error = "Read-only property was already set";
145 << "property already set";
146 return PROP_ERROR_READ_ONLY_PROPERTY; 143 return PROP_ERROR_READ_ONLY_PROPERTY;
147 } 144 }
148 145
@@ -150,8 +147,7 @@ static uint32_t PropertySetImpl(const std::string& name, const std::string& valu
150 } else { 147 } else {
151 int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); 148 int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
152 if (rc < 0) { 149 if (rc < 0) {
153 LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " 150 *error = "__system_property_add failed";
154 << "__system_property_add failed";
155 return PROP_ERROR_SET_FAILED; 151 return PROP_ERROR_SET_FAILED;
156 } 152 }
157 } 153 }
@@ -205,8 +201,10 @@ bool PropertyChildReap(pid_t pid) {
205 if (info.pid != pid) { 201 if (info.pid != pid) {
206 return false; 202 return false;
207 } 203 }
208 if (PropertySetImpl(info.name, info.value) != PROP_SUCCESS) { 204 std::string error;
209 LOG(ERROR) << "Failed to set async property " << info.name; 205 if (PropertySet(info.name, info.value, &error) != PROP_SUCCESS) {
206 LOG(ERROR) << "Failed to set async property " << info.name << " to " << info.value << ": "
207 << error;
210 } 208 }
211 property_children.pop(); 209 property_children.pop();
212 if (!property_children.empty()) { 210 if (!property_children.empty()) {
@@ -216,9 +214,9 @@ bool PropertyChildReap(pid_t pid) {
216} 214}
217 215
218static uint32_t PropertySetAsync(const std::string& name, const std::string& value, 216static uint32_t PropertySetAsync(const std::string& name, const std::string& value,
219 PropertyAsyncFunc func) { 217 PropertyAsyncFunc func, std::string* error) {
220 if (value.empty()) { 218 if (value.empty()) {
221 return PropertySetImpl(name, value); 219 return PropertySet(name, value, error);
222 } 220 }
223 221
224 PropertyChildInfo info; 222 PropertyChildInfo info;
@@ -236,30 +234,27 @@ static int RestoreconRecursiveAsync(const std::string& name, const std::string&
236 return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE); 234 return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
237} 235}
238 236
239uint32_t PropertySet(const std::string& name, const std::string& value) {
240 if (name == "selinux.restorecon_recursive") {
241 return PropertySetAsync(name, value, RestoreconRecursiveAsync);
242 }
243
244 return PropertySetImpl(name, value);
245}
246
247uint32_t InitPropertySet(const std::string& name, const std::string& value) { 237uint32_t InitPropertySet(const std::string& name, const std::string& value) {
248 if (StartsWith(name, "ctl.")) { 238 if (StartsWith(name, "ctl.")) {
249 LOG(ERROR) << "Do not set ctl. properties from init; call the Service functions directly"; 239 LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
240 "functions directly";
241 return PROP_ERROR_INVALID_NAME;
242 }
243 if (name == "selinux.restorecon_recursive") {
244 LOG(ERROR) << "InitPropertySet: Do not set selinux.restorecon_recursive from init; use the "
245 "restorecon builtin directly";
250 return PROP_ERROR_INVALID_NAME; 246 return PROP_ERROR_INVALID_NAME;
251 } 247 }
252 248
253 const char* type = nullptr; 249 uint32_t result = 0;
254 property_info_area->GetPropertyInfo(name.c_str(), nullptr, &type); 250 ucred cr = {.pid = 1, .uid = 0, .gid = 0};
255 251 std::string error;
256 if (type == nullptr || !CheckType(type, value)) { 252 result = HandlePropertySet(name, value, kInitContext.c_str(), cr, &error);
257 LOG(ERROR) << "property_set: name: '" << name << "' type check failed, type: '" 253 if (result != PROP_SUCCESS) {
258 << (type ?: "(null)") << "' value: '" << value << "'"; 254 LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
259 return PROP_ERROR_INVALID_VALUE;
260 } 255 }
261 256
262 return PropertySet(name, value); 257 return result;
263} 258}
264 259
265class SocketConnection { 260class SocketConnection {
@@ -390,9 +385,9 @@ class SocketConnection {
390 385
391// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*. 386// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
392uint32_t HandlePropertySet(const std::string& name, const std::string& value, 387uint32_t HandlePropertySet(const std::string& name, const std::string& value,
393 const std::string& source_context, const ucred& cr) { 388 const std::string& source_context, const ucred& cr, std::string* error) {
394 if (!IsLegalPropertyName(name)) { 389 if (!IsLegalPropertyName(name)) {
395 LOG(ERROR) << "PropertySet: illegal property name \"" << name << "\""; 390 *error = "Illegal property name";
396 return PROP_ERROR_INVALID_NAME; 391 return PROP_ERROR_INVALID_NAME;
397 } 392 }
398 393
@@ -405,9 +400,7 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
405 const char* type = nullptr; 400 const char* type = nullptr;
406 property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type); 401 property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
407 if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) { 402 if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) {
408 LOG(ERROR) << "PropertySet: Unable to " << (name.c_str() + 4) << " service ctl [" 403 *error = StringPrintf("Unable to '%s' service %s", name.c_str() + 4, value.c_str());
409 << value << "]"
410 << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
411 return PROP_ERROR_HANDLE_CONTROL_MESSAGE; 404 return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
412 } 405 }
413 406
@@ -420,13 +413,13 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
420 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type); 413 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
421 414
422 if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) { 415 if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
423 LOG(ERROR) << "PropertySet: permission denied uid:" << cr.uid << " name:" << name; 416 *error = "SELinux permission check failed";
424 return PROP_ERROR_PERMISSION_DENIED; 417 return PROP_ERROR_PERMISSION_DENIED;
425 } 418 }
426 419
427 if (type == nullptr || !CheckType(type, value)) { 420 if (type == nullptr || !CheckType(type, value)) {
428 LOG(ERROR) << "PropertySet: name: '" << name << "' type check failed, type: '" 421 *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
429 << (type ?: "(null)") << "' value: '" << value << "'"; 422 (type ?: "(null)"));
430 return PROP_ERROR_INVALID_VALUE; 423 return PROP_ERROR_INVALID_VALUE;
431 } 424 }
432 425
@@ -445,7 +438,11 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
445 << process_log_string; 438 << process_log_string;
446 } 439 }
447 440
448 return PropertySet(name, value); 441 if (name == "selinux.restorecon_recursive") {
442 return PropertySetAsync(name, value, RestoreconRecursiveAsync, error);
443 }
444
445 return PropertySet(name, value, error);
449} 446}
450 447
451static void handle_property_set_fd() { 448static void handle_property_set_fd() {
@@ -488,7 +485,16 @@ static void handle_property_set_fd() {
488 prop_name[PROP_NAME_MAX-1] = 0; 485 prop_name[PROP_NAME_MAX-1] = 0;
489 prop_value[PROP_VALUE_MAX-1] = 0; 486 prop_value[PROP_VALUE_MAX-1] = 0;
490 487
491 HandlePropertySet(prop_value, prop_value, socket.source_context(), socket.cred()); 488 const auto& cr = socket.cred();
489 std::string error;
490 uint32_t result =
491 HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
492 if (result != PROP_SUCCESS) {
493 LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
494 << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
495 << error;
496 }
497
492 break; 498 break;
493 } 499 }
494 500
@@ -502,7 +508,14 @@ static void handle_property_set_fd() {
502 return; 508 return;
503 } 509 }
504 510
505 auto result = HandlePropertySet(name, value, socket.source_context(), socket.cred()); 511 const auto& cr = socket.cred();
512 std::string error;
513 uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
514 if (result != PROP_SUCCESS) {
515 LOG(ERROR) << "Unable to set property '" << name << "' to '" << value
516 << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
517 << error;
518 }
506 socket.SendUint32(result); 519 socket.SendUint32(result);
507 break; 520 break;
508 } 521 }
diff --git a/init/property_service.h b/init/property_service.h
index d4973fc89..29eaaa901 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,7 +32,7 @@ struct property_audit_data {
32extern uint32_t (*property_set)(const std::string& name, const std::string& value); 32extern uint32_t (*property_set)(const std::string& name, const std::string& value);
33 33
34uint32_t HandlePropertySet(const std::string& name, const std::string& value, 34uint32_t HandlePropertySet(const std::string& name, const std::string& value,
35 const std::string& source_context, const ucred& cr); 35 const std::string& source_context, const ucred& cr, std::string* error);
36 36
37extern bool PropertyChildReap(pid_t pid); 37extern bool PropertyChildReap(pid_t pid);
38 38
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index faab36848..762492c87 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -297,7 +297,11 @@ Result<Success> Subcontext::Execute(const std::vector<std::string>& args) {
297 297
298 for (const auto& property : subcontext_reply->properties_to_set()) { 298 for (const auto& property : subcontext_reply->properties_to_set()) {
299 ucred cr = {.pid = pid_, .uid = 0, .gid = 0}; 299 ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
300 HandlePropertySet(property.name(), property.value(), context_, cr); 300 std::string error;
301 if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) {
302 LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '"
303 << property.value() << "': " << error;
304 }
301 } 305 }
302 306
303 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { 307 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {