summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/native/bpf_headers/include/bpf/bpf_helpers.h43
-rw-r--r--common/tests/unit/src/com/android/net/module/util/SharedLogTest.java58
-rw-r--r--common/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt18
3 files changed, 102 insertions, 17 deletions
diff --git a/common/native/bpf_headers/include/bpf/bpf_helpers.h b/common/native/bpf_headers/include/bpf/bpf_helpers.h
index 8bc8eb17..236318d6 100644
--- a/common/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/common/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -37,6 +37,9 @@
// Android T / 13 (api level 33) - support for shared/selinux_context/pindir
#define BPFLOADER_T_VERSION 19u
+// BpfLoader v0.25+ support obj@ver.o files
+#define BPFLOADER_OBJ_AT_VER_VERSION 25u
+
/* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER
* before #include "bpf_helpers.h" to change which bpfloaders will
* process the resulting .o file.
@@ -179,20 +182,39 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map,
return bpf_map_delete_elem_unsafe(&the_map, k); \
};
+#ifndef DEFAULT_BPF_MAP_SELINUX_CONTEXT
+#define DEFAULT_BPF_MAP_SELINUX_CONTEXT ""
+#endif
+
+#ifndef DEFAULT_BPF_MAP_PIN_SUBDIR
+#define DEFAULT_BPF_MAP_PIN_SUBDIR ""
+#endif
+
+#ifndef DEFAULT_BPF_MAP_UID
+#define DEFAULT_BPF_MAP_UID AID_ROOT
+#elif BPFLOADER_MIN_VER < 21u
+#error "Bpf Map UID must be left at default of AID_ROOT for BpfLoader prior to v0.21"
+#endif
+
#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \
- DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, "", "", false)
+ DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \
+ DEFAULT_BPF_MAP_SELINUX_CONTEXT, DEFAULT_BPF_MAP_PIN_SUBDIR, false)
#define DEFINE_BPF_MAP(the_map, TYPE, KeyType, ValueType, num_entries) \
- DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, AID_ROOT, 0600)
+ DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
+ DEFAULT_BPF_MAP_UID, AID_ROOT, 0600)
#define DEFINE_BPF_MAP_GWO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \
- DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0620)
+ DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
+ DEFAULT_BPF_MAP_UID, gid, 0620)
#define DEFINE_BPF_MAP_GRO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \
- DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0640)
+ DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
+ DEFAULT_BPF_MAP_UID, gid, 0640)
#define DEFINE_BPF_MAP_GRW(the_map, TYPE, KeyType, ValueType, num_entries, gid) \
- DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0660)
+ DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
+ DEFAULT_BPF_MAP_UID, gid, 0660)
static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read;
static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str;
@@ -221,9 +243,18 @@ static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_
SECTION(SECTION_NAME) \
int the_prog
+#ifndef DEFAULT_BPF_PROG_SELINUX_CONTEXT
+#define DEFAULT_BPF_PROG_SELINUX_CONTEXT ""
+#endif
+
+#ifndef DEFAULT_BPF_PROG_PIN_SUBDIR
+#define DEFAULT_BPF_PROG_PIN_SUBDIR ""
+#endif
+
#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
opt) \
- DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, "", "")
+ DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, \
+ DEFAULT_BPF_PROG_SELINUX_CONTEXT, DEFAULT_BPF_PROG_PIN_SUBDIR)
// Programs (here used in the sense of functions/sections) marked optional are allowed to fail
// to load (for example due to missing kernel patches).
diff --git a/common/tests/unit/src/com/android/net/module/util/SharedLogTest.java b/common/tests/unit/src/com/android/net/module/util/SharedLogTest.java
index 446e8819..aa1bfee4 100644
--- a/common/tests/unit/src/com/android/net/module/util/SharedLogTest.java
+++ b/common/tests/unit/src/com/android/net/module/util/SharedLogTest.java
@@ -17,6 +17,8 @@
package com.android.net.module.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import androidx.test.filters.SmallTest;
@@ -27,16 +29,24 @@ import org.junit.runner.RunWith;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SharedLogTest {
private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
private static final String TIMESTAMP = "HH:MM:SS";
+ private static final String TAG = "top";
@Test
public void testBasicOperation() {
- final SharedLog logTop = new SharedLog("top");
+ final SharedLog logTop = new SharedLog(TAG);
+ assertTrue(TAG.equals(logTop.getTag()));
+
logTop.mark("first post!");
final SharedLog logLevel2a = logTop.forSubComponent("twoA");
@@ -48,8 +58,10 @@ public class SharedLogTest {
final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
logTop.log("still logging");
- logLevel3.log("3 >> 2");
+ logLevel2b.e(new Exception("Got another exception"));
+ logLevel3.i("3 >> 2");
logLevel2a.mark("ok: last post");
+ logTop.logf("finished!");
final String[] expected = {
" - MARK first post!",
@@ -59,29 +71,53 @@ public class SharedLogTest {
" - [twoB] ERROR Wait, here's one: Test",
" - [twoA] WARN second post?",
" - still logging",
+ " - [twoB] ERROR java.lang.Exception: Got another exception",
" - [twoA.three] 3 >> 2",
" - [twoA] MARK ok: last post",
+ " - finished!",
};
// Verify the logs are all there and in the correct order.
- verifyLogLines(expected, logTop);
+ assertDumpLogs(expected, logTop);
// In fact, because they all share the same underlying LocalLog,
// every subcomponent SharedLog's dump() is identical.
- verifyLogLines(expected, logLevel2a);
- verifyLogLines(expected, logLevel2b);
- verifyLogLines(expected, logLevel3);
+ assertDumpLogs(expected, logLevel2a);
+ assertDumpLogs(expected, logLevel2b);
+ assertDumpLogs(expected, logLevel3);
+ }
+
+ private static void assertDumpLogs(String[] expected, SharedLog log) {
+ verifyLogLines(expected, dump(log));
+ verifyLogLines(reverse(expected), reverseDump(log));
+ }
+
+ private static String dump(SharedLog log) {
+ return getSharedLogString(pw -> log.dump(null /* fd */, pw, null /* args */));
}
- private static void verifyLogLines(String[] expected, SharedLog log) {
+ private static String reverseDump(SharedLog log) {
+ return getSharedLogString(pw -> log.reverseDump(pw));
+ }
+
+ private static String[] reverse(String[] ary) {
+ final List<String> ls = new ArrayList<>(Arrays.asList(ary));
+ Collections.reverse(ls);
+ return ls.toArray(new String[ary.length]);
+ }
+
+ private static String getSharedLogString(Consumer<PrintWriter> functor) {
final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
final PrintWriter pw = new PrintWriter(ostream, true);
- log.dump(null, pw, null);
+ functor.accept(pw);
final String dumpOutput = ostream.toString();
- assertTrue(dumpOutput != null);
- assertTrue(!"".equals(dumpOutput));
+ assertNotNull(dumpOutput);
+ assertFalse("".equals(dumpOutput));
+ return dumpOutput;
+ }
- final String[] lines = dumpOutput.split("\n");
+ private static void verifyLogLines(String[] expected, String gottenLogs) {
+ final String[] lines = gottenLogs.split("\n");
assertEquals(expected.length, lines.length);
for (int i = 0; i < expected.length; i++) {
diff --git a/common/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt b/common/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt
index f557f186..a4dbd9ad 100644
--- a/common/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt
+++ b/common/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt
@@ -19,6 +19,7 @@
package com.android.testutils
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.modules.utils.build.SdkLevel
import com.android.testutils.ExceptionUtils.ThrowingRunnable
import com.android.testutils.ExceptionUtils.ThrowingSupplier
@@ -31,6 +32,23 @@ import com.android.testutils.ExceptionUtils.ThrowingSupplier
*/
fun <T> runAsShell(vararg permissions: String, task: () -> T): T {
val autom = InstrumentationRegistry.getInstrumentation().uiAutomation
+
+ // Calls to adoptShellPermissionIdentity do not nest, and dropShellPermissionIdentity drops all
+ // permissions. Thus, nesting calls will almost certainly cause test bugs, On S+, where we can
+ // detect this, refuse to do it.
+ //
+ // TODO: when R is deprecated, we could try to make this work instead.
+ // - Get the list of previously-adopted permissions.
+ // - Adopt the union of the previously-adopted and newly-requested permissions.
+ // - Run the task.
+ // - Adopt the previously-adopted permissions, dropping the ones just adopted.
+ //
+ // This would allow tests (and utility classes, such as the TestCarrierConfigReceiver attempted
+ // in aosp/2106007) to call runAsShell even within a test that has already adopted permissions.
+ if (SdkLevel.isAtLeastS() && !autom.getAdoptedShellPermissions().isNullOrEmpty()) {
+ throw IllegalStateException("adoptShellPermissionIdentity calls must not be nested")
+ }
+
autom.adoptShellPermissionIdentity(*permissions)
try {
return task()