/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.devicepolicy; import static android.app.admin.SecurityLog.TAG_ADB_SHELL_CMD; import static android.app.admin.SecurityLog.TAG_APP_PROCESS_START; import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED; import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED; import static android.app.admin.SecurityLog.TAG_KEY_DESTRUCTION; import static android.app.admin.SecurityLog.TAG_KEY_GENERATED; import static android.app.admin.SecurityLog.TAG_KEY_IMPORT; import static android.app.admin.SecurityLog.TAG_KEY_INTEGRITY_VIOLATION; import static android.app.admin.SecurityLog.TAG_MEDIA_MOUNT; import static android.app.admin.SecurityLog.TAG_MEDIA_UNMOUNT; import static com.google.common.truth.Truth.assertThat; import android.app.admin.SecurityLog.SecurityEvent; import android.os.Parcel; import android.os.UserHandle; import android.text.TextUtils; import android.util.EventLog; import android.util.EventLog.Event; import androidx.test.runner.AndroidJUnit4; import junit.framework.AssertionFailedError; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; /** * Tests for the DeviceOwner object that saves & loads device and policy owner information. * *
Run this test with:
*
* {@code atest FrameworksServicesTests:com.android.server.devicepolicy.SecurityEventTest}
*
*/
@RunWith(AndroidJUnit4.class)
public class SecurityEventTest extends DpmTestBase {
@Test
public void testSecurityEventId() throws Exception {
SecurityEvent event = createEvent(() -> {
EventLog.writeEvent(TAG_ADB_SHELL_CMD, 0);
}, TAG_ADB_SHELL_CMD);
event.setId(20);
assertThat(event.getId()).isEqualTo(20);
}
@Test
public void testSecurityEventParceling() throws Exception {
// GIVEN an event.
SecurityEvent event = createEvent(() -> {
EventLog.writeEvent(TAG_ADB_SHELL_CMD, "test");
}, TAG_ADB_SHELL_CMD);
// WHEN parceling the event.
Parcel p = Parcel.obtain();
p.writeParcelable(event, 0);
p.setDataPosition(0);
SecurityEvent unparceledEvent = p.readParcelable(SecurityEventTest.class.getClassLoader());
p.recycle();
// THEN the event state is preserved.
assertThat(unparceledEvent.getTag()).isEqualTo(event.getTag());
assertThat(unparceledEvent.getData()).isEqualTo(event.getData());
assertThat(unparceledEvent.getTimeNanos()).isEqualTo(event.getTimeNanos());
assertThat(unparceledEvent.getId()).isEqualTo(event.getId());
}
@Test
public void testSecurityEventRedaction() throws Exception {
SecurityEvent event;
// TAG_ADB_SHELL_CMD will has the command redacted
event = createEvent(() -> {
EventLog.writeEvent(TAG_ADB_SHELL_CMD, "command");
}, TAG_ADB_SHELL_CMD);
assertThat(TextUtils.isEmpty((String) event.getData())).isFalse();
// TAG_MEDIA_MOUNT will have the volume label redacted (second data)
event = createEvent(() -> {
EventLog.writeEvent(TAG_MEDIA_MOUNT, new Object[] {"path", "label"});
}, TAG_MEDIA_MOUNT);
assertThat(TextUtils.isEmpty(event.getStringData(1))).isFalse();
assertThat(TextUtils.isEmpty(event.redact(0).getStringData(1))).isTrue();
// TAG_MEDIA_UNMOUNT will have the volume label redacted (second data)
event = createEvent(() -> {
EventLog.writeEvent(TAG_MEDIA_UNMOUNT, new Object[] {"path", "label"});
}, TAG_MEDIA_UNMOUNT);
assertThat(TextUtils.isEmpty(event.getStringData(1))).isFalse();
assertThat(TextUtils.isEmpty(event.redact(0).getStringData(1))).isTrue();
// TAG_APP_PROCESS_START will be fully redacted if user does not match
event = createEvent(() -> {
EventLog.writeEvent(TAG_APP_PROCESS_START, new Object[] {"process", 12345L,
UserHandle.getUid(10, 123), 456, "seinfo", "hash"});
}, TAG_APP_PROCESS_START);
assertThat(event.redact(10)).isNotNull();
assertThat(event.redact(11)).isNull();
// TAG_CERT_AUTHORITY_INSTALLED will be fully redacted if user does not match
event = createEvent(() -> {
EventLog.writeEvent(TAG_CERT_AUTHORITY_INSTALLED, new Object[] {1, "subject", 10});
}, TAG_CERT_AUTHORITY_INSTALLED);
assertThat(event.redact(10)).isNotNull();
assertThat(event.redact(11)).isNull();
// TAG_CERT_AUTHORITY_REMOVED will be fully redacted if user does not match
event = createEvent(() -> {
EventLog.writeEvent(TAG_CERT_AUTHORITY_REMOVED, new Object[] {1, "subject", 20});
}, TAG_CERT_AUTHORITY_REMOVED);
assertThat(event.redact(20)).isNotNull();
assertThat(event.redact(0)).isNull();
// TAG_KEY_GENERATED will be fully redacted if user does not match
event = createEvent(() -> {
EventLog.writeEvent(TAG_KEY_GENERATED,
new Object[] {1, "alias", UserHandle.getUid(0, 123)});
}, TAG_KEY_GENERATED);
assertThat(event.redact(0)).isNotNull();
assertThat(event.redact(10)).isNull();
// TAG_KEY_IMPORT will be fully redacted if user does not match
event = createEvent(() -> {
EventLog.writeEvent(TAG_KEY_IMPORT,
new Object[] {1, "alias", UserHandle.getUid(1, 123)});
}, TAG_KEY_IMPORT);
assertThat(event.redact(1)).isNotNull();
assertThat(event.redact(10)).isNull();
// TAG_KEY_DESTRUCTION will be fully redacted if user does not match
event = createEvent(() -> {
EventLog.writeEvent(TAG_KEY_DESTRUCTION,
new Object[] {1, "alias", UserHandle.getUid(2, 123)});
}, TAG_KEY_DESTRUCTION);
assertThat(event.redact(2)).isNotNull();
assertThat(event.redact(10)).isNull();
// TAG_KEY_INTEGRITY_VIOLATION will be fully redacted if user does not match
event = createEvent(() -> {
EventLog.writeEvent(TAG_KEY_INTEGRITY_VIOLATION,
new Object[] {"alias", UserHandle.getUid(2, 123)});
}, TAG_KEY_INTEGRITY_VIOLATION);
assertThat(event.redact(2)).isNotNull();
assertThat(event.redact(10)).isNull();
}
/**
* Creates an Event object. Only the native code has the serialization and deserialization logic
* so need to actually emit a real log in order to generate the object.
*/
private SecurityEvent createEvent(Runnable generator, int expectedTag) throws Exception {
Long markerData = System.currentTimeMillis();
EventLog.writeEvent(expectedTag, markerData);
generator.run();
List