Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0642086d authored by Yan Han's avatar Yan Han
Browse files

Fix array out of bounds error on bad message params

Add length checks for the HDMI-CEC message params byte array.
Add unit tests for atom logging that cover the empty params case.

Bug: 195634268
Test: atest HdmiCecAtomLoggingTest
Change-Id: If250baebfc9ffed96bfce28aa30531d40b9e52b2
parent f8c928be
Loading
Loading
Loading
Loading
+37 −11
Original line number Diff line number Diff line
@@ -27,7 +27,8 @@ import com.android.internal.util.FrameworkStatsLog;
@VisibleForTesting
public class HdmiCecAtomWriter {

    private static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
    @VisibleForTesting
    protected static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
    private static final int ERROR_CODE_UNKNOWN = -1;

    /**
@@ -103,26 +104,32 @@ public class HdmiCecAtomWriter {
            HdmiCecMessage message) {
        MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();

        if (message.getParams().length > 0) {
            int keycode = message.getParams()[0];
            if (keycode >= 0x1E && keycode <= 0x29) {
                specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER;
            } else {
                specialArgs.mUserControlPressedCommand = keycode + 0x100;
            }
        }

        return specialArgs;
    }

    /**
     * Constructs method for constructing the special arguments for a <Feature Abort> message.
     * Constructs the special arguments for a <Feature Abort> message.
     *
     * @param message The HDMI CEC message to log
     */
    private MessageReportedSpecialArgs createFeatureAbortSpecialArgs(HdmiCecMessage message) {
        MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs();

        if (message.getParams().length > 0) {
            specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte
            if (message.getParams().length > 1) {
                specialArgs.mFeatureAbortReason = message.getParams()[1] + 10;
            }
        }

        return specialArgs;
    }
@@ -135,8 +142,7 @@ public class HdmiCecAtomWriter {
     */
    private void messageReportedBase(MessageReportedGenericArgs genericArgs,
            MessageReportedSpecialArgs specialArgs) {
        FrameworkStatsLog.write(
                FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED,
        writeHdmiCecMessageReportedAtom(
                genericArgs.mUid,
                genericArgs.mDirection,
                genericArgs.mInitiatorLogicalAddress,
@@ -148,6 +154,26 @@ public class HdmiCecAtomWriter {
                specialArgs.mFeatureAbortReason);
    }

    /**
     * Writes a HdmiCecMessageReported atom representing an incoming or outgoing HDMI-CEC message.
     */
    @VisibleForTesting
    protected void writeHdmiCecMessageReportedAtom(int uid, int direction,
            int initiatorLogicalAddress, int destinationLogicalAddress, int opcode,
            int sendMessageResult, int userControlPressedCommand, int featureAbortOpcode,
            int featureAbortReason) {
        FrameworkStatsLog.write(
                FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED,
                uid,
                direction,
                initiatorLogicalAddress,
                destinationLogicalAddress,
                opcode,
                sendMessageResult,
                userControlPressedCommand,
                featureAbortOpcode,
                featureAbortReason);
    }

    /**
     * Writes a HdmiCecActiveSourceChanged atom representing a change in the active source.
+110 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.stats.hdmi.nano.HdmiStatsEnums;
import android.stats.hdmi.HdmiStatsEnums;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -53,6 +53,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;

import java.util.ArrayList;
import java.util.Collections;
@@ -134,6 +135,8 @@ public class HdmiCecAtomLoggingTest {
        mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);

        mTestLooper.dispatchAll();

        Mockito.reset(mHdmiCecAtomWriterSpy);
    }

    @Test
@@ -149,6 +152,7 @@ public class HdmiCecAtomLoggingTest {
                mPhysicalAddress);

        mHdmiCecController.sendCommand(message);
        mTestLooper.dispatchAll();

        verify(mHdmiCecAtomWriterSpy, times(1)).messageReported(
                eq(message),
@@ -193,4 +197,109 @@ public class HdmiCecAtomLoggingTest {
                eq(callerUid),
                anyInt());
    }

    @Test
    public void testMessageReported_writesAtom_userControlPressed() {
        HdmiCecMessage message = HdmiCecMessageBuilder.buildUserControlPressed(
                Constants.ADDR_TV,
                Constants.ADDR_PLAYBACK_1,
                HdmiCecKeycode.CEC_KEYCODE_MUTE
        );

        mHdmiCecAtomWriterSpy.messageReported(
                message,
                HdmiStatsEnums.INCOMING,
                1234);

        verify(mHdmiCecAtomWriterSpy, times(1))
                .writeHdmiCecMessageReportedAtom(
                        1234,
                        HdmiStatsEnums.INCOMING,
                        Constants.ADDR_TV,
                        Constants.ADDR_PLAYBACK_1,
                        Constants.MESSAGE_USER_CONTROL_PRESSED,
                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                        HdmiStatsEnums.VOLUME_MUTE,
                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
    }

    @Test
    public void testMessageReported_writesAtom_userControlPressed_noParams() {
        HdmiCecMessage message = new HdmiCecMessage(
                Constants.ADDR_TV,
                Constants.ADDR_PLAYBACK_1,
                Constants.MESSAGE_USER_CONTROL_PRESSED,
                new byte[0]);

        mHdmiCecAtomWriterSpy.messageReported(
                message,
                HdmiStatsEnums.INCOMING,
                1234);

        verify(mHdmiCecAtomWriterSpy, times(1))
                .writeHdmiCecMessageReportedAtom(
                        1234,
                        HdmiStatsEnums.INCOMING,
                        Constants.ADDR_TV,
                        Constants.ADDR_PLAYBACK_1,
                        Constants.MESSAGE_USER_CONTROL_PRESSED,
                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
    }

    @Test
    public void testMessageReported_writesAtom_featureAbort() {
        HdmiCecMessage message = HdmiCecMessageBuilder.buildFeatureAbortCommand(
                Constants.ADDR_TV,
                Constants.ADDR_PLAYBACK_1,
                Constants.MESSAGE_RECORD_ON,
                Constants.ABORT_UNRECOGNIZED_OPCODE
        );

        mHdmiCecAtomWriterSpy.messageReported(
                message,
                HdmiStatsEnums.INCOMING,
                1234);

        verify(mHdmiCecAtomWriterSpy, times(1))
                .writeHdmiCecMessageReportedAtom(
                        1234,
                        HdmiStatsEnums.INCOMING,
                        Constants.ADDR_TV,
                        Constants.ADDR_PLAYBACK_1,
                        Constants.MESSAGE_FEATURE_ABORT,
                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
                        Constants.MESSAGE_RECORD_ON,
                        HdmiStatsEnums.UNRECOGNIZED_OPCODE);
    }

    @Test
    public void testMessageReported_writesAtom_featureAbort_noParams() {
        HdmiCecMessage message = new HdmiCecMessage(
                Constants.ADDR_TV,
                Constants.ADDR_PLAYBACK_1,
                Constants.MESSAGE_FEATURE_ABORT,
                new byte[0]);

        mHdmiCecAtomWriterSpy.messageReported(
                message,
                HdmiStatsEnums.INCOMING,
                1234);

        verify(mHdmiCecAtomWriterSpy, times(1))
                .writeHdmiCecMessageReportedAtom(
                        1234,
                        HdmiStatsEnums.INCOMING,
                        Constants.ADDR_TV,
                        Constants.ADDR_PLAYBACK_1,
                        Constants.MESSAGE_FEATURE_ABORT,
                        HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN,
                        HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN,
                        HdmiCecAtomWriter.FEATURE_ABORT_OPCODE_UNKNOWN,
                        HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN);
    }
}