diff options
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() |