diff options
5 files changed, 215 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java index 06e9dcdcbedd..0ea88e8523f0 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java +++ b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java @@ -36,6 +36,9 @@ public class DataAggregator { private static final int MSG_DISABLE = 2; private static final int STORED_EVENTS_SIZE_LIMIT = 1024; + private static final IntrusionDetectionAdminReceiver ADMIN_RECEIVER = + new IntrusionDetectionAdminReceiver(); + private final IntrusionDetectionService mIntrusionDetectionService; private final ArrayList<DataSource> mDataSources; @@ -60,10 +63,19 @@ public class DataAggregator { * Initialize DataSources * @return Whether the initialization succeeds. */ - // TODO: Add the corresponding data sources public boolean initialize() { SecurityLogSource securityLogSource = new SecurityLogSource(mContext, this); mDataSources.add(securityLogSource); + + NetworkLogSource networkLogSource = new NetworkLogSource(mContext, this); + ADMIN_RECEIVER.setNetworkLogEventCallback(networkLogSource); + mDataSources.add(networkLogSource); + + for (DataSource ds : mDataSources) { + if (!ds.initialize()) { + return false; + } + } return true; } diff --git a/services/core/java/com/android/server/security/intrusiondetection/DataSource.java b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java index 0bc448245b76..61fac46be82d 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/DataSource.java +++ b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java @@ -18,6 +18,11 @@ package com.android.server.security.intrusiondetection; public interface DataSource { /** + * Initialize the data source. + */ + boolean initialize(); + + /** * Enable the data collection. */ void enable(); diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java new file mode 100644 index 000000000000..dba7374fe02a --- /dev/null +++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 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.security.intrusiondetection; + +import android.app.admin.DeviceAdminReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Slog; + +public class IntrusionDetectionAdminReceiver extends DeviceAdminReceiver { + private static final String TAG = "IntrusionDetectionAdminReceiver"; + + private static NetworkLogSource sNetworkLogSource; + + @Override + public void onNetworkLogsAvailable( + Context context, Intent intent, long batchToken, int networkLogsCount) { + if (sNetworkLogSource != null) { + sNetworkLogSource.onNetworkLogsAvailable(batchToken); + } else { + Slog.w(TAG, "Network log receiver is not initialized"); + } + } + + public void setNetworkLogEventCallback(NetworkLogSource networkLogSource) { + sNetworkLogSource = networkLogSource; + } +} diff --git a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java new file mode 100644 index 000000000000..1c93d3f9c6a1 --- /dev/null +++ b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 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.security.intrusiondetection; + +import android.app.admin.ConnectEvent; +import android.app.admin.DevicePolicyManager; +import android.app.admin.DnsEvent; +import android.app.admin.NetworkEvent; +import android.content.ComponentName; +import android.content.Context; +import android.security.intrusiondetection.IntrusionDetectionEvent; +import android.util.Slog; + +import java.util.List; +import java.util.stream.Collectors; + +public class NetworkLogSource implements DataSource { + + private static final String TAG = "IntrusionDetectionEvent NetworkLogSource"; + + private DevicePolicyManager mDpm; + private ComponentName mAdmin; + private DataAggregator mDataAggregator; + + public NetworkLogSource(Context context, DataAggregator dataAggregator) { + mDataAggregator = dataAggregator; + mDpm = context.getSystemService(DevicePolicyManager.class); + mAdmin = new ComponentName(context, IntrusionDetectionAdminReceiver.class); + } + + @Override + public boolean initialize() { + try { + if (!mDpm.isAdminActive(mAdmin)) { + Slog.e(TAG, "Admin " + mAdmin.flattenToString() + "is not active admin"); + return false; + } + } catch (SecurityException e) { + Slog.e(TAG, "Security exception in initialize: ", e); + return false; + } + return true; + } + + @Override + public void enable() { + enableNetworkLog(); + } + + @Override + public void disable() { + disableNetworkLog(); + } + + private void enableNetworkLog() { + if (!isNetworkLogEnabled()) { + mDpm.setNetworkLoggingEnabled(mAdmin, true); + } + } + + private void disableNetworkLog() { + if (isNetworkLogEnabled()) { + mDpm.setNetworkLoggingEnabled(mAdmin, false); + } + } + + private boolean isNetworkLogEnabled() { + return mDpm.isNetworkLoggingEnabled(mAdmin); + } + + /** + * Retrieve network logs when onNetworkLogsAvailable callback is received. + * + * @param batchToken The token representing the current batch of network logs. + */ + public void onNetworkLogsAvailable(long batchToken) { + List<NetworkEvent> events; + try { + events = mDpm.retrieveNetworkLogs(mAdmin, batchToken); + } catch (SecurityException e) { + Slog.e( + TAG, + "Admin " + + mAdmin.flattenToString() + + "does not have permission to retrieve network logs", + e); + return; + } + if (events == null) { + if (!isNetworkLogEnabled()) { + Slog.w(TAG, "Network logging is disabled"); + } else { + Slog.e(TAG, "Invalid batch token: " + batchToken); + } + return; + } + + List<IntrusionDetectionEvent> intrusionDetectionEvents = + events.stream() + .filter(event -> event != null) + .map(event -> toIntrusionDetectionEvent(event)) + .collect(Collectors.toList()); + mDataAggregator.addBatchData(intrusionDetectionEvents); + } + + private IntrusionDetectionEvent toIntrusionDetectionEvent(NetworkEvent event) { + if (event instanceof DnsEvent) { + DnsEvent dnsEvent = (DnsEvent) event; + return new IntrusionDetectionEvent(dnsEvent); + } else if (event instanceof ConnectEvent) { + ConnectEvent connectEvent = (ConnectEvent) event; + return new IntrusionDetectionEvent(connectEvent); + } + throw new IllegalArgumentException( + "Invalid event type with ID: " + + event.getId() + + "from package: " + + event.getPackageName()); + } +} diff --git a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java index 226f9d879cab..c5f736e383b2 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java +++ b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java @@ -22,6 +22,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.SecurityLog.SecurityEvent; import android.content.Context; import android.security.intrusiondetection.IntrusionDetectionEvent; +import android.util.Slog; import java.util.List; import java.util.concurrent.Executor; @@ -33,7 +34,7 @@ public class SecurityLogSource implements DataSource { private static final String TAG = "IntrusionDetection SecurityLogSource"; - private SecurityEventCallback mEventCallback = new SecurityEventCallback(); + private SecurityEventCallback mEventCallback; private DevicePolicyManager mDpm; private Executor mExecutor; private DataAggregator mDataAggregator; @@ -42,9 +43,26 @@ public class SecurityLogSource implements DataSource { mDataAggregator = dataAggregator; mDpm = context.getSystemService(DevicePolicyManager.class); mExecutor = Executors.newSingleThreadExecutor(); + } + + @Override + public boolean initialize() { + // Confirm caller is system and the device is managed. Otherwise logs will + // be redacted. + try { + if (!mDpm.isDeviceManaged()) { + Slog.e(TAG, "Caller does not have device owner permissions"); + return false; + } + } catch (SecurityException e) { + Slog.e(TAG, "Security exception in initialize: ", e); + return false; + } mEventCallback = new SecurityEventCallback(); + return true; } + @Override @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void enable() { @@ -72,12 +90,8 @@ public class SecurityLogSource implements DataSource { } } - /** - * Check if security audit logging is enabled for the caller. - * - * @return Whether security audit logging is enabled. - */ - public boolean isAuditLogEnabled() { + @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) + private boolean isAuditLogEnabled() { return mDpm.isAuditLogEnabled(); } |