diff options
author | Jack He <siyuanh@google.com> | 2017-03-13 10:37:06 -0700 |
---|---|---|
committer | MSe <mse1969@posteo.de> | 2017-06-09 10:26:05 +0200 |
commit | 7d99b2d1d73b0f9d501dc9c99e0139c65f3b2b8e (patch) | |
tree | 5e606e7aa843667db182efdb66431edc4089e2b0 | |
parent | 63909f33c742c49a0781a741d096372a8a13eb80 (diff) | |
download | android_packages_apps_Bluetooth-7d99b2d1d73b0f9d501dc9c99e0139c65f3b2b8e.tar.gz android_packages_apps_Bluetooth-7d99b2d1d73b0f9d501dc9c99e0139c65f3b2b8e.tar.bz2 android_packages_apps_Bluetooth-7d99b2d1d73b0f9d501dc9c99e0139c65f3b2b8e.zip |
[BACKPORT] OPP: Restrict file based URI access to external storage
* Allow only external storage paths in file based URI in
BluetoothOppSendFileInfo when the file send request comes from an
external source
* Fix a potential NPE when using Uri.getPath()
Bug: 35310991
Test: Make, test various cases of Bluetooth file share
AOSP-Change-Id: I8ff00d63d3c880667302f8d7ff8eaa0c0b533921
(cherry picked from commit 3edd7f0a8aadf2f44bc62ea5b567c74d39a534c8)
(cherry picked from commit 3ce229fa602f739d1e98e2a85a3bd955c3a308f6)
CVE-2017-0639
Change-Id: I8e90c92ae7be6819528e35638bf033f4826af16d
6 files changed, 70 insertions, 14 deletions
diff --git a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java index aa2af081d..4323db713 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java +++ b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java @@ -52,7 +52,7 @@ public class BluetoothOppHandoverReceiver extends BroadcastReceiver { // Save type/stream, will be used when adding transfer // session to DB. BluetoothOppManager.getInstance(context).saveSendingFileInfo(type, - stream.toString(), true); + stream.toString(), true /* isHandover */, true /* fromExternal */); } else { if (D) Log.d(TAG, "No mimeType or stream attached to handover request"); } @@ -62,7 +62,7 @@ public class BluetoothOppHandoverReceiver extends BroadcastReceiver { uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); if (mimeType != null && uris != null) { BluetoothOppManager.getInstance(context).saveSendingFileInfo(mimeType, - uris, true); + uris, true /* isHandover */, true /* fromExternal */); } else { if (D) Log.d(TAG, "No mimeType or stream attached to handover request"); return; diff --git a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java index 717597b06..2e395e1a4 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java +++ b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java @@ -111,7 +111,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(); @@ -127,7 +128,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(); @@ -155,7 +157,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 59ecf3599..362cda655 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppManager.java +++ b/src/com/android/bluetooth/opp/BluetoothOppManager.java @@ -248,28 +248,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<Uri> uris, boolean isHandover) { + public void saveSendingFileInfo(String mimeType, ArrayList<Uri> 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 742a60c41..c456097cc 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; @@ -139,6 +140,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/BluetoothOppTransferActivity.java b/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java index 5cd027aa2..2442735ab 100644 --- a/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java +++ b/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java @@ -401,7 +401,7 @@ public class BluetoothOppTransferActivity extends AlertActivity implements public void run() { BluetoothOppSendFileInfo sendFileInfo = BluetoothOppSendFileInfo.generateFileInfo(BluetoothOppTransferActivity.this, - uri, mTransInfo.mFileType); + uri, mTransInfo.mFileType, false); uri = BluetoothOppUtility.generateUri(uri, sendFileInfo); BluetoothOppUtility.putSendFileInfo(uri, sendFileInfo); mTransInfo.mFileUri = uri.toString(); diff --git a/src/com/android/bluetooth/opp/BluetoothOppUtility.java b/src/com/android/bluetooth/opp/BluetoothOppUtility.java index 081d15b52..71b9641c0 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.database.sqlite.SQLiteException; import android.util.Log; @@ -409,4 +411,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; + } + } } |