1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.devicepolicy;
17 
18 import static android.app.admin.SecurityLog.TAG_ADB_SHELL_CMD;
19 import static android.app.admin.SecurityLog.TAG_APP_PROCESS_START;
20 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED;
21 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED;
22 import static android.app.admin.SecurityLog.TAG_KEY_DESTRUCTION;
23 import static android.app.admin.SecurityLog.TAG_KEY_GENERATED;
24 import static android.app.admin.SecurityLog.TAG_KEY_IMPORT;
25 import static android.app.admin.SecurityLog.TAG_KEY_INTEGRITY_VIOLATION;
26 import static android.app.admin.SecurityLog.TAG_MEDIA_MOUNT;
27 import static android.app.admin.SecurityLog.TAG_MEDIA_UNMOUNT;
28 
29 import static com.google.common.truth.Truth.assertThat;
30 
31 import android.app.admin.SecurityLog.SecurityEvent;
32 import android.os.Parcel;
33 import android.os.UserHandle;
34 import android.text.TextUtils;
35 import android.util.EventLog;
36 import android.util.EventLog.Event;
37 
38 import androidx.test.runner.AndroidJUnit4;
39 
40 import junit.framework.AssertionFailedError;
41 
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 /**
49  * Tests for the DeviceOwner object that saves & loads device and policy owner information.
50  *
51  * <p>Run this test with:
52  *
53  * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.SecurityEventTest}
54  *
55  */
56 @RunWith(AndroidJUnit4.class)
57 public class SecurityEventTest extends DpmTestBase {
58 
59     @Test
testSecurityEventId()60     public void testSecurityEventId() throws Exception {
61         SecurityEvent event = createEvent(() -> {
62             EventLog.writeEvent(TAG_ADB_SHELL_CMD, 0);
63         }, TAG_ADB_SHELL_CMD);
64         event.setId(20);
65         assertThat(event.getId()).isEqualTo(20);
66     }
67 
68     @Test
testSecurityEventParceling()69     public void testSecurityEventParceling() throws Exception {
70         // GIVEN an event.
71         SecurityEvent event = createEvent(() -> {
72             EventLog.writeEvent(TAG_ADB_SHELL_CMD, "test");
73         }, TAG_ADB_SHELL_CMD);
74         // WHEN parceling the event.
75         Parcel p = Parcel.obtain();
76         p.writeParcelable(event, 0);
77         p.setDataPosition(0);
78         SecurityEvent unparceledEvent = p.readParcelable(SecurityEventTest.class.getClassLoader());
79         p.recycle();
80         // THEN the event state is preserved.
81         assertThat(unparceledEvent.getTag()).isEqualTo(event.getTag());
82         assertThat(unparceledEvent.getData()).isEqualTo(event.getData());
83         assertThat(unparceledEvent.getTimeNanos()).isEqualTo(event.getTimeNanos());
84         assertThat(unparceledEvent.getId()).isEqualTo(event.getId());
85     }
86 
87     @Test
testSecurityEventRedaction()88     public void testSecurityEventRedaction() throws Exception {
89         SecurityEvent event;
90 
91         // TAG_ADB_SHELL_CMD will has the command redacted
92         event = createEvent(() -> {
93             EventLog.writeEvent(TAG_ADB_SHELL_CMD, "command");
94         }, TAG_ADB_SHELL_CMD);
95         assertThat(TextUtils.isEmpty((String) event.getData())).isFalse();
96 
97         // TAG_MEDIA_MOUNT will have the volume label redacted (second data)
98         event = createEvent(() -> {
99             EventLog.writeEvent(TAG_MEDIA_MOUNT, new Object[] {"path", "label"});
100         }, TAG_MEDIA_MOUNT);
101         assertThat(TextUtils.isEmpty(event.getStringData(1))).isFalse();
102         assertThat(TextUtils.isEmpty(event.redact(0).getStringData(1))).isTrue();
103 
104         // TAG_MEDIA_UNMOUNT will have the volume label redacted (second data)
105         event = createEvent(() -> {
106             EventLog.writeEvent(TAG_MEDIA_UNMOUNT, new Object[] {"path", "label"});
107         }, TAG_MEDIA_UNMOUNT);
108         assertThat(TextUtils.isEmpty(event.getStringData(1))).isFalse();
109         assertThat(TextUtils.isEmpty(event.redact(0).getStringData(1))).isTrue();
110 
111         // TAG_APP_PROCESS_START will be fully redacted if user does not match
112         event = createEvent(() -> {
113             EventLog.writeEvent(TAG_APP_PROCESS_START, new Object[] {"process", 12345L,
114                     UserHandle.getUid(10, 123), 456, "seinfo", "hash"});
115         }, TAG_APP_PROCESS_START);
116         assertThat(event.redact(10)).isNotNull();
117         assertThat(event.redact(11)).isNull();
118 
119         // TAG_CERT_AUTHORITY_INSTALLED will be fully redacted if user does not match
120         event = createEvent(() -> {
121             EventLog.writeEvent(TAG_CERT_AUTHORITY_INSTALLED, new Object[] {1, "subject", 10});
122         }, TAG_CERT_AUTHORITY_INSTALLED);
123         assertThat(event.redact(10)).isNotNull();
124         assertThat(event.redact(11)).isNull();
125 
126         // TAG_CERT_AUTHORITY_REMOVED will be fully redacted if user does not match
127         event = createEvent(() -> {
128             EventLog.writeEvent(TAG_CERT_AUTHORITY_REMOVED, new Object[] {1, "subject", 20});
129         }, TAG_CERT_AUTHORITY_REMOVED);
130         assertThat(event.redact(20)).isNotNull();
131         assertThat(event.redact(0)).isNull();
132 
133         // TAG_KEY_GENERATED will be fully redacted if user does not match
134         event = createEvent(() -> {
135             EventLog.writeEvent(TAG_KEY_GENERATED,
136                     new Object[] {1, "alias", UserHandle.getUid(0, 123)});
137         }, TAG_KEY_GENERATED);
138         assertThat(event.redact(0)).isNotNull();
139         assertThat(event.redact(10)).isNull();
140 
141         // TAG_KEY_IMPORT will be fully redacted if user does not match
142         event = createEvent(() -> {
143             EventLog.writeEvent(TAG_KEY_IMPORT,
144                     new Object[] {1, "alias", UserHandle.getUid(1, 123)});
145         }, TAG_KEY_IMPORT);
146         assertThat(event.redact(1)).isNotNull();
147         assertThat(event.redact(10)).isNull();
148 
149         // TAG_KEY_DESTRUCTION will be fully redacted if user does not match
150         event = createEvent(() -> {
151             EventLog.writeEvent(TAG_KEY_DESTRUCTION,
152                     new Object[] {1, "alias", UserHandle.getUid(2, 123)});
153         }, TAG_KEY_DESTRUCTION);
154         assertThat(event.redact(2)).isNotNull();
155         assertThat(event.redact(10)).isNull();
156 
157         // TAG_KEY_INTEGRITY_VIOLATION will be fully redacted if user does not match
158         event = createEvent(() -> {
159             EventLog.writeEvent(TAG_KEY_INTEGRITY_VIOLATION,
160                     new Object[] {"alias", UserHandle.getUid(2, 123)});
161         }, TAG_KEY_INTEGRITY_VIOLATION);
162         assertThat(event.redact(2)).isNotNull();
163         assertThat(event.redact(10)).isNull();
164 
165     }
166 
167     /**
168      * Creates an Event object. Only the native code has the serialization and deserialization logic
169      * so need to actually emit a real log in order to generate the object.
170      */
createEvent(Runnable generator, int expectedTag)171     private SecurityEvent createEvent(Runnable generator, int expectedTag) throws Exception {
172         Long markerData = System.currentTimeMillis();
173         EventLog.writeEvent(expectedTag, markerData);
174         generator.run();
175 
176         List<Event> events = new ArrayList<>();
177         // Give the message some time to show up in the log
178         Thread.sleep(20);
179         EventLog.readEvents(new int[] {expectedTag}, events);
180 
181         for (int i = 0; i < events.size() - 1; i++) {
182             if (markerData.equals(events.get(i).getData())) {
183                 return new SecurityEvent(0, events.get(i + 1).getBytes());
184             }
185         }
186         throw new AssertionFailedError("Unable to locate marker event");
187     }
188 }
189