mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-07-03 21:21:12 +08:00
Add INTERACT_ACROSS_USERS permission
This is a signature-level permission required in order to call getPackagesForUid for other users/profiles. It will be granted on first root capture start. See #217
This commit is contained in:
parent
e6bc27b3e3
commit
fec54e9499
@ -11,9 +11,11 @@
|
||||
<uses-permission android:name="android.permission.WRITE_CLIPS" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<uses-permission android:name="com.pcapdroid.permission.MITM" android:required="false"/>
|
||||
|
||||
<!-- Required with root to properly resolve UIDs cross-users/profiles. Granted via root -->
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" android:protectionLevel="signature" tools:ignore="ProtectedPermissions" />
|
||||
|
||||
<uses-feature android:name="android.software.leanback" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.wifi" android:required="false" />
|
||||
|
||||
@ -112,7 +112,8 @@ public class AppsResolver {
|
||||
try {
|
||||
packages = mPm.getPackagesForUid(uid);
|
||||
} catch (SecurityException e) {
|
||||
// this is a bug in some devices https://github.com/AdguardTeam/AdguardForAndroid/issues/173
|
||||
// A SecurityException is normally raised when trying to query a package of another user/profile
|
||||
// without holding the INTERACT_ACROSS_USERS/INTERACT_ACROSS_PROFILES permissions
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
@ -418,6 +418,12 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
Utils.showToast(this, R.string.vpn_setup_failed);
|
||||
return abortStart();
|
||||
}
|
||||
} else {
|
||||
// Root capture
|
||||
if(checkCallingOrSelfPermission(Utils.INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
|
||||
boolean success = Utils.rootGrantPermission(Utils.INTERACT_ACROSS_USERS);
|
||||
Utils.showToast(this, success ? R.string.permission_granted : R.string.permission_grant_fail, "INTERACT_ACROSS_USERS");
|
||||
}
|
||||
}
|
||||
|
||||
mWhitelist = PCAPdroid.getInstance().getMalwareWhitelist();
|
||||
@ -1224,4 +1230,5 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
public static native void nativeSetFirewallEnabled(boolean enabled);
|
||||
public static native int getNumCheckedMalwareConnections();
|
||||
public static native int getNumCheckedFirewallConnections();
|
||||
public static native int rootCmd(String prog, String args);
|
||||
}
|
||||
|
||||
@ -127,6 +127,7 @@ import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
public class Utils {
|
||||
static final String TAG = "Utils";
|
||||
public static final String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
|
||||
public static final int UID_UNKNOWN = -1;
|
||||
public static final int UID_NO_FILTER = -2;
|
||||
private static Boolean rootAvailable = null;
|
||||
@ -502,13 +503,13 @@ public class Utils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void showToast(Context context, int id) {
|
||||
String msg = context.getResources().getString(id);
|
||||
public static void showToast(Context context, int id, Object... args) {
|
||||
String msg = context.getResources().getString(id, (Object[]) args);
|
||||
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public static void showToastLong(Context context, int id) {
|
||||
String msg = context.getResources().getString(id);
|
||||
public static void showToastLong(Context context, int id, Object... args) {
|
||||
String msg = context.getResources().getString(id, (Object[]) args);
|
||||
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@ -1182,4 +1183,8 @@ public class Utils {
|
||||
tv.setText(text);
|
||||
tv.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
public static boolean rootGrantPermission(String perm) {
|
||||
return CaptureService.rootCmd("pm", String.format("grant %s %s", BuildConfig.APPLICATION_ID, perm)) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/wait.h>
|
||||
#include <paths.h>
|
||||
#include "utils.h"
|
||||
|
||||
memtrack_t memtrack = {0};
|
||||
@ -28,6 +30,9 @@ int loglevel = 0;
|
||||
const char *logtag = "pcapdroid-native";
|
||||
void (*logcallback)(int lvl, const char *msg) = NULL;
|
||||
|
||||
// Needed for local compilation, don't remove
|
||||
extern char **environ;
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
void set_log_level(int lvl) {
|
||||
@ -191,3 +196,78 @@ void hexdump(const char *buf, size_t bufsize) {
|
||||
out[idx] = '\0';
|
||||
log_d("%s", out);
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
int run_shell_cmd(const char *prog, const char *args, bool as_root, bool check_error) {
|
||||
int in_p[2], out_p[2];
|
||||
int rv = -1;
|
||||
pid_t pid;
|
||||
|
||||
if((pipe(in_p) != 0) || (pipe(out_p) != 0)) {
|
||||
log_f("pipe failed[%d]: %s", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((pid = fork()) == 0) {
|
||||
// child
|
||||
char *argp[] = {"sh", "-c", as_root ? "su" : "sh", NULL};
|
||||
|
||||
close(in_p[1]);
|
||||
close(out_p[0]);
|
||||
|
||||
dup2(in_p[0], STDIN_FILENO);
|
||||
dup2(out_p[1], STDOUT_FILENO);
|
||||
dup2(out_p[1], STDERR_FILENO);
|
||||
|
||||
execve(_PATH_BSHELL, argp, environ);
|
||||
fprintf(stderr, "execve failed[%d]: %s", errno, strerror(errno));
|
||||
exit(1);
|
||||
} else if(pid > 0) {
|
||||
// parent
|
||||
int out = out_p[0];
|
||||
close(in_p[0]);
|
||||
close(out_p[1]);
|
||||
|
||||
// write "su" command input
|
||||
log_d("run_shell_cmd[%d]: %s %s", pid, prog, args);
|
||||
write(in_p[1], prog, strlen(prog));
|
||||
write(in_p[1], " ", 1);
|
||||
write(in_p[1], args, strlen(args));
|
||||
write(in_p[1], "\n", 1);
|
||||
close(in_p[1]);
|
||||
|
||||
waitpid(pid, &rv, 0);
|
||||
|
||||
if(check_error && (rv != 0)) {
|
||||
char buf[128];
|
||||
struct timeval timeout = {0};
|
||||
fd_set fds;
|
||||
|
||||
buf[0] = '\0';
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(out, &fds);
|
||||
|
||||
select(out + 1, &fds, NULL, NULL, &timeout);
|
||||
if (FD_ISSET(out, &fds)) {
|
||||
int num = read(out, buf, sizeof(buf) - 1);
|
||||
if (num > 0)
|
||||
buf[num] = '\0';
|
||||
}
|
||||
|
||||
log_f("su \"%s\" invocation failed: %s", prog, buf);
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
close(out_p[0]);
|
||||
} else {
|
||||
log_f("fork() failed[%d]: %s", errno, strerror(errno));
|
||||
close(in_p[0]);
|
||||
close(in_p[1]);
|
||||
close(out_p[0]);
|
||||
close(out_p[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -62,5 +62,6 @@ void tupleSwapPeers(zdtun_5tuple_t *tuple);
|
||||
char loglvl2char(int lvl);
|
||||
char* humanSize(char *buf, int bufsize, double bytes);
|
||||
void hexdump(const char *buf, size_t bufsize);
|
||||
int run_shell_cmd(const char *prog, const char *args, bool as_root, bool check_error);
|
||||
|
||||
#endif // __LOG_UTILS_H__
|
||||
|
||||
@ -19,16 +19,11 @@
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <linux/limits.h>
|
||||
#include <sys/wait.h>
|
||||
#include <paths.h>
|
||||
#include "pcapdroid.h"
|
||||
#include "pcapd/pcapd.h"
|
||||
#include "common/utils.h"
|
||||
#include "third_party/uthash.h"
|
||||
|
||||
// Needed for local compilation, don't remove
|
||||
extern char **environ;
|
||||
|
||||
#ifdef FUZZING
|
||||
extern int openPcap(pcapdroid_t *pd);
|
||||
extern int nextPacket(pcapdroid_t *pd, pcapd_hdr_t *hdr, char *buf, size_t bufsize);
|
||||
@ -50,81 +45,6 @@ typedef struct pcap_conn_t {
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static int run_cmd(const char *prog, const char *args, bool as_root, bool check_error) {
|
||||
int in_p[2], out_p[2];
|
||||
int rv = -1;
|
||||
pid_t pid;
|
||||
|
||||
if((pipe(in_p) != 0) || (pipe(out_p) != 0)) {
|
||||
log_f("pipe failed[%d]: %s", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((pid = fork()) == 0) {
|
||||
// child
|
||||
char *argp[] = {"sh", "-c", as_root ? "su" : "sh", NULL};
|
||||
|
||||
close(in_p[1]);
|
||||
close(out_p[0]);
|
||||
|
||||
dup2(in_p[0], STDIN_FILENO);
|
||||
dup2(out_p[1], STDOUT_FILENO);
|
||||
dup2(out_p[1], STDERR_FILENO);
|
||||
|
||||
execve(_PATH_BSHELL, argp, environ);
|
||||
fprintf(stderr, "execve failed[%d]: %s", errno, strerror(errno));
|
||||
exit(1);
|
||||
} else if(pid > 0) {
|
||||
// parent
|
||||
int out = out_p[0];
|
||||
close(in_p[0]);
|
||||
close(out_p[1]);
|
||||
|
||||
// write "su" command input
|
||||
log_d("run_cmd[%d]: %s %s", pid, prog, args);
|
||||
write(in_p[1], prog, strlen(prog));
|
||||
write(in_p[1], " ", 1);
|
||||
write(in_p[1], args, strlen(args));
|
||||
write(in_p[1], "\n", 1);
|
||||
close(in_p[1]);
|
||||
|
||||
waitpid(pid, &rv, 0);
|
||||
|
||||
if(check_error && (rv != 0)) {
|
||||
char buf[128];
|
||||
struct timeval timeout = {0};
|
||||
fd_set fds;
|
||||
|
||||
buf[0] = '\0';
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(out, &fds);
|
||||
|
||||
select(out + 1, &fds, NULL, NULL, &timeout);
|
||||
if (FD_ISSET(out, &fds)) {
|
||||
int num = read(out, buf, sizeof(buf) - 1);
|
||||
if (num > 0)
|
||||
buf[num] = '\0';
|
||||
}
|
||||
|
||||
log_f("su \"%s\" invocation failed: %s", prog, buf);
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
close(out_p[0]);
|
||||
} else {
|
||||
log_f("fork() failed[%d]: %s", errno, strerror(errno));
|
||||
close(in_p[0]);
|
||||
close(in_p[1]);
|
||||
close(out_p[0]);
|
||||
close(out_p[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static void kill_pcapd(pcapdroid_t *nc) {
|
||||
int pid;
|
||||
char pid_s[8];
|
||||
@ -138,7 +58,7 @@ static void kill_pcapd(pcapdroid_t *nc) {
|
||||
|
||||
if(pid != 0) {
|
||||
log_d("Killing old pcapd with pid %d", pid);
|
||||
run_cmd("kill", pid_s, true, false);
|
||||
run_shell_cmd("kill", pid_s, true, false);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
@ -244,7 +164,7 @@ static int connectPcapd(pcapdroid_t *pd) {
|
||||
// Start the daemon
|
||||
char args[256];
|
||||
snprintf(args, sizeof(args), "-l pcapd.log -i '%s' -d -u %d -t -b '%s'", pd->root.capture_interface, pd->app_filter, bpf);
|
||||
if(run_cmd(pcapd, args, pd->root.as_root, true) != 0)
|
||||
if(run_shell_cmd(pcapd, args, pd->root.as_root, true) != 0)
|
||||
goto cleanup;
|
||||
|
||||
// Wait for pcapd to start
|
||||
|
||||
@ -793,6 +793,19 @@ Java_com_emanuelef_remote_1capture_CaptureService_nativeSetFirewallEnabled(JNIEn
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
JNIEXPORT int JNICALL
|
||||
Java_com_emanuelef_remote_1capture_CaptureService_rootCmd(JNIEnv *env, jclass clazz, jstring prog,
|
||||
jstring args) {
|
||||
const char *prog_s = (*env)->GetStringUTFChars(env, prog, 0);
|
||||
const char *args_s = (*env)->GetStringUTFChars(env, args, 0);
|
||||
int rv = run_shell_cmd(prog_s, args_s, true, true);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, prog, prog_s);
|
||||
(*env)->ReleaseStringUTFChars(env, args, args_s);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* getStringPref(pcapdroid_t *pd, const char *key, char *buf, int bufsize) {
|
||||
JNIEnv *env = pd->env;
|
||||
|
||||
@ -904,5 +917,4 @@ void getApplicationByUid(pcapdroid_t *pd, jint uid, char *buf, int bufsize) {
|
||||
if(obj) (*env)->DeleteLocalRef(env, obj);
|
||||
}
|
||||
|
||||
#endif // ANDROID
|
||||
|
||||
#endif // ANDROID
|
||||
@ -359,4 +359,6 @@
|
||||
<string name="app_intro_firewall_msg">With the integrated <a href='%1$s'>Firewall</a> you can easily block Internet access to individual apps and domains\n\nCombine this with the built-in traffic visibility to get the ultimate tool to protect your privacy</string>
|
||||
<string name="app_intro_malware_detection">Enhance the security of your device with the <a href='%1$s'>malware detection</a> feature\n\nBy using up-to-date blacklists, it can detect, block and alert malicious connections in real-time</string>
|
||||
<string name="app_intro_traffic_dump">PCAPdroid provides <a href='%1$s'>multiple ways</a> to dump the traffic in the standard PCAP format for further analysis\n\nVia the <a href='%2$s'>trailer option</a>, you can add app names to the packets and display them in Wireshark</string>
|
||||
<string name="permission_granted">%1$s permission was granted</string>
|
||||
<string name="permission_grant_fail">%1$s permission could not be granted</string>
|
||||
</resources>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user