am 3617eb6c: am e57c5ae4: am 355d65b9: am c015f8e1: am 940b951d: am d0fd622e: am d96863a0: Backport path validation changes.

* commit '3617eb6c97c41c4e9f4120d9eac5ce1730506d3e':
  Backport path validation changes.
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index f1121be..0265a1e 100755
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -104,6 +104,8 @@
 import libcore.io.ErrnoException;
 import libcore.io.IoUtils;
 import libcore.io.Libcore;
+import libcore.io.OsConstants;
+import libcore.io.StructStat;
 
 /**
  * Media content provider. See {@link android.provider.MediaStore} for details.
@@ -4460,15 +4462,65 @@
             if (modeBits == MODE_READ_ONLY) {
                 file = Environment.maybeTranslateEmulatedPathToInternal(file);
             }
-
         } else if (path.startsWith(sCachePath)) {
             getContext().enforceCallingOrSelfPermission(
                     ACCESS_CACHE_FILESYSTEM, "Cache path: " + path);
+        } else if (isWrite) {
+            // don't write to non-cache, non-sdcard files.
+            throw new FileNotFoundException("Can't access " + file);
+        } else {
+            checkWorldReadAccess(path);
         }
 
         return ParcelFileDescriptor.open(file, modeBits);
     }
 
+    /**
+     * Check whether the path is a world-readable file
+     */
+    private void checkWorldReadAccess(String path) throws FileNotFoundException {
+
+        try {
+            StructStat stat = Libcore.os.stat(path);
+            int accessBits = OsConstants.S_IROTH;
+            if (OsConstants.S_ISREG(stat.st_mode) &&
+                ((stat.st_mode & accessBits) == accessBits)) {
+                checkLeadingPathComponentsWorldExecutable(path);
+                return;
+            }
+        } catch (ErrnoException e) {
+            // couldn't stat the file, either it doesn't exist or isn't
+            // accessible to us
+        }
+
+        throw new FileNotFoundException("Can't access " + path);
+    }
+
+    private void checkLeadingPathComponentsWorldExecutable(String filePath)
+            throws FileNotFoundException {
+        File parent = new File(filePath).getParentFile();
+
+        int accessBits = OsConstants.S_IXOTH;
+
+        while (parent != null) {
+            if (! parent.exists()) {
+                // parent dir doesn't exist, give up
+                throw new FileNotFoundException("access denied");
+            }
+            try {
+                StructStat stat = Libcore.os.stat(parent.getPath());
+                if ((stat.st_mode & accessBits) != accessBits) {
+                    // the parent dir doesn't have the appropriate access
+                    throw new FileNotFoundException("Can't access " + filePath);
+                }
+            } catch (ErrnoException e1) {
+                // couldn't stat() parent
+                throw new FileNotFoundException("Can't access " + filePath);
+            }
+            parent = parent.getParentFile();
+        }
+    }
+
     private class ThumbData {
         DatabaseHelper helper;
         SQLiteDatabase db;