Fix Gallery2 path traversal bug

Fix a path traversal bug that allowed a malicious launcher app to access files in the private space of the Gallery2 app by injecting a bad path.
Fix: Check URI before passing the file out from SharedImageProvider and raise exception if it's not pointing to the relevant folder.
Bug: 198174170
Test: manual by following the reporters instructions

Change-Id: I74dce6c4794b3eafb922bb9a2f2516677cc5f4d8
diff --git a/src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java b/src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java
index bc17a6e..fc7ec60 100644
--- a/src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java
+++ b/src/com/android/gallery3d/filtershow/provider/SharedImageProvider.java
@@ -29,16 +29,20 @@
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 
 public class SharedImageProvider extends ContentProvider {
 
     private static final String LOGTAG = "SharedImageProvider";
 
     public static final String MIME_TYPE = "image/jpeg";
-    public static final String AUTHORITY = "com.android.gallery3d.filtershow.provider.SharedImageProvider";
+    public static final String AUTHORITY =
+            "com.android.gallery3d.filtershow.provider.SharedImageProvider";
     public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/image");
     public static final String PREPARE = "prepare";
 
+    public static String LOCAL_PATH = (new File(CONTENT_URI.getPath())).getAbsolutePath();
+
     private final String[] mMimeStreamType = {
             MIME_TYPE
     };
@@ -83,13 +87,14 @@
     }
 
     @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
         String uriPath = uri.getLastPathSegment();
         if (uriPath == null) {
             return null;
         }
         if (projection == null) {
-            projection = new String[] {
+            projection = new String[]{
                     BaseColumns._ID,
                     MediaStore.MediaColumns.DATA,
                     OpenableColumns.DISPLAY_NAME,
@@ -130,8 +135,32 @@
         // Here we need to block until the image is ready
         mImageReadyCond.block();
         File path = new File(uriPath);
+        ensureValidImagePath(path);
         int imode = 0;
         imode |= ParcelFileDescriptor.MODE_READ_ONLY;
         return ParcelFileDescriptor.open(path, imode);
     }
+
+    /**
+     * Ensure that the provided file path is part of the image directory.
+     * Prevent unauthorized access to other directories by path traversal.
+     * Throw security exception for paths outside the directory.
+     *
+     * @param path The path of the file to check. This path is expected to point to the image
+     *             directory.
+     * @throws SecurityException     Throws SecurityException if the path is not part of the image
+     *                               directory.
+     * @throws FileNotFoundException Throws FileNotFoundException if there is
+     *                               no file associated with the given URI.
+     */
+    private void ensureValidImagePath(File path) throws FileNotFoundException {
+        try {
+            if (!path.getCanonicalPath().startsWith(LOCAL_PATH)) {
+                throw new SecurityException(
+                        "The requested file path is not part of the image directory");
+            }
+        } catch (IOException e) {
+            throw new FileNotFoundException(e.getMessage());
+        }
+    }
 }