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

Commit e1561909 authored by Hungming Chen's avatar Hungming Chen
Browse files

[NFCT.NS.1] Respect the nlfamily in the netlink message parsing

The netlink message parsing requires the netlink family except the
reserved control message. Here is an example. If the netlink family
is not provided, the netlink message parser may not be able to
distinguish which netlink family it belongs to by netlink message
type 20.
    NETLINK_ROUTE.RTM_NEWADDR (20)
    NETLINK_SOCK_DIAG.SOCK_DIAG_BY_FAMILY (20)

Test: atest TetheringCoverageTest
Change-Id: I04ef64828e6b2a5ac62a28895da7bc71d06fcb9b
parent 7c07695f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ public class NetlinkMonitor extends PacketReader {
        while (byteBuffer.remaining() > 0) {
            try {
                final int position = byteBuffer.position();
                final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
                final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer, mFamily);
                if (nlMsg == null || nlMsg.getHeader() == null) {
                    byteBuffer.position(position);
                    mLog.e("unparsable netlink msg: " + hexify(byteBuffer));
+1 −1
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ public class InetDiagMessage extends NetlinkMessage {
        NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
        ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);

        final NetlinkMessage nlMsg = NetlinkMessage.parse(response);
        final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG);
        final StructNlMsgHdr hdr = nlMsg.getHeader();
        if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
            return INVALID_UID;
+65 −25
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package android.net.netlink;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.system.OsConstants;

import java.nio.ByteBuffer;


@@ -35,7 +39,12 @@ import java.nio.ByteBuffer;
public class NetlinkMessage {
    private final static String TAG = "NetlinkMessage";

    public static NetlinkMessage parse(ByteBuffer byteBuffer) {
    /**
     * Parsing netlink messages for reserved control message or specific netlink message. The
     * netlink family is required for parsing specific netlink message. See man-pages/netlink.
     */
    @Nullable
    public static NetlinkMessage parse(@NonNull ByteBuffer byteBuffer, int nlFamily) {
        final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1;
        final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer);
        if (nlmsghdr == null) {
@@ -50,31 +59,23 @@ public class NetlinkMessage {
            return null;
        }

        switch (nlmsghdr.nlmsg_type) {
            //case NetlinkConstants.NLMSG_NOOP:
            case NetlinkConstants.NLMSG_ERROR:
                return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
            case NetlinkConstants.NLMSG_DONE:
                byteBuffer.position(byteBuffer.position() + payloadLength);
                return new NetlinkMessage(nlmsghdr);
            //case NetlinkConstants.NLMSG_OVERRUN:
            case NetlinkConstants.RTM_NEWNEIGH:
            case NetlinkConstants.RTM_DELNEIGH:
            case NetlinkConstants.RTM_GETNEIGH:
                return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
            case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
                return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
            case NetlinkConstants.RTM_NEWNDUSEROPT:
                return (NetlinkMessage) NduseroptMessage.parse(nlmsghdr, byteBuffer);
            default:
        // Reserved control messages. The netlink family is ignored.
        // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h.
        if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
                    // Netlink control message.  Just parse the header for now,
                    // pretending the whole message was consumed.
                    byteBuffer.position(byteBuffer.position() + payloadLength);
                    return new NetlinkMessage(nlmsghdr);
            return parseCtlMessage(nlmsghdr, byteBuffer, payloadLength);
        }
                return null;

        // Netlink family messages. The netlink family is required. Note that the reason for using
        // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are
        // not constant.
        if (nlFamily == OsConstants.NETLINK_ROUTE) {
            return parseRtMessage(nlmsghdr, byteBuffer);
        }
        if (nlFamily == OsConstants.NETLINK_INET_DIAG) {
            return parseInetDiagMessage(nlmsghdr, byteBuffer);
        }

        return null;
    }

    protected StructNlMsgHdr mHeader;
@@ -91,4 +92,43 @@ public class NetlinkMessage {
    public String toString() {
        return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}";
    }

    @NonNull
    private static NetlinkMessage parseCtlMessage(@NonNull StructNlMsgHdr nlmsghdr,
            @NonNull ByteBuffer byteBuffer, int payloadLength) {
        switch (nlmsghdr.nlmsg_type) {
            case NetlinkConstants.NLMSG_ERROR:
                return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
            default: {
                // Other netlink control messages. Just parse the header for now,
                // pretending the whole message was consumed.
                byteBuffer.position(byteBuffer.position() + payloadLength);
                return new NetlinkMessage(nlmsghdr);
            }
        }
    }

    @Nullable
    private static NetlinkMessage parseRtMessage(@NonNull StructNlMsgHdr nlmsghdr,
            @NonNull ByteBuffer byteBuffer) {
        switch (nlmsghdr.nlmsg_type) {
            case NetlinkConstants.RTM_NEWNEIGH:
            case NetlinkConstants.RTM_DELNEIGH:
            case NetlinkConstants.RTM_GETNEIGH:
                return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
            case NetlinkConstants.RTM_NEWNDUSEROPT:
                return (NetlinkMessage) NduseroptMessage.parse(nlmsghdr, byteBuffer);
            default: return null;
        }
    }

    @Nullable
    private static NetlinkMessage parseInetDiagMessage(@NonNull StructNlMsgHdr nlmsghdr,
            @NonNull ByteBuffer byteBuffer) {
        switch (nlmsghdr.nlmsg_type) {
            case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
                return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
            default: return null;
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ public class NetlinkSocket {
            sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
            final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
            // recvMessage() guaranteed to not return null if it did not throw.
            final NetlinkMessage response = NetlinkMessage.parse(bytes);
            final NetlinkMessage response = NetlinkMessage.parse(bytes, nlProto);
            if (response != null && response instanceof NetlinkErrorMessage &&
                    (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
                final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
+2 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.NETLINK_INET_DIAG;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -249,7 +250,7 @@ public class InetDiagSocketTest {
    public void testParseInetDiagResponse() throws Exception {
        final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG);
        assertNotNull(msg);

        assertTrue(msg instanceof InetDiagMessage);
Loading