ConfigUpdateInstallReceiver: pass content via content provider
When receiving a request to update ConfigUpdater content, don't
try to open by filename. Fetch the content via a file descriptor
delivered from a content provider. This avoids the files needing to
be marked world-readable, and resolves an SELinux violation.
Bug: 14989241
Change-Id: I10ad0d710c9a833a45995c545ba585a533c35b0d
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7db478d..1a3c66d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2893,36 +2893,42 @@
<receiver android:name="com.android.server.updates.CertPinInstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.UPDATE_PINS" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
<receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
<receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
<receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
<receiver android:name="com.android.server.updates.TZInfoInstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.UPDATE_TZINFO" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
<receiver android:name="com.android.server.updates.SELinuxPolicyInstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.UPDATE_SEPOLICY" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
diff --git a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index 1a68fb3..7f7aae3 100644
--- a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -20,6 +20,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
import android.provider.Settings;
import android.util.Base64;
import android.util.EventLog;
@@ -40,6 +41,7 @@
import java.security.Signature;
import libcore.io.IoUtils;
+import libcore.io.Streams;
public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
@@ -73,7 +75,7 @@
// get the certificate from Settings.Secure
X509Certificate cert = getCert(context.getContentResolver());
// get the content path from the extras
- byte[] altContent = getAltContent(intent);
+ byte[] altContent = getAltContent(context, intent);
// get the version from the extras
int altVersion = getVersionFromIntent(intent);
// get the previous value from the extras
@@ -127,12 +129,12 @@
}
}
- private String getContentFromIntent(Intent i) {
- String extraValue = i.getStringExtra(EXTRA_CONTENT_PATH);
- if (extraValue == null) {
+ private Uri getContentFromIntent(Intent i) {
+ Uri data = i.getData();
+ if (data == null) {
throw new IllegalStateException("Missing required content path, ignoring.");
}
- return extraValue;
+ return data;
}
private int getVersionFromIntent(Intent i) throws NumberFormatException {
@@ -169,8 +171,14 @@
}
}
- private byte[] getAltContent(Intent i) throws IOException {
- return IoUtils.readFileAsByteArray(getContentFromIntent(i));
+ private byte[] getAltContent(Context c, Intent i) throws IOException {
+ Uri content = getContentFromIntent(i);
+ InputStream is = c.getContentResolver().openInputStream(content);
+ try {
+ return Streams.readFullyNoClose(is);
+ } finally {
+ is.close();
+ }
}
private byte[] getCurrentContent() {