diff --git a/app/src/full/AndroidManifest.xml b/app/src/full/AndroidManifest.xml
index 6b5b170f3..d07e9c31b 100644
--- a/app/src/full/AndroidManifest.xml
+++ b/app/src/full/AndroidManifest.xml
@@ -47,12 +47,19 @@
+
+
diff --git a/app/src/full/java/a/p.java b/app/src/full/java/a/p.java
new file mode 100644
index 000000000..479de2a43
--- /dev/null
+++ b/app/src/full/java/a/p.java
@@ -0,0 +1,7 @@
+package a;
+
+import com.topjohnwu.magisk.SuRequestActivity;
+
+public class p extends SuRequestActivity {
+ /* stub */
+}
diff --git a/app/src/full/java/com/topjohnwu/magisk/Const.java b/app/src/full/java/com/topjohnwu/magisk/Const.java
index fe49b1d8e..5630f064b 100644
--- a/app/src/full/java/com/topjohnwu/magisk/Const.java
+++ b/app/src/full/java/com/topjohnwu/magisk/Const.java
@@ -141,9 +141,6 @@ public class Const {
public static final int NAMESPACE_MODE_ISOLATE = 2;
public static final int NO_NOTIFICATION = 0;
public static final int NOTIFICATION_TOAST = 1;
- public static final int NOTIFY_NORMAL_LOG = 0;
- public static final int NOTIFY_USER_TOASTS = 1;
- public static final int NOTIFY_USER_TO_OWNER = 2;
public static final int SU_PROMPT = 0;
public static final int SU_AUTO_DENY = 1;
public static final int SU_AUTO_ALLOW = 2;
diff --git a/app/src/full/java/com/topjohnwu/magisk/Data.java b/app/src/full/java/com/topjohnwu/magisk/Data.java
index c73e561a0..865b90c05 100644
--- a/app/src/full/java/com/topjohnwu/magisk/Data.java
+++ b/app/src/full/java/com/topjohnwu/magisk/Data.java
@@ -87,6 +87,7 @@ public class Data {
classMap.put(OnBootService.class, a.m.class);
classMap.put(UpdateCheckService.class, a.n.class);
classMap.put(AboutCardRow.class, a.o.class);
+ classMap.put(SuRequestActivity.class, a.p.class);
}
diff --git a/app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java b/app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java
new file mode 100644
index 000000000..b86c04253
--- /dev/null
+++ b/app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java
@@ -0,0 +1,258 @@
+package com.topjohnwu.magisk;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.net.LocalSocketAddress;
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.os.FileObserver;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.Window;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.topjohnwu.magisk.components.BaseActivity;
+import com.topjohnwu.magisk.container.Policy;
+import com.topjohnwu.magisk.utils.FingerprintHelper;
+import com.topjohnwu.magisk.utils.SuConnector;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import androidx.annotation.Nullable;
+
+public class SuRequestActivity extends BaseActivity {
+ LinearLayout suPopup;
+ Spinner timeout;
+ ImageView appIcon;
+ TextView appNameView;
+ TextView packageNameView;
+ Button grant_btn;
+ Button deny_btn;
+ ImageView fingerprintImg;
+ TextView warning;
+
+ private SuConnector connector;
+ private Policy policy;
+ private CountDownTimer timer;
+ private FingerprintHelper fingerprintHelper;
+
+ class SuConnectorV1 extends SuConnector {
+
+ SuConnectorV1(String name) throws IOException {
+ socket.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.FILESYSTEM));
+ new FileObserver(name) {
+ @Override
+ public void onEvent(int fileEvent, String path) {
+ if (fileEvent == FileObserver.DELETE_SELF) {
+ finish();
+ }
+ }
+ }.startWatching();
+ }
+
+ @Override
+ public void response() {
+ try (OutputStream out = getOutputStream()) {
+ out.write((policy.policy == Policy.ALLOW ? "socket:ALLOW" : "socket:DENY").getBytes());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ class SuConnectorV2 extends SuConnector {
+
+ SuConnectorV2(String name) throws IOException {
+ socket.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.ABSTRACT));
+ }
+
+ @Override
+ public void response() {
+ try (DataOutputStream out = getOutputStream()) {
+ out.writeInt(policy.policy);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public int getDarkTheme() {
+ return R.style.SuRequest_Dark;
+ }
+
+ @Override
+ public void finish() {
+ if (timer != null)
+ timer.cancel();
+ if (fingerprintHelper != null)
+ fingerprintHelper.cancel();
+ super.finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (policy != null) {
+ handleAction(Policy.DENY);
+ } else {
+ finish();
+ }
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ PackageManager pm = getPackageManager();
+ mm.mDB.clearOutdated();
+
+ // Get policy
+ Intent intent = getIntent();
+ try {
+ connector = intent.getIntExtra("version", 1) == 1 ?
+ new SuConnectorV1(intent.getStringExtra("socket")) :
+ new SuConnectorV2(intent.getStringExtra("socket"));
+ Bundle bundle = connector.readSocketInput();
+ int uid = Integer.parseInt(bundle.getString("uid"));
+ policy = mm.mDB.getPolicy(uid);
+ if (policy == null) {
+ policy = new Policy(uid, pm);
+ }
+ } catch (IOException | PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ finish();
+ return;
+ }
+
+ // Never allow com.topjohnwu.magisk (could be malware)
+ if (TextUtils.equals(policy.packageName, Const.ORIG_PKG_NAME)) {
+ finish();
+ return;
+ }
+
+ switch (Data.suResponseType) {
+ case Const.Value.SU_AUTO_DENY:
+ handleAction(Policy.DENY, 0);
+ return;
+ case Const.Value.SU_AUTO_ALLOW:
+ handleAction(Policy.ALLOW, 0);
+ return;
+ case Const.Value.SU_PROMPT:
+ default:
+ }
+
+ // If not interactive, response directly
+ if (policy.policy != Policy.INTERACTIVE) {
+ handleAction();
+ return;
+ }
+
+ setContentView(R.layout.activity_request);
+ ViewBinder.bind(this);
+
+ appIcon.setImageDrawable(policy.info.loadIcon(pm));
+ appNameView.setText(policy.appName);
+ packageNameView.setText(policy.packageName);
+
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
+ R.array.allow_timeout, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ timeout.setAdapter(adapter);
+
+ timer = new CountDownTimer(Data.suRequestTimeout * 1000, 1000) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+ deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")"));
+ }
+ @Override
+ public void onFinish() {
+ deny_btn.setText(getString(R.string.deny_with_str, "(0)"));
+ handleAction(Policy.DENY);
+ }
+ };
+
+ boolean useFingerprint = Data.suFingerprint && FingerprintHelper.canUseFingerprint();
+
+ if (useFingerprint) {
+ try {
+ fingerprintHelper = new FingerprintHelper() {
+ @Override
+ public void onAuthenticationError(int errorCode, CharSequence errString) {
+ warning.setText(errString);
+ }
+
+ @Override
+ public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
+ warning.setText(helpString);
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
+ handleAction(Policy.ALLOW);
+ }
+
+ @Override
+ public void onAuthenticationFailed() {
+ warning.setText(R.string.auth_fail);
+ }
+ };
+ fingerprintHelper.authenticate();
+ } catch (Exception e) {
+ e.printStackTrace();
+ useFingerprint = false;
+ }
+ }
+
+ if (!useFingerprint) {
+ grant_btn.setOnClickListener(v -> {
+ handleAction(Policy.ALLOW);
+ timer.cancel();
+ });
+ grant_btn.requestFocus();
+ }
+
+ grant_btn.setVisibility(useFingerprint ? View.GONE : View.VISIBLE);
+ fingerprintImg.setVisibility(useFingerprint ? View.VISIBLE : View.GONE);
+
+ deny_btn.setOnClickListener(v -> {
+ handleAction(Policy.DENY);
+ timer.cancel();
+ });
+ suPopup.setOnClickListener(v -> cancelTimeout());
+ timeout.setOnTouchListener((v, event) -> cancelTimeout());
+ timer.start();
+ }
+
+ private boolean cancelTimeout() {
+ timer.cancel();
+ deny_btn.setText(getString(R.string.deny));
+ return false;
+ }
+
+ private void handleAction() {
+ connector.response();
+ finish();
+ }
+
+ private void handleAction(int action) {
+ handleAction(action, Const.Value.timeoutList[timeout.getSelectedItemPosition()]);
+ }
+
+ private void handleAction(int action, int time) {
+ policy.policy = action;
+ if (time >= 0) {
+ policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
+ mm.mDB.addPolicy(policy);
+ }
+ handleAction();
+ }
+}
diff --git a/app/src/full/java/com/topjohnwu/magisk/ViewBinder.java b/app/src/full/java/com/topjohnwu/magisk/ViewBinder.java
index 0d5f2c9dd..ecaf39dd1 100644
--- a/app/src/full/java/com/topjohnwu/magisk/ViewBinder.java
+++ b/app/src/full/java/com/topjohnwu/magisk/ViewBinder.java
@@ -18,7 +18,6 @@ import com.topjohnwu.magisk.fragments.ModulesFragment;
import com.topjohnwu.magisk.fragments.ReposFragment;
import com.topjohnwu.magisk.fragments.SuLogFragment;
import com.topjohnwu.magisk.fragments.SuperuserFragment;
-import com.topjohnwu.magisk.superuser.RequestActivity;
import androidx.core.content.ContextCompat;
@@ -56,8 +55,8 @@ public class ViewBinder {
target.findViewById(R.id.no_thanks).setOnClickListener(v -> target.finish());
target.findViewById(R.id.save_logs).setOnClickListener(v -> target.saveLogs());
}
-
- public static void bind(RequestActivity target) {
+
+ public static void bind(SuRequestActivity target) {
target.suPopup = target.findViewById(R.id.su_popup);
target.timeout = target.findViewById(R.id.timeout);
target.appIcon = target.findViewById(R.id.app_icon);
diff --git a/app/src/full/java/com/topjohnwu/magisk/receivers/BootReceiver.java b/app/src/full/java/com/topjohnwu/magisk/receivers/BootReceiver.java
index 11bb65b5f..75bf33616 100644
--- a/app/src/full/java/com/topjohnwu/magisk/receivers/BootReceiver.java
+++ b/app/src/full/java/com/topjohnwu/magisk/receivers/BootReceiver.java
@@ -5,14 +5,31 @@ import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
-import a.m;
+import com.topjohnwu.magisk.Data;
+import com.topjohnwu.magisk.SuRequestActivity;
+import com.topjohnwu.magisk.services.OnBootService;
+import com.topjohnwu.magisk.utils.SuConnector;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED))
- m.enqueueWork(context);
+ if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
+ switch (intent.getExtras().getString("action", "boot")) {
+ case "request":
+ Intent i = new Intent(context, Data.classMap.get(SuRequestActivity.class))
+ .putExtra("socket", intent.getStringExtra("socket"))
+ .putExtra("version", 2)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(i);
+ break;
+ case "log":
+ SuConnector.handleLogs(intent, 2);
+ break;
+ case "boot":
+ OnBootService.enqueueWork(context);
+ break;
+ }
+ }
}
-
}
diff --git a/app/src/full/java/com/topjohnwu/magisk/superuser/RequestActivity.java b/app/src/full/java/com/topjohnwu/magisk/superuser/RequestActivity.java
index 7dbedb57f..3f8a2cbde 100644
--- a/app/src/full/java/com/topjohnwu/magisk/superuser/RequestActivity.java
+++ b/app/src/full/java/com/topjohnwu/magisk/superuser/RequestActivity.java
@@ -1,295 +1,21 @@
package com.topjohnwu.magisk.superuser;
-import android.content.ContentValues;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.hardware.fingerprint.FingerprintManager;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.os.FileObserver;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.Window;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
-import android.widget.TextView;
-import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.Data;
-import com.topjohnwu.magisk.R;
-import com.topjohnwu.magisk.ViewBinder;
-import com.topjohnwu.magisk.asyncs.ParallelTask;
+import com.topjohnwu.magisk.SuRequestActivity;
import com.topjohnwu.magisk.components.BaseActivity;
-import com.topjohnwu.magisk.container.Policy;
-import com.topjohnwu.magisk.utils.FingerprintHelper;
-
-import java.io.DataInputStream;
-import java.io.IOException;
public class RequestActivity extends BaseActivity {
- public LinearLayout suPopup;
- public Spinner timeout;
- public ImageView appIcon;
- public TextView appNameView;
- public TextView packageNameView;
- public Button grant_btn;
- public Button deny_btn;
- public ImageView fingerprintImg;
- public TextView warning;
-
- private String socketPath;
- private LocalSocket socket;
- private PackageManager pm;
-
- private boolean hasTimeout;
- private Policy policy;
- private CountDownTimer timer;
- private FingerprintHelper fingerprintHelper;
-
- @Override
- public int getDarkTheme() {
- return R.style.SuRequest_Dark;
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
-
- pm = getPackageManager();
- mm.mDB.clearOutdated();
-
- Intent intent = getIntent();
- socketPath = intent.getStringExtra("socket");
- hasTimeout = intent.getBooleanExtra("timeout", true);
-
- new FileObserver(socketPath) {
- @Override
- public void onEvent(int fileEvent, String path) {
- if (fileEvent == FileObserver.DELETE_SELF) {
- finish();
- }
- }
- }.startWatching();
-
- new SocketManager(this).exec();
- }
-
- @Override
- public void finish() {
- if (timer != null)
- timer.cancel();
- if (fingerprintHelper != null)
- fingerprintHelper.cancel();
- super.finish();
- }
-
- private boolean cancelTimeout() {
- timer.cancel();
- deny_btn.setText(getString(R.string.deny));
- return false;
- }
-
- private void showRequest() {
- switch (Data.suResponseType) {
- case Const.Value.SU_AUTO_DENY:
- handleAction(Policy.DENY, 0);
- return;
- case Const.Value.SU_AUTO_ALLOW:
- handleAction(Policy.ALLOW, 0);
- return;
- case Const.Value.SU_PROMPT:
- default:
- }
-
- // If not interactive, response directly
- if (policy.policy != Policy.INTERACTIVE) {
- handleAction();
- return;
- }
-
- setContentView(R.layout.activity_request);
- ViewBinder.bind(this);
-
- appIcon.setImageDrawable(policy.info.loadIcon(pm));
- appNameView.setText(policy.appName);
- packageNameView.setText(policy.packageName);
-
- ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
- R.array.allow_timeout, android.R.layout.simple_spinner_item);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- timeout.setAdapter(adapter);
-
- timer = new CountDownTimer(Data.suRequestTimeout * 1000, 1000) {
- @Override
- public void onTick(long millisUntilFinished) {
- deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")"));
- }
- @Override
- public void onFinish() {
- deny_btn.setText(getString(R.string.deny_with_str, "(0)"));
- handleAction(Policy.DENY);
- }
- };
-
- boolean useFingerprint = Data.suFingerprint && FingerprintHelper.canUseFingerprint();
-
- if (useFingerprint) {
- try {
- fingerprintHelper = new FingerprintHelper() {
- @Override
- public void onAuthenticationError(int errorCode, CharSequence errString) {
- warning.setText(errString);
- }
-
- @Override
- public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
- warning.setText(helpString);
- }
-
- @Override
- public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
- handleAction(Policy.ALLOW);
- }
-
- @Override
- public void onAuthenticationFailed() {
- warning.setText(R.string.auth_fail);
- }
- };
- fingerprintHelper.authenticate();
- } catch (Exception e) {
- e.printStackTrace();
- useFingerprint = false;
- }
- }
-
- if (!useFingerprint) {
- grant_btn.setOnClickListener(v -> {
- handleAction(Policy.ALLOW);
- timer.cancel();
- });
- grant_btn.requestFocus();
- }
-
- grant_btn.setVisibility(useFingerprint ? View.GONE : View.VISIBLE);
- fingerprintImg.setVisibility(useFingerprint ? View.VISIBLE : View.GONE);
-
- deny_btn.setOnClickListener(v -> {
- handleAction(Policy.DENY);
- timer.cancel();
- });
- suPopup.setOnClickListener(v -> cancelTimeout());
- timeout.setOnTouchListener((v, event) -> cancelTimeout());
-
- if (hasTimeout) {
- timer.start();
- } else {
- cancelTimeout();
- }
- }
-
- @Override
- public void onBackPressed() {
- if (policy != null) {
- handleAction(Policy.DENY);
- } else {
- finish();
- }
- }
-
- void handleAction() {
- String response;
- if (policy.policy == Policy.ALLOW) {
- response = "socket:ALLOW";
- } else {
- response = "socket:DENY";
- }
- try {
- socket.getOutputStream().write((response).getBytes());
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ Intent intent = new Intent(this, Data.classMap.get(SuRequestActivity.class))
+ .putExtra("socket", getIntent().getStringExtra("socket"))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
finish();
}
-
- void handleAction(int action) {
- handleAction(action, Const.Value.timeoutList[timeout.getSelectedItemPosition()]);
- }
-
- void handleAction(int action, int time) {
- policy.policy = action;
- if (time >= 0) {
- policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
- mm.mDB.addPolicy(policy);
- }
- handleAction();
- }
-
- private class SocketManager extends ParallelTask {
-
- SocketManager(BaseActivity context) {
- super(context);
- }
-
- @Override
- protected Boolean doInBackground(Void... params) {
- try {
- socket = new LocalSocket();
- socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM));
-
- DataInputStream is = new DataInputStream(socket.getInputStream());
- ContentValues payload = new ContentValues();
-
- while (true) {
- int nameLen = is.readInt();
- byte[] nameBytes = new byte[nameLen];
- is.readFully(nameBytes);
- String name = new String(nameBytes);
- if (TextUtils.equals(name, "eof"))
- break;
-
- int dataLen = is.readInt();
- byte[] dataBytes = new byte[dataLen];
- is.readFully(dataBytes);
- String data = new String(dataBytes);
- payload.put(name, data);
- }
-
- if (payload.getAsInteger("uid") == null) {
- return false;
- }
-
- int uid = payload.getAsInteger("uid");
- policy = mm.mDB.getPolicy(uid);
- if (policy == null) {
- policy = new Policy(uid, pm);
- }
-
- /* Never allow com.topjohnwu.magisk (could be malware) */
- if (TextUtils.equals(policy.packageName, Const.ORIG_PKG_NAME))
- return false;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean result) {
- if (result) {
- showRequest();
- } else {
- finish();
- }
- }
- }
}
diff --git a/app/src/full/java/com/topjohnwu/magisk/superuser/SuReceiver.java b/app/src/full/java/com/topjohnwu/magisk/superuser/SuReceiver.java
index 5b055db3d..fe7198e68 100644
--- a/app/src/full/java/com/topjohnwu/magisk/superuser/SuReceiver.java
+++ b/app/src/full/java/com/topjohnwu/magisk/superuser/SuReceiver.java
@@ -3,88 +3,13 @@ package com.topjohnwu.magisk.superuser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Process;
-import android.widget.Toast;
-import com.topjohnwu.magisk.Const;
-import com.topjohnwu.magisk.Data;
-import com.topjohnwu.magisk.MagiskManager;
-import com.topjohnwu.magisk.R;
-import com.topjohnwu.magisk.container.Policy;
-import com.topjohnwu.magisk.container.SuLogEntry;
-import com.topjohnwu.magisk.utils.Utils;
-
-import java.util.Date;
+import com.topjohnwu.magisk.utils.SuConnector;
public class SuReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- int fromUid, toUid, pid, mode;
- String command, action;
- Policy policy;
-
- MagiskManager mm = Data.MM();
-
- if (intent == null) return;
-
- mode = intent.getIntExtra("mode", -1);
- if (mode < 0) return;
-
- if (mode == Const.Value.NOTIFY_USER_TO_OWNER) {
- Utils.toast(R.string.multiuser_hint_owner_request, Toast.LENGTH_LONG);
- return;
- }
-
- fromUid = intent.getIntExtra("from.uid", -1);
- if (fromUid < 0) return;
- if (fromUid == Process.myUid()) return; // Don't show anything if it's Magisk Manager
-
- action = intent.getStringExtra("action");
- if (action == null) return;
-
- policy = mm.mDB.getPolicy(fromUid);
- if (policy == null) {
- try {
- policy = new Policy(fromUid, mm.getPackageManager());
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- return;
- }
- }
-
- SuLogEntry log = new SuLogEntry(policy);
-
- String message;
- switch (action) {
- case "allow":
- message = mm.getString(R.string.su_allow_toast, policy.appName);
- log.action = true;
- break;
- case "deny":
- message = mm.getString(R.string.su_deny_toast, policy.appName);
- log.action = false;
- break;
- default:
- return;
- }
-
- if (policy.notification && Data.suNotificationType == Const.Value.NOTIFICATION_TOAST)
- Utils.toast(message, Toast.LENGTH_SHORT);
-
- if (mode == Const.Value.NOTIFY_NORMAL_LOG && policy.logging) {
- toUid = intent.getIntExtra("to.uid", -1);
- if (toUid < 0) return;
- pid = intent.getIntExtra("pid", -1);
- if (pid < 0) return;
- command = intent.getStringExtra("command");
- if (command == null) return;
- log.toUid = toUid;
- log.fromPid = pid;
- log.command = command;
- log.date = new Date();
- mm.mDB.addLog(log);
- }
+ SuConnector.handleLogs(intent, 1);
}
}
diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/SuConnector.java b/app/src/full/java/com/topjohnwu/magisk/utils/SuConnector.java
new file mode 100644
index 000000000..408aa35cf
--- /dev/null
+++ b/app/src/full/java/com/topjohnwu/magisk/utils/SuConnector.java
@@ -0,0 +1,118 @@
+package com.topjohnwu.magisk.utils;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.LocalSocket;
+import android.os.Bundle;
+import android.os.Process;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+import com.topjohnwu.magisk.Const;
+import com.topjohnwu.magisk.Data;
+import com.topjohnwu.magisk.MagiskManager;
+import com.topjohnwu.magisk.R;
+import com.topjohnwu.magisk.container.Policy;
+import com.topjohnwu.magisk.container.SuLogEntry;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Date;
+
+public abstract class SuConnector {
+
+ protected LocalSocket socket = new LocalSocket();
+
+ private String readString(DataInputStream is) throws IOException {
+ int len = is.readInt();
+ byte[] buf = new byte[len];
+ is.readFully(buf);
+ return new String(buf);
+ }
+
+ public Bundle readSocketInput() throws IOException {
+ Bundle bundle = new Bundle();
+ DataInputStream is = new DataInputStream(socket.getInputStream());
+ while (true) {
+ String name = readString(is);
+ if (TextUtils.equals(name, "eof"))
+ break;
+ bundle.putString(name, readString(is));
+ }
+ return bundle;
+ }
+
+ protected DataOutputStream getOutputStream() throws IOException {
+ return new DataOutputStream(socket.getOutputStream());
+ }
+
+ public abstract void response();
+
+ public static void handleLogs(Intent intent, int version) {
+ MagiskManager mm = Data.MM();
+
+ if (intent == null) return;
+
+ int fromUid = intent.getIntExtra("from.uid", -1);
+ if (fromUid < 0) return;
+ if (fromUid == Process.myUid()) return;
+
+ Policy policy = mm.mDB.getPolicy(fromUid);
+ if (policy == null) {
+ try {
+ policy = new Policy(fromUid, mm.getPackageManager());
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return;
+ }
+ }
+
+ SuLogEntry log = new SuLogEntry(policy);
+ if (version == 1) {
+ String action = intent.getStringExtra("action");
+ if (action == null) return;
+ switch (action) {
+ case "allow":
+ log.action = true;
+ break;
+ case "deny":
+ log.action = false;
+ break;
+ default:
+ return;
+ }
+ } else {
+ switch (intent.getIntExtra("policy", -1)) {
+ case Policy.ALLOW:
+ log.action = true;
+ break;
+ case Policy.DENY:
+ log.action = false;
+ break;
+ default:
+ return;
+ }
+ }
+
+ String message = mm.getString(log.action ?
+ R.string.su_allow_toast : R.string.su_deny_toast, policy.appName);
+
+ if (policy.notification && Data.suNotificationType == Const.Value.NOTIFICATION_TOAST)
+ Utils.toast(message, Toast.LENGTH_SHORT);
+
+ if (policy.logging) {
+ int toUid = intent.getIntExtra("to.uid", -1);
+ if (toUid < 0) return;
+ int pid = intent.getIntExtra("pid", -1);
+ if (pid < 0) return;
+ String command = intent.getStringExtra("command");
+ if (command == null) return;
+ log.toUid = toUid;
+ log.fromPid = pid;
+ log.command = command;
+ log.date = new Date();
+ mm.mDB.addLog(log);
+ }
+ }
+}
diff --git a/app/src/full/res/layout/activity_request.xml b/app/src/full/res/layout/activity_request.xml
index 10fa98672..d0348dd81 100644
--- a/app/src/full/res/layout/activity_request.xml
+++ b/app/src/full/res/layout/activity_request.xml
@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/su_popup"
- tools:context=".superuser.RequestActivity"
+ tools:context=".SuRequestActivity"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:minWidth="350dp"
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index ef01795f3..263317ed9 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -52,10 +52,9 @@ LOCAL_SRC_FILES := \
resetprop/system_property_api.cpp \
resetprop/system_property_set.cpp \
su/su.c \
- su/activity.c \
+ su/connect.c \
su/pts.c \
su/su_daemon.c \
- su/su_socket.c \
utils/img.c \
$(COMMON_UTILS)
diff --git a/native/jni/core/daemon.c b/native/jni/core/daemon.c
index a42054206..9560b40a6 100644
--- a/native/jni/core/daemon.c
+++ b/native/jni/core/daemon.c
@@ -111,9 +111,9 @@ void main_daemon() {
check_and_start_logger();
struct sockaddr_un sun;
- fd = setup_socket(&sun, MAIN_DAEMON);
-
- if (xbind(fd, (struct sockaddr*) &sun, sizeof(sun.sun_family) + strlen(sun.sun_path + 1) + 1))
+ socklen_t len = setup_sockaddr(&sun, MAIN_DAEMON);
+ fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (xbind(fd, (struct sockaddr*) &sun, len))
exit(1);
xlisten(fd, 10);
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n");
@@ -148,8 +148,8 @@ void main_daemon() {
/* Connect the daemon, set sockfd, and return if new daemon is spawned */
int connect_daemon2(daemon_t d, int *sockfd) {
struct sockaddr_un sun;
- *sockfd = setup_socket(&sun, d);
- socklen_t len = sizeof(sun.sun_family) + strlen(sun.sun_path + 1) + 1;
+ socklen_t len = setup_sockaddr(&sun, d);
+ *sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (connect(*sockfd, (struct sockaddr*) &sun, len)) {
if (getuid() != UID_ROOT || getgid() != UID_ROOT) {
fprintf(stderr, "No daemon is currently running!\n");
diff --git a/native/jni/core/log_daemon.c b/native/jni/core/log_daemon.c
index fbfd11a76..bf0594fa4 100644
--- a/native/jni/core/log_daemon.c
+++ b/native/jni/core/log_daemon.c
@@ -123,8 +123,9 @@ int check_and_start_logger() {
void log_daemon() {
setsid();
struct sockaddr_un sun;
- sockfd = setup_socket(&sun, LOG_DAEMON);
- if (xbind(sockfd, (struct sockaddr*) &sun, sizeof(sun.sun_family) + strlen(sun.sun_path + 1) + 1))
+ socklen_t len = setup_sockaddr(&sun, LOG_DAEMON);
+ sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (xbind(sockfd, (struct sockaddr*) &sun, len))
exit(1);
xlisten(sockfd, 10);
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") logger started\n");
diff --git a/native/jni/core/socket.c b/native/jni/core/socket.c
index 8c93d78b8..23673c334 100644
--- a/native/jni/core/socket.c
+++ b/native/jni/core/socket.c
@@ -2,18 +2,18 @@
*/
#include
+#include
#include "daemon.h"
#include "logging.h"
#include "utils.h"
#include "magisk.h"
-/* Setup the address and return socket fd */
-int setup_socket(struct sockaddr_un *sun, daemon_t d) {
- int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+#define ABS_SOCKET_LEN(sun) (sizeof(sun->sun_family) + strlen(sun->sun_path + 1) + 1)
+
+socklen_t setup_sockaddr(struct sockaddr_un *sun, daemon_t d) {
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_LOCAL;
- sun->sun_path[0] = '\0';
const char *name;
switch (d) {
case MAIN_DAEMON:
@@ -24,9 +24,39 @@ int setup_socket(struct sockaddr_un *sun, daemon_t d) {
break;
}
strcpy(sun->sun_path + 1, name);
+ return ABS_SOCKET_LEN(sun);
+}
+
+int create_rand_socket(struct sockaddr_un *sun) {
+ memset(sun, 0, sizeof(*sun));
+ sun->sun_family = AF_LOCAL;
+ gen_rand_str(sun->sun_path + 1, 9);
+ int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ xbind(fd, (struct sockaddr*) sun, ABS_SOCKET_LEN(sun));
+ xlisten(fd, 1);
return fd;
}
+int socket_accept(int serv_fd, int timeout) {
+ struct timeval tv;
+ fd_set fds;
+ int rc;
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ FD_ZERO(&fds);
+ FD_SET(serv_fd, &fds);
+ do {
+ rc = select(serv_fd + 1, &fds, NULL, NULL, &tv);
+ } while (rc < 0 && errno == EINTR);
+ if (rc < 1) {
+ PLOGE("select");
+ exit(-1);
+ }
+
+ return xaccept4(serv_fd, NULL, NULL, SOCK_CLOEXEC);
+}
+
/*
* Receive a file descriptor from a Unix socket.
* Contributed by @mkasick
@@ -136,26 +166,59 @@ int read_int(int fd) {
return val;
}
+int read_int_be(int fd) {
+ uint32_t val;
+ xxread(fd, &val, sizeof(val));
+ return ntohl(val);
+}
+
void write_int(int fd, int val) {
if (fd < 0) return;
xwrite(fd, &val, sizeof(int));
}
-char* read_string(int fd) {
- int len = read_int(fd);
- if (len > PATH_MAX || len < 0) {
- LOGE("invalid string length %d", len);
- exit(1);
- }
+void write_int_be(int fd, int val) {
+ uint32_t nl = htonl(val);
+ xwrite(fd, &nl, sizeof(nl));
+}
+
+static char *rd_str(int fd, int len) {
char* val = xmalloc(sizeof(char) * (len + 1));
xxread(fd, val, len);
val[len] = '\0';
return val;
}
-void write_string(int fd, const char* val) {
+char* read_string(int fd) {
+ int len = read_int(fd);
+ return rd_str(fd, len);
+}
+
+char* read_string_be(int fd) {
+ int len = read_int_be(fd);
+ return rd_str(fd, len);
+}
+
+void write_string(int fd, const char *val) {
if (fd < 0) return;
int len = strlen(val);
write_int(fd, len);
xwrite(fd, val, len);
}
+
+void write_string_be(int fd, const char *val) {
+ int len = strlen(val);
+ write_int_be(fd, len);
+ xwrite(fd, val, len);
+}
+
+void write_key_value(int fd, const char *key, const char *val) {
+ write_string_be(fd, key);
+ write_string_be(fd, val);
+}
+
+void write_key_token(int fd, const char *key, int tok) {
+ char val[16];
+ sprintf(val, "%d", tok);
+ write_key_value(fd, key, val);
+}
diff --git a/native/jni/include/daemon.h b/native/jni/include/daemon.h
index d93f5f8ad..0d20ef223 100644
--- a/native/jni/include/daemon.h
+++ b/native/jni/include/daemon.h
@@ -59,13 +59,21 @@ int check_and_start_logger();
// socket.c
-int setup_socket(struct sockaddr_un *sun, daemon_t d);
+socklen_t setup_sockaddr(struct sockaddr_un *sun, daemon_t d);
+int create_rand_socket(struct sockaddr_un *sun);
+int socket_accept(int serv_fd, int timeout);
int recv_fd(int sockfd);
void send_fd(int sockfd, int fd);
int read_int(int fd);
+int read_int_be(int fd);
void write_int(int fd, int val);
-char* read_string(int fd);
-void write_string(int fd, const char* val);
+void write_int_be(int fd, int val);
+char *read_string(int fd);
+char *read_string_be(int fd);
+void write_string(int fd, const char *val);
+void write_string_be(int fd, const char *val);
+void write_key_value(int fd, const char *key, const char *val);
+void write_key_token(int fd, const char *key, int tok);
/***************
* Boot Stages *
diff --git a/native/jni/su/activity.c b/native/jni/su/activity.c
deleted file mode 100644
index 9058fa1b1..000000000
--- a/native/jni/su/activity.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
-** Copyright 2017, John Wu (@topjohnwu)
-** Copyright 2010, Adam Shanks (@ChainsDD)
-** Copyright 2008, Zinx Verituse (@zinxv)
-**
-*/
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "magisk.h"
-#include "su.h"
-
-/* intent actions */
-#define ACTION_REQUEST "%s/" REQUESTOR_PREFIX ".RequestActivity"
-#define ACTION_RESULT "%s/" REQUESTOR_PREFIX ".SuReceiver"
-
-#define AM_PATH "/system/bin/app_process", "/system/bin", "com.android.commands.am.Am"
-
-static char *get_command(const struct su_request *to) {
- if (to->command)
- return to->command;
- if (to->shell)
- return to->shell;
- return DEFAULT_SHELL;
-}
-
-static void silent_run(char* const args[]) {
- set_identity(0);
- if (fork())
- return;
- int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
- dup2(zero, 0);
- int null = open("/dev/null", O_WRONLY | O_CLOEXEC);
- dup2(null, 1);
- dup2(null, 2);
- setenv("CLASSPATH", "/system/framework/am.jar", 1);
- execv(args[0], args);
- PLOGE("exec am");
- _exit(EXIT_FAILURE);
-}
-
-static int setup_user(struct su_context *ctx, char* user) {
- switch (ctx->info->dbs.v[SU_MULTIUSER_MODE]) {
- case MULTIUSER_MODE_OWNER_ONLY: /* Should already be denied if not owner */
- case MULTIUSER_MODE_OWNER_MANAGED:
- sprintf(user, "%d", 0);
- return ctx->info->uid / 100000;
- case MULTIUSER_MODE_USER:
- sprintf(user, "%d", ctx->info->uid / 100000);
- break;
- }
- return 0;
-}
-
-void app_send_result(struct su_context *ctx, policy_t policy) {
- char fromUid[16];
- if (ctx->info->dbs.v[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED)
- sprintf(fromUid, "%d", ctx->info->uid % 100000);
- else
- sprintf(fromUid, "%d", ctx->info->uid);
-
- char toUid[16];
- sprintf(toUid, "%d", ctx->to.uid);
-
- char pid[16];
- sprintf(pid, "%d", ctx->pid);
-
- char user[16];
- int notify = setup_user(ctx, user);
-
- char activity[128];
- sprintf(activity, ACTION_RESULT, ctx->info->str.s[SU_MANAGER]);
-
- // Send notice to manager, enable logging
- char *result_command[] = {
- AM_PATH, "broadcast", "-n",
- activity,
- "--user", user,
- "--ei", "mode", "0",
- "--ei", "from.uid", fromUid,
- "--ei", "to.uid", toUid,
- "--ei", "pid", pid,
- "--es", "command", get_command(&ctx->to),
- "--es", "action", policy == ALLOW ? "allow" : "deny",
- NULL
- };
- silent_run(result_command);
-
- // Send notice to user (if needed) to create toasts
- if (notify) {
- sprintf(fromUid, "%d", ctx->info->uid);
- sprintf(user, "%d", notify);
- char *notify_command[] = {
- AM_PATH, "broadcast", "-n",
- activity,
- "--user", user,
- "--ei", "mode", "1",
- "--ei", "from.uid", fromUid,
- "--es", "action", policy == ALLOW ? "allow" : "deny",
- NULL
- };
- silent_run(notify_command);
- }
-}
-
-void app_send_request(struct su_context *ctx) {
- char user[16];
- int notify = setup_user(ctx, user);
-
- char activity[128];
- sprintf(activity, ACTION_REQUEST, ctx->info->str.s[SU_MANAGER]);
-
- char *request_command[] = {
- AM_PATH, "start", "-n",
- activity,
- "--user", user,
- "--es", "socket", ctx->sock_path,
- "--ez", "timeout", notify ? "false" : "true",
- NULL
- };
- silent_run(request_command);
-
- // Send notice to user to tell them root is managed by owner
- if (notify) {
- sprintf(user, "%d", notify);
- sprintf(activity, ACTION_RESULT, ctx->info->str.s[SU_MANAGER]);
- char *notify_command[] = {
- AM_PATH, "broadcast", "-n",
- activity,
- "--user", user,
- "--ei", "mode", "2",
- NULL
- };
- silent_run(notify_command);
- }
-}
diff --git a/native/jni/su/connect.c b/native/jni/su/connect.c
new file mode 100644
index 000000000..8197d1045
--- /dev/null
+++ b/native/jni/su/connect.c
@@ -0,0 +1,109 @@
+/*
+** Copyright 2018, John Wu (@topjohnwu)
+** Copyright 2010, Adam Shanks (@ChainsDD)
+** Copyright 2008, Zinx Verituse (@zinxv)
+**
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "magisk.h"
+#include "daemon.h"
+#include "su.h"
+
+#define AM_PATH "/system/bin/app_process", "/system/bin", "com.android.commands.am.Am"
+
+static char *get_command(const struct su_request *to) {
+ if (to->command)
+ return to->command;
+ if (to->shell)
+ return to->shell;
+ return DEFAULT_SHELL;
+}
+
+static void silent_run(char * const args[]) {
+ set_identity(0);
+ if (fork())
+ return;
+ int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
+ dup2(zero, 0);
+ int null = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ dup2(null, 1);
+ dup2(null, 2);
+ setenv("CLASSPATH", "/system/framework/am.jar", 1);
+ execv(args[0], args);
+ PLOGE("exec am");
+ _exit(EXIT_FAILURE);
+}
+
+static void setup_user(char *user) {
+ switch (su_ctx->info->dbs.v[SU_MULTIUSER_MODE]) {
+ case MULTIUSER_MODE_OWNER_ONLY:
+ case MULTIUSER_MODE_OWNER_MANAGED:
+ sprintf(user, "%d", 0);
+ break;
+ case MULTIUSER_MODE_USER:
+ sprintf(user, "%d", su_ctx->info->uid / 100000);
+ break;
+ }
+}
+
+void app_log() {
+ char user[8];
+ setup_user(user);
+
+ char fromUid[8];
+ sprintf(fromUid, "%d",
+ su_ctx->info->dbs.v[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED ?
+ su_ctx->info->uid % 100000 : su_ctx->info->uid);
+
+ char toUid[8];
+ sprintf(toUid, "%d", su_ctx->to.uid);
+
+ char pid[8];
+ sprintf(pid, "%d", su_ctx->pid);
+
+ char policy[2];
+ sprintf(policy, "%d", su_ctx->info->access.policy);
+
+ char *cmd[] = {
+ AM_PATH, "broadcast",
+ "-a", "android.intent.action.BOOT_COMPLETED",
+ "-p", su_ctx->info->str.s[SU_MANAGER],
+ "--user", user,
+ "--es", "action", "log",
+ "--ei", "from.uid", fromUid,
+ "--ei", "to.uid", toUid,
+ "--ei", "pid", pid,
+ "--ei", "policy", policy,
+ "--es", "command", get_command(&su_ctx->to),
+ NULL
+ };
+ silent_run(cmd);
+}
+
+void app_connect(const char *socket) {
+ char user[8];
+ setup_user(user);
+ char *cmd[] = {
+ AM_PATH, "broadcast",
+ "-a", "android.intent.action.BOOT_COMPLETED",
+ "-p", su_ctx->info->str.s[SU_MANAGER],
+ "--user", user,
+ "--es", "action", "request",
+ "--es", "socket", (char *) socket,
+ NULL
+ };
+ silent_run(cmd);
+}
+
+void socket_send_request(int fd) {
+ write_key_token(fd, "uid", su_ctx->info->uid);
+ write_string_be(fd, "eof");
+}
+
diff --git a/native/jni/su/su.c b/native/jni/su/su.c
index 569694223..44439e8a1 100644
--- a/native/jni/su/su.c
+++ b/native/jni/su/su.c
@@ -25,6 +25,7 @@
#include
#include "magisk.h"
+#include "daemon.h"
#include "utils.h"
#include "su.h"
@@ -44,11 +45,9 @@ static void usage(int status) {
" --preserve-environment preserve the entire environment\n"
" -s, --shell SHELL use SHELL instead of the default " DEFAULT_SHELL "\n"
" -v, --version display version number and exit\n"
- " -V display version code and exit,\n"
- " this is used almost exclusively by Superuser.apk\n"
+ " -V display version code and exit\n"
" -mm, -M,\n"
- " --mount-master run in the global mount namespace,\n"
- " use if you need to publicly apply mounts\n");
+ " --mount-master force run in the global mount namespace\n");
exit2(status);
}
@@ -64,20 +63,20 @@ static char *concat_commands(int argc, char *argv[]) {
return strdup(command);
}
-static void populate_environment(const struct su_context *ctx) {
+static void populate_environment() {
struct passwd *pw;
- if (ctx->to.keepenv)
+ if (su_ctx->to.keepenv)
return;
- pw = getpwuid(ctx->to.uid);
+ pw = getpwuid(su_ctx->to.uid);
if (pw) {
setenv("HOME", pw->pw_dir, 1);
- if (ctx->to.shell)
- setenv("SHELL", ctx->to.shell, 1);
+ if (su_ctx->to.shell)
+ setenv("SHELL", su_ctx->to.shell, 1);
else
setenv("SHELL", DEFAULT_SHELL, 1);
- if (ctx->to.login || ctx->to.uid) {
+ if (su_ctx->to.login || su_ctx->to.uid) {
setenv("USER", pw->pw_name, 1);
setenv("LOGNAME", pw->pw_name, 1);
}
@@ -103,9 +102,6 @@ void set_identity(unsigned uid) {
static __attribute__ ((noreturn)) void allow() {
char* argv[] = { NULL, NULL, NULL, NULL };
- if (su_ctx->info->access.notify || su_ctx->info->access.log)
- app_send_result(su_ctx, ALLOW);
-
if (su_ctx->to.login)
argv[0] = "-";
else
@@ -118,9 +114,12 @@ static __attribute__ ((noreturn)) void allow() {
// Setup shell
umask(022);
- populate_environment(su_ctx);
+ populate_environment();
set_identity(su_ctx->to.uid);
+ if (su_ctx->info->access.notify || su_ctx->info->access.log)
+ app_log();
+
execvp(su_ctx->to.shell, argv);
fprintf(stderr, "Cannot execute %s: %s\n", su_ctx->to.shell, strerror(errno));
PLOGE("exec");
@@ -129,25 +128,13 @@ static __attribute__ ((noreturn)) void allow() {
static __attribute__ ((noreturn)) void deny() {
if (su_ctx->info->access.notify || su_ctx->info->access.log)
- app_send_result(su_ctx, DENY);
+ app_log();
LOGW("su: request rejected (%u->%u)", su_ctx->info->uid, su_ctx->to.uid);
fprintf(stderr, "%s\n", strerror(EACCES));
exit(EXIT_FAILURE);
}
-static void socket_cleanup() {
- if (su_ctx && su_ctx->sock_path[0]) {
- unlink(su_ctx->sock_path);
- su_ctx->sock_path[0] = '\0';
- }
-}
-
-static void cleanup_signal(int sig) {
- socket_cleanup();
- exit2(EXIT_FAILURE);
-}
-
__attribute__ ((noreturn)) void exit2(int status) {
// Handle the pipe, or the daemon will get stuck
if (su_ctx->pipefd[0] >= 0) {
@@ -159,8 +146,7 @@ __attribute__ ((noreturn)) void exit2(int status) {
}
int su_daemon_main(int argc, char **argv) {
- int c, socket_serv_fd, fd;
- char result[64];
+ int c;
struct option long_opts[] = {
{ "command", required_argument, NULL, 'c' },
{ "help", no_argument, NULL, 'h' },
@@ -247,28 +233,20 @@ int su_daemon_main(int argc, char **argv) {
// Change directory to cwd
chdir(su_ctx->cwd);
- // New request or no db exist, notify user for response
if (su_ctx->pipefd[0] >= 0) {
- socket_serv_fd = socket_create_temp(su_ctx->sock_path, sizeof(su_ctx->sock_path));
- setup_sighandlers(cleanup_signal);
+ // Create random socket
+ struct sockaddr_un addr;
+ int sockfd = create_rand_socket(&addr);
- // Start activity
- app_send_request(su_ctx);
+ // Connect Magisk Manager
+ app_connect(addr.sun_path + 1);
+ int fd = socket_accept(sockfd, 60);
- atexit(socket_cleanup);
-
- fd = socket_accept(socket_serv_fd);
- socket_send_request(fd, su_ctx);
- socket_receive_result(fd, result, sizeof(result));
+ socket_send_request(fd);
+ su_ctx->info->access.policy = read_int_be(fd);
close(fd);
- close(socket_serv_fd);
- socket_cleanup();
-
- if (strcmp(result, "socket:ALLOW") == 0)
- su_ctx->info->access.policy = ALLOW;
- else
- su_ctx->info->access.policy = DENY;
+ close(sockfd);
// Report the policy to main daemon
xwrite(su_ctx->pipefd[1], &su_ctx->info->access.policy, sizeof(policy_t));
@@ -276,9 +254,6 @@ int su_daemon_main(int argc, char **argv) {
close(su_ctx->pipefd[1]);
}
- if (su_ctx->info->access.policy == ALLOW)
- allow();
- else
- deny();
+ su_ctx->info->access.policy == ALLOW ? allow() : deny();
}
diff --git a/native/jni/su/su.h b/native/jni/su/su.h
index 43c936c19..28abb67b5 100644
--- a/native/jni/su/su.h
+++ b/native/jni/su/su.h
@@ -12,11 +12,6 @@
#include "list.h"
#define MAGISKSU_VER_STR xstr(MAGISK_VERSION) ":MAGISKSU (topjohnwu)"
-
-// This is used if wrapping the fragment classes and activities
-// with classes in another package.
-#define REQUESTOR_PREFIX JAVA_PACKAGE_NAME ".superuser"
-
#define DEFAULT_SHELL "/system/bin/sh"
struct su_info {
@@ -49,7 +44,6 @@ struct su_context {
struct su_request to;
pid_t pid;
char cwd[PATH_MAX];
- char sock_path[PATH_MAX];
int pipefd[2];
};
@@ -61,16 +55,11 @@ int su_daemon_main(int argc, char **argv);
__attribute__ ((noreturn)) void exit2(int status);
void set_identity(unsigned uid);
-// su_client.c
+// connect.c
-int socket_create_temp(char *path, size_t len);
-int socket_accept(int serv_fd);
-void socket_send_request(int fd, const struct su_context *ctx);
-void socket_receive_result(int fd, char *result, ssize_t result_len);
+void app_log();
-// activity.c
-
-void app_send_result(struct su_context *ctx, policy_t policy);
-void app_send_request(struct su_context *ctx);
+void app_connect(const char *socket);
+void socket_send_request(int fd);
#endif
diff --git a/native/jni/su/su_socket.c b/native/jni/su/su_socket.c
deleted file mode 100644
index 28b2e18bd..000000000
--- a/native/jni/su/su_socket.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/* su_socket.c - Functions for communication to client
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "magisk.h"
-#include "utils.h"
-#include "su.h"
-#include "magiskpolicy.h"
-
-int socket_create_temp(char *path, size_t len) {
- int fd;
- struct sockaddr_un sun;
-
- fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
- PLOGE("fcntl FD_CLOEXEC");
- }
-
- memset(&sun, 0, sizeof(sun));
- sun.sun_family = AF_LOCAL;
- snprintf(path, len, "/dev/.socket%d", getpid());
- strcpy(sun.sun_path, path);
-
- /*
- * Delete the socket to protect from situations when
- * something bad occured previously and the kernel reused pid from that process.
- * Small probability, isn't it.
- */
- unlink(path);
-
- xbind(fd, (struct sockaddr*) &sun, sizeof(sun));
- xlisten(fd, 1);
-
- // Set attributes so requester can access it
- setfilecon(path, "u:object_r:"SEPOL_FILE_DOMAIN":s0");
- chown(path, su_ctx->info->manager_stat.st_uid, su_ctx->info->manager_stat.st_gid);
-
- return fd;
-}
-
-int socket_accept(int serv_fd) {
- struct timeval tv;
- fd_set fds;
- int rc;
-
- /* Wait 60 seconds for a connection, then give up. */
- tv.tv_sec = 60;
- tv.tv_usec = 0;
- FD_ZERO(&fds);
- FD_SET(serv_fd, &fds);
- do {
- rc = select(serv_fd + 1, &fds, NULL, NULL, &tv);
- } while (rc < 0 && errno == EINTR);
- if (rc < 1) {
- PLOGE("select");
- }
-
- return xaccept4(serv_fd, NULL, NULL, SOCK_CLOEXEC);
-}
-
-#define write_data(fd, data, data_len) \
-do { \
- uint32_t __len = htonl(data_len); \
- __len = write((fd), &__len, sizeof(__len)); \
- if (__len != sizeof(__len)) { \
- PLOGE("write(" #data ")"); \
- } \
- __len = write((fd), data, data_len); \
- if (__len != data_len) { \
- PLOGE("write(" #data ")"); \
- } \
-} while (0)
-
-#define write_string_data(fd, name, data) \
-do { \
- write_data(fd, name, strlen(name)); \
- write_data(fd, data, strlen(data)); \
-} while (0)
-
-// stringify everything.
-#define write_token(fd, name, data) \
-do { \
- char buf[16]; \
- snprintf(buf, sizeof(buf), "%d", data); \
- write_string_data(fd, name, buf); \
-} while (0)
-
-void socket_send_request(int fd, const struct su_context *ctx) {
- write_token(fd, "uid", ctx->info->uid);
- write_token(fd, "eof", 1);
-}
-
-void socket_receive_result(int fd, char *result, ssize_t result_len) {
- ssize_t len;
- len = xread(fd, result, result_len - 1);
- result[len] = '\0';
-}