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