Reconcile with jb-mr1-factory-release jb-mr1-release - do not merge

Change-Id: Ie75896ec89b34fe067a2d1c6b34309629459228b
diff --git a/adb/services.c b/adb/services.c
index 495a083..54d21a8 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -202,7 +202,7 @@
     int c;
 
     for(;;) {
-        r = read(fd, buf, 4096);
+        r = adb_read(fd, buf, 4096);
         if(r == 0) goto done;
         if(r < 0) {
             if(errno == EINTR) continue;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 66b60cc..0252ef3 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -275,6 +275,22 @@
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <string.h>
+#include <unistd.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
 
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
@@ -310,7 +326,7 @@
 {
     if ((options & O_CREAT) == 0)
     {
-        return  open(path, options);
+        return  TEMP_FAILURE_RETRY( open(path, options) );
     }
     else
     {
@@ -319,19 +335,19 @@
         va_start( args, options );
         mode = va_arg( args, int );
         va_end( args );
-        return open(path, options, mode);
+        return TEMP_FAILURE_RETRY( open( path, options, mode ) );
     }
 }
 
 static __inline__ int  adb_open_mode( const char*  pathname, int  options, int  mode )
 {
-    return open( pathname, options, mode );
+    return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
 }
 
 
 static __inline__ int  adb_open( const char*  pathname, int  options )
 {
-    int  fd = open( pathname, options );
+    int  fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
     if (fd < 0)
         return -1;
     close_on_exec( fd );
@@ -357,7 +373,7 @@
 
 static __inline__  int  adb_read(int  fd, void*  buf, size_t  len)
 {
-    return read(fd, buf, len);
+    return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
 }
 
 #undef   read
@@ -365,7 +381,7 @@
 
 static __inline__  int  adb_write(int  fd, const void*  buf, size_t  len)
 {
-    return write(fd, buf, len);
+    return TEMP_FAILURE_RETRY( write( fd, buf, len ) );
 }
 #undef   write
 #define  write  ___xxx_write
@@ -386,7 +402,7 @@
 
 static __inline__  int  adb_creat(const char*  path, int  mode)
 {
-    int  fd = creat(path, mode);
+    int  fd = TEMP_FAILURE_RETRY( creat( path, mode ) );
 
     if ( fd < 0 )
         return -1;
@@ -401,7 +417,7 @@
 {
     int fd;
 
-    fd = accept(serverfd, addr, addrlen);
+    fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
     if (fd >= 0)
         close_on_exec(fd);
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 538b5be..2bcc9c4 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -173,7 +173,7 @@
  * then return an empty buffer.  This effectively ignores lines that are too long.
  * On EOF, return null.
  */
-static char *getline(char *buf, int size, FILE *file)
+static char *fs_getline(char *buf, int size, FILE *file)
 {
     int cnt = 0;
     int eof = 0;
@@ -247,7 +247,7 @@
     }
 
     entries = 0;
-    while (getline(line, sizeof(line), fstab_file)) {
+    while (fs_getline(line, sizeof(line), fstab_file)) {
         /* if the last character is a newline, shorten the string by 1 byte */
         len = strlen(line);
         if (line[len - 1] == '\n') {
@@ -274,7 +274,7 @@
     fseek(fstab_file, 0, SEEK_SET);
 
     cnt = 0;
-    while (getline(line, sizeof(line), fstab_file)) {
+    while (fs_getline(line, sizeof(line), fstab_file)) {
         /* if the last character is a newline, shorten the string by 1 byte */
         len = strlen(line);
         if (line[len - 1] == '\n') {
diff --git a/init/property_service.c b/init/property_service.c
index f58e07d..01a4d17 100755
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -125,7 +125,7 @@
         /* dev is a tmpfs that we can use to carve a shared workspace
          * out of, so let's do that...
          */
-    fd = open("/dev/__properties__", O_RDWR | O_CREAT, 0600);
+    fd = open("/dev/__properties__", O_RDWR | O_CREAT | O_NOFOLLOW, 0600);
     if (fd < 0)
         return -1;
 
@@ -138,7 +138,7 @@
 
     close(fd);
 
-    fd = open("/dev/__properties__", O_RDONLY);
+    fd = open("/dev/__properties__", O_RDONLY | O_NOFOLLOW);
     if (fd < 0)
         return -1;
 
@@ -320,13 +320,12 @@
 
 static void write_persistent_property(const char *name, const char *value)
 {
-    const char *tempPath = PERSISTENT_PROPERTY_DIR "/.temp";
+    char tempPath[PATH_MAX];
     char path[PATH_MAX];
-    int fd, length;
+    int fd;
 
-    snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
-
-    fd = open(tempPath, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+    snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
+    fd = mkstemp(tempPath);
     if (fd < 0) {
         ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);
         return;
@@ -334,6 +333,7 @@
     write(fd, value, strlen(value));
     close(fd);
 
+    snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
     if (rename(tempPath, path)) {
         unlink(tempPath);
         ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);
@@ -345,8 +345,8 @@
     prop_area *pa;
     prop_info *pi;
 
-    int namelen = strlen(name);
-    int valuelen = strlen(value);
+    size_t namelen = strlen(name);
+    size_t valuelen = strlen(value);
 
     if(namelen >= PROP_NAME_MAX) return -1;
     if(valuelen >= PROP_VALUE_MAX) return -1;
@@ -425,13 +425,13 @@
     /* Check socket options here */
     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
         close(s);
-        ERROR("Unable to recieve socket options\n");
+        ERROR("Unable to receive socket options\n");
         return;
     }
 
     r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
     if(r != sizeof(prop_msg)) {
-        ERROR("sys_prop: mis-match msg size recieved: %d expected: %d errno: %d\n",
+        ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
               r, sizeof(prop_msg), errno);
         close(s);
         return;
@@ -530,10 +530,11 @@
 static void load_persistent_properties()
 {
     DIR* dir = opendir(PERSISTENT_PROPERTY_DIR);
+    int dir_fd = dirfd(dir);
     struct dirent*  entry;
-    char path[PATH_MAX];
     char value[PROP_VALUE_MAX];
     int fd, length;
+    struct stat sb;
 
     if (dir) {
         while ((entry = readdir(dir)) != NULL) {
@@ -544,20 +545,39 @@
                 continue;
 #endif
             /* open the file and read the property value */
-            snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, entry->d_name);
-            fd = open(path, O_RDONLY);
-            if (fd >= 0) {
-                length = read(fd, value, sizeof(value) - 1);
-                if (length >= 0) {
-                    value[length] = 0;
-                    property_set(entry->d_name, value);
-                } else {
-                    ERROR("Unable to read persistent property file %s errno: %d\n", path, errno);
-                }
-                close(fd);
-            } else {
-                ERROR("Unable to open persistent property file %s errno: %d\n", path, errno);
+            fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW);
+            if (fd < 0) {
+                ERROR("Unable to open persistent property file \"%s\" errno: %d\n",
+                      entry->d_name, errno);
+                continue;
             }
+            if (fstat(fd, &sb) < 0) {
+                ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno);
+                close(fd);
+                continue;
+            }
+
+            // File must not be accessible to others, be owned by root/root, and
+            // not be a hard link to any other file.
+            if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0)
+                    || (sb.st_uid != 0)
+                    || (sb.st_gid != 0)
+                    || (sb.st_nlink != 1)) {
+                ERROR("skipping insecure property file %s (uid=%lu gid=%lu nlink=%d mode=%o)\n",
+                      entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode);
+                close(fd);
+                continue;
+            }
+
+            length = read(fd, value, sizeof(value) - 1);
+            if (length >= 0) {
+                value[length] = 0;
+                property_set(entry->d_name, value);
+            } else {
+                ERROR("Unable to read persistent property file %s errno: %d\n",
+                      entry->d_name, errno);
+            }
+            close(fd);
         }
         closedir(dir);
     } else {
diff --git a/toolbox/ls.c b/toolbox/ls.c
index a4db99c..b7ba1b7 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -276,12 +276,12 @@
     switch(s.st_mode & S_IFMT) {
     case S_IFLNK: {
         char linkto[256];
-        int len;
+        ssize_t len;
 
         len = readlink(path, linkto, sizeof(linkto));
         if(len < 0) return -1;
 
-        if(len > sizeof(linkto)-1) {
+        if((size_t)len > sizeof(linkto)-1) {
             linkto[sizeof(linkto)-4] = '.';
             linkto[sizeof(linkto)-3] = '.';
             linkto[sizeof(linkto)-2] = '.';
@@ -307,7 +307,7 @@
 
 static int listfile(const char *dirname, const char *filename, int flags)
 {
-    if ((flags & LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL) == 0) {
+    if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL)) == 0) {
         printf("%s\n", filename);
         return 0;
     }