mirror of
https://github.com/github/codeql.git
synced 2026-04-24 16:25:15 +02:00
Documentation and examples
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Android allows an application to install an APK (Android package kit)
|
||||
using an <code>Intent</code> with
|
||||
the <code>"application/vnd.android.package-archive"</code> MIME type. If
|
||||
the file used in the <code>Intent</code> is from a location that is not
|
||||
controlled by the application (for example, the SD card which is
|
||||
universally writable), this can result in the installation of an
|
||||
application which was not intended.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
It is advised to transition to install packages using
|
||||
the <code>PackageInstaller</code> class.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If installation from a file is necessary, it is best to use
|
||||
a <code>FileProvider</code>. Content providers can provide more specific
|
||||
permissions than file system permissions can.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When your application does not require installing packages, do not add
|
||||
the <code>REQUEST_INSTALL_PACKAGES</code> permission in the manifest file.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
<p>
|
||||
In the following (bad) example, the package is installed from a file which
|
||||
may be altered by another application.
|
||||
</p>
|
||||
|
||||
<sample src="InstallApkWithFile.java"/>
|
||||
|
||||
<p>
|
||||
In the following (good) example, the package is installed by using
|
||||
a <code>FileProvider</code>.
|
||||
</p>
|
||||
|
||||
<sample src="InstallApkWithFileProvider.java"/>
|
||||
|
||||
<p>
|
||||
In the following (good) example, the package is installed using an
|
||||
instance of the <code>android.content.pm.PackageInstaller</code> class.
|
||||
</p>
|
||||
|
||||
<sample src="InstallApkWithPackageInstaller.java"/>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Intent.ACTION_INSTALL_PACKAGE: <a href="https://developer.android.com/reference/android/content/Intent#ACTION_INSTALL_PACKAGE"></a>.
|
||||
</li>
|
||||
<li>
|
||||
Android Manifest Permission to Install Packages: <a href="https://developer.android.com/reference/android/Manifest.permission#REQUEST_INSTALL_PACKAGES"></a>.
|
||||
</li>
|
||||
<li>
|
||||
PackageInstaller: <a href="https://developer.android.com/reference/android/content/pm/PackageInstaller"></a>.
|
||||
</li>
|
||||
<li>
|
||||
FileProvider: <a href="https://developer.android.com/reference/androidx/core/content/FileProvider"></a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
14
java/ql/src/Security/CWE/CWE-094/InstallApkWithFile.java
Normal file
14
java/ql/src/Security/CWE/CWE-094/InstallApkWithFile.java
Normal file
@@ -0,0 +1,14 @@
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/* Get a file from external storage */
|
||||
File file = new File(Environment.getExternalStorageDirectory(), "myapp.apk");
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
/* Set the mimetype to APK */
|
||||
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
|
||||
|
||||
startActivity(intent);
|
||||
@@ -0,0 +1,31 @@
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
String tempFilename = "temporary.apk";
|
||||
byte[] buffer = new byte[16384];
|
||||
|
||||
/* Copy application asset into temporary file */
|
||||
try (InputStream is = getAssets().open(assetName);
|
||||
FileOutputStream fout = openFileOutput(tempFilename, Context.MODE_PRIVATE)) {
|
||||
int n;
|
||||
while ((n=is.read(buffer)) >= 0) {
|
||||
fout.write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
|
||||
/* Expose temporary file with FileProvider */
|
||||
File toInstall = new File(this.getFilesDir(), tempFilename);
|
||||
Uri applicationUri = FileProvider.getUriForFile(this, "com.example.apkprovider", toInstall);
|
||||
|
||||
/* Create Intent and set data to APK file. */
|
||||
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
|
||||
intent.setData(applicationUri);
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
startActivity(intent);
|
||||
@@ -0,0 +1,32 @@
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInstaller;
|
||||
|
||||
private static final String PACKAGE_INSTALLED_ACTION =
|
||||
"com.example.SESSION_API_PACKAGE_INSTALLED";
|
||||
|
||||
/* Create the package installer and session */
|
||||
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
|
||||
PackageInstaller.SessionParams params =
|
||||
new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
|
||||
int sessionId = packageInstaller.createSession(params);
|
||||
session = packageInstaller.openSession(sessionId);
|
||||
|
||||
/* Load asset into session */
|
||||
try (OutputStream packageInSession = session.openWrite("package", 0, -1);
|
||||
InputStream is = getAssets().open(assetName)) {
|
||||
byte[] buffer = new byte[16384];
|
||||
int n;
|
||||
while ((n = is.read(buffer)) >= 0) {
|
||||
packageInSession.write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create status receiver */
|
||||
Intent intent = new Intent(this, InstallApkSessionApi.class);
|
||||
intent.setAction(PACKAGE_INSTALLED_ACTION);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
|
||||
IntentSender statusReceiver = pendingIntent.getIntentSender();
|
||||
|
||||
/* Commit the session */
|
||||
session.commit(statusReceiver);
|
||||
Reference in New Issue
Block a user