From 0ed24c45ee74bf83c14e4f05d9ee82bc99aa0712 Mon Sep 17 00:00:00 2001 From: Jack He Date: Mon, 13 Mar 2017 10:37:06 -0700 Subject: [PATCH] OPP: Restrict file based URI access to external storage Change-Id: Icad55763f2478586544a4bbd233b820c7f69b658 --- .../opp/BluetoothOppHandoverReceiver.java | 2 +- .../opp/BluetoothOppLauncherActivity.java | 9 +++-- .../android/bluetooth/opp/BluetoothOppManager.java | 16 +++++---- .../bluetooth/opp/BluetoothOppSendFileInfo.java | 15 +++++++-- .../android/bluetooth/opp/BluetoothOppUtility.java | 38 ++++++++++++++++++++++ 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java index 3553d34f..4f03c96c 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java +++ b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java @@ -59,7 +59,7 @@ public class BluetoothOppHandoverReceiver extends BroadcastReceiver { Thread t = new Thread(new Runnable() { public void run() { BluetoothOppManager.getInstance(context).saveSendingFileInfo(finalType, - finalUris, true); + finalUris, true /* isHandover */, true /* fromExternal */); BluetoothOppManager.getInstance(context).startTransfer(device); } }); diff --git a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java index 0d4b5b28..c2987456 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java +++ b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java @@ -112,7 +112,8 @@ public class BluetoothOppLauncherActivity extends Activity { Thread t = new Thread(new Runnable() { public void run() { BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this) - .saveSendingFileInfo(type,stream.toString(), false); + .saveSendingFileInfo(type,stream.toString(), + false /* isHandover */, true /* fromExternal */); //Done getting file info..Launch device picker and finish this activity launchDevicePicker(); finish(); @@ -128,7 +129,8 @@ public class BluetoothOppLauncherActivity extends Activity { Thread t = new Thread(new Runnable() { public void run() { BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this) - .saveSendingFileInfo(type,fileUri.toString(), false); + .saveSendingFileInfo(type,fileUri.toString(), + false /* isHandover */, false /* fromExternal */); //Done getting file info..Launch device picker //and finish this activity launchDevicePicker(); @@ -156,7 +158,8 @@ public class BluetoothOppLauncherActivity extends Activity { Thread t = new Thread(new Runnable() { public void run() { BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this) - .saveSendingFileInfo(mimeType,uris, false); + .saveSendingFileInfo(mimeType,uris, + false /* isHandover */, true /* fromExternal */); //Done getting file info..Launch device picker //and finish this activity launchDevicePicker(); diff --git a/src/com/android/bluetooth/opp/BluetoothOppManager.java b/src/com/android/bluetooth/opp/BluetoothOppManager.java index dd8efe01..39929aa9 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppManager.java +++ b/src/com/android/bluetooth/opp/BluetoothOppManager.java @@ -246,28 +246,32 @@ public class BluetoothOppManager { if (V) Log.v(TAG, "Application data stored to SharedPreference! "); } - public void saveSendingFileInfo(String mimeType, String uriString, boolean isHandover) { + public void saveSendingFileInfo(String mimeType, String uriString, boolean isHandover, + boolean fromExternal) { synchronized (BluetoothOppManager.this) { mMultipleFlag = false; mMimeTypeOfSendingFile = mimeType; mUriOfSendingFile = uriString; mIsHandoverInitiated = isHandover; Uri uri = Uri.parse(uriString); - BluetoothOppUtility.putSendFileInfo(uri, - BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType)); + BluetoothOppUtility.putSendFileInfo( + uri, BluetoothOppSendFileInfo.generateFileInfo( + mContext, uri, mimeType, fromExternal)); storeApplicationData(); } } - public void saveSendingFileInfo(String mimeType, ArrayList uris, boolean isHandover) { + public void saveSendingFileInfo(String mimeType, ArrayList uris, boolean isHandover, + boolean fromExternal) { synchronized (BluetoothOppManager.this) { mMultipleFlag = true; mMimeTypeOfSendingFiles = mimeType; mUrisOfSendingFiles = uris; mIsHandoverInitiated = isHandover; for (Uri uri : uris) { - BluetoothOppUtility.putSendFileInfo(uri, - BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType)); + BluetoothOppUtility.putSendFileInfo( + uri, BluetoothOppSendFileInfo.generateFileInfo( + mContext, uri, mimeType, fromExternal)); } storeApplicationData(); } diff --git a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java index b9d2b9f2..84ebc822 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java +++ b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java @@ -39,6 +39,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.net.Uri; import android.provider.OpenableColumns; +import android.util.EventLog; import android.util.Log; import java.io.File; @@ -97,8 +98,8 @@ public class BluetoothOppSendFileInfo { mStatus = status; } - public static BluetoothOppSendFileInfo generateFileInfo(Context context, Uri uri, - String type) { + public static BluetoothOppSendFileInfo generateFileInfo( + Context context, Uri uri, String type, boolean fromExternal) { ContentResolver contentResolver = context.getContentResolver(); String scheme = uri.getScheme(); String fileName = null; @@ -140,6 +141,16 @@ public class BluetoothOppSendFileInfo { fileName = uri.getLastPathSegment(); } } else if ("file".equals(scheme)) { + if (uri.getPath() == null) { + Log.e(TAG, "Invalid URI path: " + uri); + return SEND_FILE_INFO_ERROR; + } + if (fromExternal && !BluetoothOppUtility.isInExternalStorageDir(uri)) { + EventLog.writeEvent(0x534e4554, "35310991", -1, uri.getPath()); + Log.e(TAG, + "File based URI not in Environment.getExternalStorageDirectory() is not allowed."); + return SEND_FILE_INFO_ERROR; + } fileName = uri.getLastPathSegment(); contentType = type; File f = new File(uri.getPath()); diff --git a/src/com/android/bluetooth/opp/BluetoothOppUtility.java b/src/com/android/bluetooth/opp/BluetoothOppUtility.java index bd671b21..6b94ab56 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppUtility.java +++ b/src/com/android/bluetooth/opp/BluetoothOppUtility.java @@ -39,6 +39,7 @@ import com.google.android.collect.Lists; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.net.Uri; +import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.ActivityNotFoundException; @@ -46,6 +47,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; +import android.os.Environment; import android.util.Log; import java.io.File; @@ -353,4 +355,40 @@ public class BluetoothOppUtility { } } } + + /** + * Checks if the URI is in Environment.getExternalStorageDirectory() as it + * is the only directory that is possibly readable by both the sender and + * the Bluetooth process. + */ + static boolean isInExternalStorageDir(Uri uri) { + if (!ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { + Log.e(TAG, "Not a file URI: " + uri); + return false; + } + final File file = new File(uri.getCanonicalUri().getPath()); + return isSameOrSubDirectory(Environment.getExternalStorageDirectory(), file); + } + + /** + * Checks, whether the child directory is the same as, or a sub-directory of the base + * directory. Neither base nor child should be null. + */ + static boolean isSameOrSubDirectory(File base, File child) { + try { + base = base.getCanonicalFile(); + child = child.getCanonicalFile(); + File parentFile = child; + while (parentFile != null) { + if (base.equals(parentFile)) { + return true; + } + parentFile = parentFile.getParentFile(); + } + return false; + } catch (IOException ex) { + Log.e(TAG, "Error while accessing file", ex); + return false; + } + } } -- 2.11.0