property_service.cpp revision 98ff77204cef9bb8f0f27420833233622060a09e
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 202int property_set(const char *name, const char *value) 203{ 204 prop_info *pi; 205 int ret; 206 207 size_t namelen = strlen(name); 208 size_t valuelen = strlen(value); 209 210 if (!is_legal_property_name(name, namelen)) return -1; 211 if (valuelen >= PROP_VALUE_MAX) return -1; 212 213 pi = (prop_info*) __system_property_find(name); 214 215 if(pi != 0) { 216 /* ro.* properties may NEVER be modified once set */ 217 if(!strncmp(name, "ro.", 3)) return -1; 218 219 __system_property_update(pi, value, valuelen); 220 } else { 221 ret = __system_property_add(name, namelen, value, valuelen); 222 if (ret < 0) { 223 ERROR("Failed to set '%s'='%s'\n", name, value); 224 return ret; 225 } 226 } 227 /* If name starts with "net." treat as a DNS property. */ 228 if (strncmp("net.", name, strlen("net.")) == 0) { 229 if (strcmp("net.change", name) == 0) { 230 return 0; 231 } 232 /* 233 * The 'net.change' property is a special property used track when any 234 * 'net.*' property name is updated. It is _ONLY_ updated here. Its value 235 * contains the last updated 'net.*' property. 236 */ 237 property_set("net.change", name); 238 } else if (persistent_properties_loaded && 239 strncmp("persist.", name, strlen("persist.")) == 0) { 240 /* 241 * Don't write properties to disk until after we have read all default properties 242 * to prevent them from being overwritten by default values. 243 */ 244 write_persistent_property(name, value); 245 } else if (strcmp("selinux.reload_policy", name) == 0 && 246 strcmp("1", value) == 0) { 247 selinux_reload_policy(); 248 } 249 property_changed(name, value); 250 return 0; 251} 252 253void handle_property_set_fd() 254{ 255 prop_msg msg; 256 int s; 257 int r; 258 struct ucred cr; 259 struct sockaddr_un addr; 260 socklen_t addr_size = sizeof(addr); 261 socklen_t cr_size = sizeof(cr); 262 char * source_ctx = NULL; 263 struct pollfd ufds[1]; 264 const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */ 265 int nr; 266 267 if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) { 268 return; 269 } 270 271 /* Check socket options here */ 272 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { 273 close(s); 274 ERROR("Unable to receive socket options\n"); 275 return; 276 } 277 278 ufds[0].fd = s; 279 ufds[0].events = POLLIN; 280 ufds[0].revents = 0; 281 nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms)); 282 if (nr == 0) { 283 ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid); 284 close(s); 285 return; 286 } else if (nr < 0) { 287 ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno)); 288 close(s); 289 return; 290 } 291 292 r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT)); 293 if(r != sizeof(prop_msg)) { 294 ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n", 295 r, sizeof(prop_msg), errno); 296 close(s); 297 return; 298 } 299 300 switch(msg.cmd) { 301 case PROP_MSG_SETPROP: 302 msg.name[PROP_NAME_MAX-1] = 0; 303 msg.value[PROP_VALUE_MAX-1] = 0; 304 305 if (!is_legal_property_name(msg.name, strlen(msg.name))) { 306 ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name); 307 close(s); 308 return; 309 } 310 311 getpeercon(s, &source_ctx); 312 313 if(memcmp(msg.name,"ctl.",4) == 0) { 314 // Keep the old close-socket-early behavior when handling 315 // ctl.* properties. 316 close(s); 317 if (check_control_mac_perms(msg.value, source_ctx)) { 318 handle_control_message((char*) msg.name + 4, (char*) msg.value); 319 } else { 320 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n", 321 msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid); 322 } 323 } else { 324 if (check_perms(msg.name, source_ctx)) { 325 property_set((char*) msg.name, (char*) msg.value); 326 } else { 327 ERROR("sys_prop: permission denied uid:%d name:%s\n", 328 cr.uid, msg.name); 329 } 330 331 // Note: bionic's property client code assumes that the 332 // property server will not close the socket until *AFTER* 333 // the property is written to memory. 334 close(s); 335 } 336 freecon(source_ctx); 337 break; 338 339 default: 340 close(s); 341 break; 342 } 343} 344 345void get_property_workspace(int *fd, int *sz) 346{ 347 *fd = pa_workspace.fd; 348 *sz = pa_workspace.size; 349} 350 351static void load_properties_from_file(const char *, const char *); 352 353/* 354 * Filter is used to decide which properties to load: NULL loads all keys, 355 * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. 356 */ 357static void load_properties(char *data, const char *filter) 358{ 359 char *key, *value, *eol, *sol, *tmp, *fn; 360 size_t flen = 0; 361 362 if (filter) { 363 flen = strlen(filter); 364 } 365 366 sol = data; 367 while ((eol = strchr(sol, '\n'))) { 368 key = sol; 369 *eol++ = 0; 370 sol = eol; 371 372 while (isspace(*key)) key++; 373 if (*key == '#') continue; 374 375 tmp = eol - 2; 376 while ((tmp > key) && isspace(*tmp)) *tmp-- = 0; 377 378 if (!strncmp(key, "import ", 7) && flen == 0) { 379 fn = key + 7; 380 while (isspace(*fn)) fn++; 381 382 key = strchr(fn, ' '); 383 if (key) { 384 *key++ = 0; 385 while (isspace(*key)) key++; 386 } 387 388 load_properties_from_file(fn, key); 389 390 } else { 391 value = strchr(key, '='); 392 if (!value) continue; 393 *value++ = 0; 394 395 tmp = value - 2; 396 while ((tmp > key) && isspace(*tmp)) *tmp-- = 0; 397 398 while (isspace(*value)) value++; 399 400 if (flen > 0) { 401 if (filter[flen - 1] == '*') { 402 if (strncmp(key, filter, flen - 1)) continue; 403 } else { 404 if (strcmp(key, filter)) continue; 405 } 406 } 407 408 property_set(key, value); 409 } 410 } 411} 412 413/* 414 * Filter is used to decide which properties to load: NULL loads all keys, 415 * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. 416 */ 417static void load_properties_from_file(const char *fn, const char *filter) 418{ 419 std::string data; 420 if (read_file(fn, &data)) { 421 load_properties(&data[0], filter); 422 } 423} 424 425static void load_persistent_properties() 426{ 427 DIR* dir = opendir(PERSISTENT_PROPERTY_DIR); 428 int dir_fd; 429 struct dirent* entry; 430 char value[PROP_VALUE_MAX]; 431 int fd, length; 432 struct stat sb; 433 434 if (dir) { 435 dir_fd = dirfd(dir); 436 while ((entry = readdir(dir)) != NULL) { 437 if (strncmp("persist.", entry->d_name, strlen("persist."))) 438 continue; 439 if (entry->d_type != DT_REG) 440 continue; 441 /* open the file and read the property value */ 442 fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW); 443 if (fd < 0) { 444 ERROR("Unable to open persistent property file \"%s\" errno: %d\n", 445 entry->d_name, errno); 446 continue; 447 } 448 if (fstat(fd, &sb) < 0) { 449 ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno); 450 close(fd); 451 continue; 452 } 453 454 // File must not be accessible to others, be owned by root/root, and 455 // not be a hard link to any other file. 456 if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) 457 || (sb.st_uid != 0) 458 || (sb.st_gid != 0) 459 || (sb.st_nlink != 1)) { 460 ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n", 461 entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid, 462 (unsigned int)sb.st_nlink, sb.st_mode); 463 close(fd); 464 continue; 465 } 466 467 length = read(fd, value, sizeof(value) - 1); 468 if (length >= 0) { 469 value[length] = 0; 470 property_set(entry->d_name, value); 471 } else { 472 ERROR("Unable to read persistent property file %s errno: %d\n", 473 entry->d_name, errno); 474 } 475 close(fd); 476 } 477 closedir(dir); 478 } else { 479 ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno); 480 } 481 482 persistent_properties_loaded = 1; 483} 484 485void property_init(void) 486{ 487 init_property_area(); 488} 489 490void property_load_boot_defaults(void) 491{ 492 load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL); 493} 494 495int properties_inited(void) 496{ 497 return property_area_inited; 498} 499 500static void load_override_properties() { 501 if (ALLOW_LOCAL_PROP_OVERRIDE) { 502 char debuggable[PROP_VALUE_MAX]; 503 int ret = property_get("ro.debuggable", debuggable); 504 if (ret && (strcmp(debuggable, "1") == 0)) { 505 load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL); 506 } 507 } 508} 509 510 511/* When booting an encrypted system, /data is not mounted when the 512 * property service is started, so any properties stored there are 513 * not loaded. Vold triggers init to load these properties once it 514 * has mounted /data. 515 */ 516void load_persist_props(void) 517{ 518 load_override_properties(); 519 /* Read persistent properties after all default values have been loaded. */ 520 load_persistent_properties(); 521} 522 523void load_all_props(void) 524{ 525 load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); 526 load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); 527 load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL); 528 load_properties_from_file(PROP_PATH_BOOTIMAGE_BUILD, NULL); 529 load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); 530 531 load_override_properties(); 532 533 /* Read persistent properties after all default values have been loaded. */ 534 load_persistent_properties(); 535} 536 537void start_property_service(void) 538{ 539 int fd; 540 541 fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL); 542 if(fd < 0) return; 543 fcntl(fd, F_SETFD, FD_CLOEXEC); 544 fcntl(fd, F_SETFL, O_NONBLOCK); 545 546 listen(fd, 8); 547 property_set_fd = fd; 548} 549 550int get_property_set_fd() 551{ 552 return property_set_fd; 553} 554