我正在尝试使用 Google 在我的 Android 应用程序中发布的 SecureRandom 解决方法: http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
此工作涉及写入(和读取)/dev/urandom。然而,三星似乎已启用 SELinux,以阻止应用程序访问 /dev/urandom。
我没有这些设备之一,所以除了在 Android 市场上尝试解决方案之外,测试解决方案对我来说有点困难,但这似乎不是我可以捕获的错误try catch 块。 File.canRead 和 canWrite 似乎也返回 true。您可以在以下类的supportedOnThisDevice方法中看到我尝试的解决方法: PRNGFixes.java
我正在寻找一种可靠的方法来检测我是否是此类设备,如果是,则不应用 Google SecureRandom 解决方法。
这是我检查 SELinux 是否处于强制模式的方法 - 可以通过任何 Shell 脚本完成,而不依赖于 RootTools:
private static boolean isSELinuxEnforcing() {
try {
CommandCapture command = new CommandCapture(1, "getenforce");
RootTools.getShell(false).add(command).waitForFinish();
boolean isSELinuxEnforcing = command.toString().trim().equalsIgnoreCase("enforcing");
return isSELinuxEnforcing;
} catch (Exception e) {
// handle exception
}
return false;
}
我听说三星开始发售将 SELinux 策略设置为强制执行的设备,但我不知道这是否属实。据我所知,4.3 上的大多数设备仍然将其设置为宽容。
根据 Google 的说法,“SELinux 强化对于用户和开发人员来说是不可见的,它为现有 Android 安全模型增加了稳健性,同时保持了与现有应用程序的兼容性。” 因此,您可能需要检查系统属性或通过 shell 进行测试确定一下。
如果你能让某人向你发送他们的 build.prop,你也许可以通过
System.getProperty("ro.build.selinux")
比较他们的 ro.build.selinux 属性来捕获它,
但您还需要验证您是否能够更直接地访问它,以防它不可靠或 getProperty() 在未来的更新中被破坏。
Root(SELinux 上的系统用户)是另一个可用选项,但无论哪种方式,基于 shell 的解决方案可能都是您的最佳选择。
System.getProperty("ro.build.selinux")
在 Samsung S4 Android 4.3 上不适用于我。所以我写了这个
private static final int JELLY_BEAN_MR2 = 18;
public static boolean isSELinuxSupported() {
// Didnt' work
//String selinuxStatus = System.getProperty(PROPERTY_SELINUX_STATUS);
//return selinuxStatus.equals("1") ? true : false;
String selinuxFlag = getSelinuxFlag();
if (!StringUtils.isEmpty(selinuxFlag)) {
return selinuxFlag.equals("1") ? true : false;
} else {
// 4.3 or later ?
if(Build.VERSION.SDK_INT >= JELLY_BEAN_MR2) {
return true;
}
else {
return false;
}
}
}
public static String getSelinuxFlag() {
String selinux = null;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
selinux = (String) get.invoke(c, "ro.build.selinux");
} catch (Exception ignored) {
}
return selinux;
}
如果您有权访问框架
import android.os.SELinux;
SELinux.isSELinuxEnforced();
从 Jellybean MR2 开始,大多数设备都会在其设备上启用 SELinux,但如果您与 OEM 合作或进行平台工作,则情况可能不一定如此。
我用来验证的方法是使用 getenforce shell 命令:
public boolean isSeLinuxEnforcing() {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec("getenforce");
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line);
}
} catch (Exception e) {
Log.e(TAG, "OS does not support getenforce");
// If getenforce is not available to the device, assume the device is not enforcing
e.printStackTrace();
return false;
}
String response = output.toString();
if ("Enforcing".equals(response)) {
return true;
} else if ("Permissive".equals(response)) {
return false;
} else {
Log.e(TAG, "getenforce returned unexpected value, unable to determine selinux!");
// If getenforce is modified on this device, assume the device is not enforcing
return false;
}
}
大多数设备似乎只是在“未”运行在强制状态下时才为 selinux 编写系统属性。您还可以检查属性:ro.boot.selinux以查看内核是否在当前构建上传递了许可参数。
public static String getviarefSelinuxFlag(Context ctx) {
try {
Class<?> cls = Class.forName("android.os.SELinux");
Object newInstance = cls.getConstructor(Context.class).newInstance(ctx);
Method method = cls.getMethod("isSELinuxEnforced");
Method method1 = cls.getMethod("isSELinuxEnabled");
Boolean SELinuxEnforced = (Boolean) method.invoke(null);
Boolean SELinuxEnabled = (Boolean) method1.invoke(null);
return "isSELinuxEnforced : " + SELinuxEnforced + "\nisSELinuxEnabled : " + SELinuxEnabled;
} catch (Exception ignored) {
return "Method not working";
}
}