su: fix binary so Superuser always gets access, even if root is disabled. Obviously need this to reenabled root.
Check superuser binary version.
Change-Id: I39a667a001cb8f1e3e1f2876f4e4c874579cdc81
read_options(&ctx);
user_init(&ctx);
- if (ctx.user.multiuser_mode == MULTIUSER_MODE_OWNER_ONLY && ctx.user.android_user_id != 0) {
- deny(&ctx);
- }
-
- if (access_disabled(&ctx.from)) {
- LOGD("access_disabled");
- deny(&ctx);
- }
-
- ctx.umask = umask(027);
-
- if (ctx.from.uid == AID_ROOT || ctx.from.uid == AID_SHELL) {
- LOGD("Allowing root/shell.");
- allow(&ctx);
- }
-
+ // verify superuser is installed
if (stat(ctx.user.base_path, &st) < 0) {
+ // send to market
silent_run("am start -d market://details?id=" JAVA_PACKAGE_NAME);
PLOGE("stat %s", ctx.user.base_path);
deny(&ctx);
}
+ // odd perms on superuser data dir
if (st.st_gid != st.st_uid) {
LOGE("Bad uid/gid %d/%d for Superuser Requestor application",
(int)st.st_uid, (int)st.st_gid);
deny(&ctx);
}
+ // always allow if this is the superuser uid
+ // superuser needs to be able to reenable itself when disabled...
if (ctx.from.uid == st.st_uid) {
- // automatically grant the superuser app itself
+ allow(&ctx);
+ }
+
+ // check if superuser is disabled completely
+ if (access_disabled(&ctx.from)) {
+ LOGD("access_disabled");
+ deny(&ctx);
+ }
+
+ // deny if this is a non owner request and owner mode only
+ if (ctx.user.multiuser_mode == MULTIUSER_MODE_OWNER_ONLY && ctx.user.android_user_id != 0) {
+ deny(&ctx);
+ }
+
+ ctx.umask = umask(027);
+
+ // TODO: customizable behavior for shell? It can currently be toggled via settings.
+ if (ctx.from.uid == AID_ROOT || ctx.from.uid == AID_SHELL) {
+ LOGD("Allowing root/shell.");
allow(&ctx);
}
#define xstr(a) str(a)
#define str(a) #a
-#define VERSION_CODE 1
+#define VERSION_CODE 2
#define VERSION xstr(VERSION_CODE) " " REQUESTOR
#define PROTO_VERSION 1
<attr name="bottomButtonBar" format="reference|color" />
<attr name="bottomButtonBarText" format="reference|color" />
+ <attr name="toggleIcon" format="reference|color" />
<attr name="multiuserIcon" format="reference|color" />
<attr name="declaredPermissionsIcon" format="reference|color" />
<attr name="automaticResponseIcon" format="reference|color" />
<string name="install_error">There was an error installing Superuser. Please send a log of the error to the developer.</string>
<string name="install_success">Installation of Superuser was successful.</string>
<string name="su_binary_outdated">The su binary is out of date.</string>
+ <string name="superuser_access">Superuser Access</string>
+ <string name="disabled">Disabled</string>
+ <string name="apps_only">Apps only</string>
+ <string name="adb_only">ADB only</string>
+ <string name="apps_and_adb">Apps and ADB</string>
</resources>
<item name="bottomButtonBar">@null</item>
<item name="bottomButtonBarText">?android:attr/textColorPrimary</item>
+ <item name="toggleIcon">@drawable/ic_toggle_dark</item>
<item name="multiuserIcon">@drawable/ic_users_dark</item>
<item name="declaredPermissionsIcon">@drawable/ic_declare_dark</item>
<item name="automaticResponseIcon">@drawable/ic_alert_dark</item>
<item name="bottomButtonBar">@color/background_dark</item>
<item name="bottomButtonBarText">?android:attr/textColorPrimaryInverse</item>
+ <item name="toggleIcon">@drawable/ic_toggle</item>
<item name="multiuserIcon">@drawable/ic_users</item>
<item name="declaredPermissionsIcon">@drawable/ic_declare</item>
<item name="automaticResponseIcon">@drawable/ic_alert</item>
protected int getListFragmentResource() {
return R.layout.settings;
}
-
-// static final int containerId = 100001;
-// public static class MyPinFragment extends DialogFragment {
-// public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-// FrameLayout ret = new FrameLayout(getActivity());
-// ret.setId(containerId);
-// return ret;
-// };
-//
-// private int title;
-// public void setTitle(int title) {
-// this.title = title;
-// }
-//
-// Dialog d;
-// @Override
-// public Dialog onCreateDialog(Bundle savedInstanceState) {
-// d = super.onCreateDialog(savedInstanceState);
-// d.setTitle(title);
-// PinView pf = new PinView() {
-// @Override
-// public void onCancel() {
-// super.onCancel();
-// d.dismiss();
-// }
-//
-// @Override
-// public void onEnter(String password) {
-// super.onEnter(password);
-// MyPinFragment.this.onEnter(password);
-// }
-// };
-// getChildFragmentManager().beginTransaction().add(containerId, pf).commit();
-//
-// return d;
-// }
-//
-// public void onEnter(String password) {
-// d.dismiss();
-// }
-// };
ListItem pinItem;
void confirmPin(final String pin) {
protected void onCreate(Bundle savedInstanceState, View view) {
super.onCreate(savedInstanceState, view);
+ // NOTE to future koush
+ // dark icons use the color #f3f3f3
+
+ addItem(R.string.security, new ListItem(this, R.string.superuser_access, 0, 0) {
+ void update() {
+ switch (Settings.getSuperuserAccess()) {
+ case Settings.SUPERUSER_ACCESS_ADB_ONLY:
+ setSummary(R.string.adb_only);
+ break;
+ case Settings.SUPERUSER_ACCESS_APPS_ONLY:
+ setSummary(R.string.apps_only);
+ break;
+ case Settings.SUPERUSER_ACCESS_APPS_AND_ADB:
+ setSummary(R.string.apps_and_adb);
+ break;
+ case Settings.SUPERUSER_ACCESS_DISABLED:
+ setSummary(R.string.disabled);
+ break;
+ default:
+ setSummary(R.string.apps_and_adb);
+ break;
+ }
+ }
+ {
+ update();
+ }
+
+ @Override
+ public void onClick(View view) {
+ super.onClick(view);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.superuser_access);
+ String[] items = new String[] { getString(R.string.disabled), getString(R.string.apps_only), getString(R.string.adb_only), getString(R.string.apps_and_adb) };
+ builder.setItems(items, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case 0:
+ Settings.setSuperuserAccess(Settings.SUPERUSER_ACCESS_DISABLED);
+ break;
+ case 1:
+ Settings.setSuperuserAccess(Settings.SUPERUSER_ACCESS_APPS_ONLY);
+ break;
+ case 2:
+ Settings.setSuperuserAccess(Settings.SUPERUSER_ACCESS_ADB_ONLY);
+ break;
+ case 3:
+ Settings.setSuperuserAccess(Settings.SUPERUSER_ACCESS_APPS_AND_ADB);
+ break;
+ }
+ update();
+ }
+ });
+ builder.create().show();
+ }
+ }).setAttrDrawable(R.attr.toggleIcon);
+
if (Settings.getMultiuserMode(getActivity()) != Settings.MULTIUSER_MODE_NONE) {
addItem(R.string.security, new ListItem(this, R.string.multiuser_policy, 0) {
void update() {
public static ArrayList<UidPolicy> getPolicies(Context context) {
ArrayList<UidPolicy> ret = new ArrayList<UidPolicy>();
SQLiteDatabase db = new SuDatabaseHelper(context).getReadableDatabase();
+
+ db.delete("uid_policy", "until > 0 and until < ?", new String[] { String.valueOf(System.currentTimeMillis()) });
+
Cursor c = db.query("uid_policy", null, null, null, null, null, null);
try {
while (c.moveToNext()) {
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Method;
import java.security.MessageDigest;
import android.content.ContentValues;
}
}
+
+ public static final int SUPERUSER_ACCESS_DISABLED = 0;
+ public static final int SUPERUSER_ACCESS_APPS_ONLY = 1;
+ public static final int SUPERUSER_ACCESS_ADB_ONLY = 2;
+ public static final int SUPERUSER_ACCESS_APPS_AND_ADB = 3;
+ public static int getSuperuserAccess() {
+ try {
+ Class c = Class.forName("android.os.SystemProperties");
+ Method m = c.getMethod("get", String.class);
+ String value = (String)m.invoke(null, "persist.sys.root_access");
+ int val = Integer.valueOf(value);
+ switch (val) {
+ case SUPERUSER_ACCESS_DISABLED:
+ case SUPERUSER_ACCESS_APPS_ONLY:
+ case SUPERUSER_ACCESS_ADB_ONLY:
+ case SUPERUSER_ACCESS_APPS_AND_ADB:
+ return val;
+ default:
+ return SUPERUSER_ACCESS_APPS_AND_ADB;
+ }
+ }
+ catch (Exception e) {
+ return SUPERUSER_ACCESS_APPS_AND_ADB;
+ }
+ }
+
+ public static void setSuperuserAccess(int mode) {
+ // TODO: fallback to using SystemProperties.set if this has system uid (ie, embedded)
+ try {
+ String command = "setprop persist.sys.root_access " + mode;
+ Process p = Runtime.getRuntime().exec("su");
+ p.getOutputStream().write(command.getBytes());
+ p.getOutputStream().close();
+ p.waitFor();
+ }
+ catch (Exception ex) {
+ }
+ }
+
private static final String CHECK_SU_QUIET = "check_su_quiet";
public static final int getCheckSuQuietCounter(Context context) {
return getInt(context, CHECK_SU_QUIET, 0);
throw new Exception("no data");
if (!result.contains(context.getPackageName()))
throw new Exception("unknown su");
- // TODO: upgrades herp derp
+
+ String[] parts = result.split(" ");
+ if (!"2".equals(parts[0]))
+ throw new Exception("binary is old");
}
}