summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack He <siyuanh@google.com>2017-03-13 10:37:06 -0700
committerWolf-Dieter Enders <grzwolf1@gmail.com>2017-06-11 18:11:45 +0000
commit454570d2a9a43fce05aadaf401bc341403efab78 (patch)
treea445067fea5725e000bb1e6a9611b60e6fd7394a
parent77656bec777a9992ef5a00e921d4990f5962ebba (diff)
downloadandroid_packages_apps_Bluetooth-454570d2a9a43fce05aadaf401bc341403efab78.tar.gz
android_packages_apps_Bluetooth-454570d2a9a43fce05aadaf401bc341403efab78.tar.bz2
android_packages_apps_Bluetooth-454570d2a9a43fce05aadaf401bc341403efab78.zip
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 Change-Id: Id5519588266f22674b6d01ec6ebe34fe38cbccce (cherry picked from commit 3edd7f0a8aadf2f44bc62ea5b567c74d39a534c8) (cherry picked from commit 3ce229fa602f739d1e98e2a85a3bd955c3a308f6)
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java4
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java9
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppManager.java10
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java15
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java2
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppUtility.java38
6 files changed, 66 insertions, 12 deletions
diff --git a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
index c2cd172d0..5b3777bb7 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
@@ -50,7 +50,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, false);
} else {
if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
}
@@ -60,7 +60,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 39116a0d3..b0ff6d9e6 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 b9c0a8a60..407552a1c 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppManager.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppManager.java
@@ -251,14 +251,15 @@ 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;
mIsHandoverInitiated = isHandover;
Uri uri = Uri.parse(uriString);
BluetoothOppSendFileInfo sendFileInfo =
- BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType);
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType, fromExternal);
uri = BluetoothOppUtility.generateUri(uri, sendFileInfo);
BluetoothOppUtility.putSendFileInfo(uri, sendFileInfo);
mUriOfSendingFile = uri.toString();
@@ -267,7 +268,8 @@ public class BluetoothOppManager {
}
}
- 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;
@@ -275,7 +277,7 @@ public class BluetoothOppManager {
mIsHandoverInitiated = isHandover;
for (Uri uri : uris) {
BluetoothOppSendFileInfo sendFileInfo =
- BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType);
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType, fromExternal);
uri = BluetoothOppUtility.generateUri(uri, sendFileInfo);
mUrisOfSendingFiles.add(uri);
BluetoothOppUtility.putSendFileInfo(uri, sendFileInfo);
diff --git a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
index 7c75d950f..724d75b5a 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
@@ -41,6 +41,7 @@ import android.database.CursorWindowAllocationException;
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;
@@ -99,8 +100,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;
@@ -143,6 +144,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 78f75ed58..2020d967e 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
@@ -373,7 +373,7 @@ public class BluetoothOppTransferActivity extends AlertActivity implements
// retry the failed transfer
Uri uri = BluetoothOppUtility.originalUri(Uri.parse(mTransInfo.mFileUri));
BluetoothOppSendFileInfo sendFileInfo =
- BluetoothOppSendFileInfo.generateFileInfo(this, uri, mTransInfo.mFileType);
+ BluetoothOppSendFileInfo.generateFileInfo(this, 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 f50b0fd15..4ccc3ca12 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.CursorWindowAllocationException;
import android.database.sqlite.SQLiteException;
import android.util.Log;
@@ -377,4 +379,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;
+ }
+ }
}