property_service.cpp revision db3f267c99411b10144998c6c1f1a6288d0191bc
1/* 2 * Copyright (C) 2007 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 <stdio.h> 18#include <stdlib.h> 19#include <unistd.h> 20#include <string.h> 21#include <ctype.h> 22#include <fcntl.h> 23#include <stdarg.h> 24#include <dirent.h> 25#include <limits.h> 26#include <errno.h> 27#include <sys/poll.h> 28 29#include <cutils/misc.h> 30#include <cutils/sockets.h> 31#include <cutils/multiuser.h> 32 33#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 34#include <sys/_system_properties.h> 35 36#include <sys/socket.h> 37#include <sys/un.h> 38#include <sys/select.h> 39#include <sys/types.h> 40#include <netinet/in.h> 41#include <sys/mman.h> 42#include <private/android_filesystem_config.h> 43 44#include <selinux/selinux.h> 45#include <selinux/label.h> 46 47#include "property_service.h" 48#include "init.h" 49#include "util.h" 50#include "log.h" 51 52#define PERSISTENT_PROPERTY_DIR "/data/property" 53 54static int persistent_properties_loaded = 0; 55static int property_area_inited = 0; 56 57static int property_set_fd = -1; 58 59struct workspace { 60 size_t size; 61 int fd; 62}; 63 64static int init_workspace(workspace *w, size_t size) 65{ 66 int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); 67 if (fd < 0) 68 return -1; 69 70 w->size = size; 71 w->fd = fd; 72 return 0; 73} 74 75static workspace pa_workspace; 76 77static int init_property_area(void) 78{ 79 if (property_area_inited) 80 return -1; 81 82 if(__system_property_area_init()) 83 return -1; 84 85 if(init_workspace(&pa_workspace, 0)) 86 return -1; 87 88 fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC); 89 90 property_area_inited = 1; 91 return 0; 92} 93 94static int check_mac_perms(const char *name, char *sctx) 95{ 96 if (is_selinux_enabled() <= 0) 97 return 1; 98 99 char *tctx = NULL; 100 int result = 0; 101 102 if (!sctx) 103 goto err; 104 105 if (!sehandle_prop) 106 goto err; 107 108 if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0) 109 goto err; 110 111 if (selinux_check_access(sctx, tctx, "property_service", "set", (void*) name) == 0) 112 result = 1; 113 114 freecon(tctx); 115 err: 116 return result; 117} 118 119static int check_control_mac_perms(const char *name, char *sctx) 120{ 121 /* 122 * Create a name prefix out of ctl.<service name> 123 * The new prefix allows the use of the existing 124 * property service backend labeling while avoiding 125 * mislabels based on true property prefixes. 126 */ 127 char ctl_name[PROP_VALUE_MAX+4]; 128 int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name); 129 130 if (ret < 0 || (size_t) ret >= sizeof(ctl_name)) 131 return 0; 132 133 return check_mac_perms(ctl_name, sctx); 134} 135 136/* 137 * Checks permissions for setting system properties. 138 * Returns 1 if uid allowed, 0 otherwise. 139 */ 140static int check_perms(const char *name, char *sctx) 141{ 142 if(!strncmp(name, "ro.", 3)) 143 name +=3; 144 145 return check_mac_perms(name, sctx); 146} 147 148int __property_get(const char *name, char *value) 149{ 150 return __system_property_get(name, value); 151} 152 153static void write_persistent_property(const char *name, const char *value) 154{ 155 char tempPath[PATH_MAX]; 156 char path[PATH_MAX]; 157 int fd; 158 159 snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR); 160 fd = mkstemp(tempPath); 161 if (fd < 0) { 162 ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno); 163 return; 164 } 165 write(fd, value, strlen(value)); 166 fsync(fd); 167 close(fd); 168 169 snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name); 170 if (rename(tempPath, path)) { 171 unlink(tempPath); 172 ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path); 173 } 174} 175 176static bool is_legal_property_name(const char* name, size_t namelen) 177{ 178 size_t i; 179 if (namelen >= PROP_NAME_MAX) return false; 180 if (namelen < 1) return false; 181 if (name[0] == '.') return false; 182 if (name[namelen - 1] == '.') return false; 183 184 /* Only allow alphanumeric, plus '.', '-', or '_' */ 185 /* Don't allow ".." to appear in a property name */ 186 for (i = 0; i < namelen; i++) { 187 if (name[i] == '.') { 188 // i=0 is guaranteed to never have a dot. See above. 189 if (name[i-1] == '.') return false; 190 continue; 191 } 192 if (name[i] == '_' || name[i] == '-') continue; 193 if (name[i] >= 'a' && name[i] <= 'z') continue; 194 if (name[i] >= 'A' && name[i] <= 'Z') continue; 195 if (name[i] >= '0' && name[i] <= '9') continue; 196 return false; 197 } 198 199 return true; 200} 201 202static int property_set_impl(const char* name, const char* value) { 203 size_t namelen = strlen(name); 204 size_t valuelen = strlen(value); 205 206 if (!is_legal_property_name(name, namelen)) return -1; 207 if (valuelen >= PROP_VALUE_MAX) return -1; 208 209 prop_info* pi = (prop_info*) __system_property_find(name); 210 211 if(pi != 0) { 212 /* ro.* properties may NEVER be modified once set */ 213 if(!strncmp(name, "ro.", 3)) return -1; 214 215 __system_property_update(pi, value, valuelen); 216 } else { 217 int rc = __system_property_add(name, namelen, value, valuelen); 218 if (rc < 0) { 219 return rc; 220 } 221 } 222 /* If name starts with "net." treat as a DNS property. */ 223 if (strncmp("net.", name, strlen("net.")) == 0) { 224 if (strcmp("net.change", name) == 0) { 225 return 0; 226 } 227 /* 228 * The 'net.change' property is a special property used track when any 229 * 'net.*' property name is updated. It is _ONLY_ updated here. Its value 230 * contains the last updated 'net.*' property. 231 */ 232 property_set("net.change", name); 233 } else if (persistent_properties_loaded && 234 strncmp("persist.", name, strlen("persist.")) == 0) { 235 /* 236 * Don't write properties to disk until after we have read all default properties 237 * to prevent them from being overwritten by default values. 238 */ 239 write_persistent_property(name, value); 240 } else if (strcmp("selinux.reload_policy", name) == 0 && 241 strcmp("1", value) == 0) { 242 selinux_reload_policy(); 243 } 244 property_changed(name, value); 245 return 0; 246} 247 248int property_set(const char* name, const char* value) { 249 int rc = property_set_impl(name, value); 250 if (rc == -1) { 251 ERROR("property_set(\"%s\", \"%s\" failed\n", name, value); 252 } 253 return rc; 254} 255 256void handle_property_set_fd() 257{ 258 prop_msg msg; 259 int s; 260 int r; 261 struct ucred cr; 262 struct sockaddr_un addr; 263 socklen_t addr_size = sizeof(addr); 264 socklen_t cr_size = sizeof(cr); 265 char * source_ctx = NULL; 266 struct pollfd ufds[1]; 267 const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */ 268 int nr; 269 270 if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) { 271 return; 272 } 273 274 /* Check socket options here */ 275 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { 276 close(s); 277 ERROR("Unable to receive socket options\n"); 278 return; 279 } 280 281 ufds[0].fd = s; 282 ufds[0].events = POLLIN; 283 ufds[0].revents = 0; 284 nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms)); 285 if (nr == 0) { 286 ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid); 287 close(s); 288 return; 289 } else if (nr < 0) { 290 ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno)); 291 close(s); 292 return; 293 } 294 295 r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT)); 296 if(r != sizeof(prop_msg)) { 297 ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n", 298 r, sizeof(prop_msg), errno); 299 close(s); 300 return; 301 } 302 303 switch(msg.cmd) { 304 case PROP_MSG_SETPROP: 305 msg.name[PROP_NAME_MAX-1] = 0; 306 msg.value[PROP_VALUE_MAX-1] = 0; 307 308 if (!is_legal_property_name(msg.name, strlen(msg.name))) { 309 ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name); 310 close(s); 311 return; 312 } 313 314 getpeercon(s, &source_ctx); 315 316 if(memcmp(msg.name,"ctl.",4) == 0) { 317 // Keep the old close-socket-early behavior when handling 318 // ctl.* properties. 319 close(s); 320 if (check_control_mac_perms(msg.value, source_ctx)) { 321 handle_control_message((char*) msg.name + 4, (char*) msg.value); 322 } else { 323 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n", 324 msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid); 325 } 326 } else { 327 if (check_perms(msg.name, source_ctx)) { 328 property_set((char*) msg.name, (char*) msg.value); 329 } else { 330 ERROR("sys_prop: permission denied uid:%d name:%s\n", 331 cr.uid, msg.name); 332 } 333 334 // Note: bionic's property client code assumes that the 335 // property server will not close the socket until *AFTER* 336 // the property is written to memory. 337 close(s); 338 } 339 freecon(source_ctx); 340 break; 341 342 default: 343 close(s); 344 break; 345 } 346} 347 348void get_property_workspace(int *fd, int *sz) 349{ 350 *fd = pa_workspace.fd; 351 *sz = pa_workspace.size; 352} 353 354static void load_properties_from_file(const char *, const char *); 355 356/* 357 * Filter is used to decide which properties to load: NULL loads all keys, 358 * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. 359 */ 360static void load_properties(char *data, const char *filter) 361{ 362 char *key, *value, *eol, *sol, *tmp, *fn; 363 size_t flen = 0; 364 365 if (filter) { 366 flen = strlen(filter); 367 } 368 369 sol = data; 370 while ((eol = strchr(sol, '\n'))) { 371 key = sol; 372 *eol++ = 0; 373 sol = eol; 374 375 while (isspace(*key)) key++; 376 if (*key == '#') continue; 377 378 tmp = eol - 2; 379 while ((tmp > key) && isspace(*tmp)) *tmp-- = 0; 380 381 if (!strncmp(key, "import ", 7) && flen == 0) { 382 fn = key + 7; 383 while (isspace(*fn)) fn++; 384 385 key = strchr(fn, ' '); 386 if (key) { 387 *key++ = 0; 388 while (isspace(*key)) key++; 389 } 390 391 load_properties_from_file(fn, key); 392 393 } else { 394 value = strchr(key, '='); 395 if (!value) continue; 396 *value++ = 0; 397 398 tmp = value - 2; 399 while ((tmp > key) && isspace(*tmp)) *tmp-- = 0; 400 401 while (isspace(*value)) value++; 402 403 if (flen > 0) { 404 if (filter[flen - 1] == '*') { 405 if (strncmp(key, filter, flen - 1)) continue; 406 } else { 407 if (strcmp(key, filter)) continue; 408 } 409 } 410 411 property_set(key, value); 412 } 413 } 414} 415 416/* 417 * Filter is used to decide which properties to load: NULL loads all keys, 418 * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. 419 */ 420static void load_properties_from_file(const char *fn, const char *filter) 421{ 422 std::string data; 423 if (read_file(fn, &data)) { 424 load_properties(&data[0], filter); 425 } 426} 427 428static void load_persistent_properties() 429{ 430 DIR* dir = opendir(PERSISTENT_PROPERTY_DIR); 431 int dir_fd; 432 struct dirent* entry; 433 char value[PROP_VALUE_MAX]; 434 int fd, length; 435 struct stat sb; 436 437 if (dir) { 438 dir_fd = dirfd(dir); 439 while ((entry = readdir(dir)) != NULL) { 440 if (strncmp("persist.", entry->d_name, strlen("persist."))) 441 continue; 442 if (entry->d_type != DT_REG) 443 continue; 444 /* open the file and read the property value */ 445 fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW); 446 if (fd < 0) { 447 ERROR("Unable to open persistent property file \"%s\" errno: %d\n", 448 entry->d_name, errno); 449 continue; 450 } 451 if (fstat(fd, &sb) < 0) { 452 ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno); 453 close(fd); 454 continue; 455 } 456 457 // File must not be accessible to others, be owned by root/root, and 458 // not be a hard link to any other file. 459 if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) 460 || (sb.st_uid != 0) 461 || (sb.st_gid != 0) 462 || (sb.st_nlink != 1)) { 463 ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n", 464 entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid, 465 (unsigned int)sb.st_nlink, sb.st_mode); 466 close(fd); 467 continue; 468 } 469 470 length = read(fd, value, sizeof(value) - 1); 471 if (length >= 0) { 472 value[length] = 0; 473 property_set(entry->d_name, value); 474 } else { 475 ERROR("Unable to read persistent property file %s errno: %d\n", 476 entry->d_name, errno); 477 } 478 close(fd); 479 } 480 closedir(dir); 481 } else { 482 ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno); 483 } 484 485 persistent_properties_loaded = 1; 486} 487 488void property_init(void) 489{ 490 init_property_area(); 491} 492 493void property_load_boot_defaults(void) 494{ 495 load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL); 496} 497 498int properties_inited(void) 499{ 500 return property_area_inited; 501} 502 503static void load_override_properties() { 504 if (ALLOW_LOCAL_PROP_OVERRIDE) { 505 char debuggable[PROP_VALUE_MAX]; 506 int ret = property_get("ro.debuggable", debuggable); 507 if (ret && (strcmp(debuggable, "1") == 0)) { 508 load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL); 509 } 510 } 511} 512 513 514/* When booting an encrypted system, /data is not mounted when the 515 * property service is started, so any properties stored there are 516 * not loaded. Vold triggers init to load these properties once it 517 * has mounted /data. 518 */ 519void load_persist_props(void) 520{ 521 load_override_properties(); 522 /* Read persistent properties after all default values have been loaded. */ 523 load_persistent_properties(); 524} 525 526void load_all_props(void) 527{ 528 load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); 529 load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); 530 load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL); 531 load_properties_from_file(PROP_PATH_BOOTIMAGE_BUILD, NULL); 532 load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); 533 534 load_override_properties(); 535 536 /* Read persistent properties after all default values have been loaded. */ 537 load_persistent_properties(); 538} 539 540void start_property_service(void) 541{ 542 int fd; 543 544 fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL); 545 if(fd < 0) return; 546 fcntl(fd, F_SETFD, FD_CLOEXEC); 547 fcntl(fd, F_SETFL, O_NONBLOCK); 548 549 listen(fd, 8); 550 property_set_fd = fd; 551} 552 553int get_property_set_fd() 554{ 555 return property_set_fd; 556} 557