Commit message: None
CVE: CVE-2018-9511
CWE: CWE-909
Vulnerability description: In ipSecSetEncapSocketOwner of XfrmController.cpp, there is a possible failure to initialize a security feature due to uninitialized data. This could lead to local denial of service of IPsec on sockets with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-9.0 Android ID: A-111650288

Project: Android

netdutils::Status XfrmController::Init() {
    RETURN_IF_NOT_OK(flushInterfaces());
 XfrmSocketImpl sock;
    RETURN_IF_NOT_OK(sock.open());
    RETURN_IF_NOT_OK(flushSaDb(sock));
 return flushPolicyDb(sock);
}

Project: Android

int XfrmController::addVirtualTunnelInterface(const std::string& deviceName,
 const std::string& localAddress,
 const std::string& remoteAddress, int32_t ikey,
 int32_t okey, bool isUpdate) {
    ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
    ALOGD("deviceName=%s", deviceName.c_str());
    ALOGD("localAddress=%s", localAddress.c_str());
    ALOGD("remoteAddress=%s", remoteAddress.c_str());
    ALOGD("ikey=%0.8x", ikey);
    ALOGD("okey=%0.8x", okey);
    ALOGD("isUpdate=%d", isUpdate);

 if (deviceName.empty() || localAddress.empty() || remoteAddress.empty()) {
 return EINVAL;
 }

 const char* INFO_KIND_VTI6 = "vti6";
 const char* INFO_KIND_VTI = "vti";
 uint8_t PADDING_BUFFER[] = {0, 0, 0, 0};

 uint8_t remAddr[sizeof(in6_addr)];

 StatusOr<uint16_t> statusOrRemoteFam = convertStringAddress(remoteAddress, remAddr);
 if (!isOk(statusOrRemoteFam)) {
 return statusOrRemoteFam.status().code();
 }

 uint8_t locAddr[sizeof(in6_addr)];
 StatusOr<uint16_t> statusOrLocalFam = convertStringAddress(localAddress, locAddr);
 if (!isOk(statusOrLocalFam)) {
 return statusOrLocalFam.status().code();
 }

 if (statusOrLocalFam.value() != statusOrRemoteFam.value()) {
 return EINVAL;
 }

 uint16_t family = statusOrLocalFam.value();

    ifinfomsg ifInfoMsg{};

    nlattr iflaIfName;
 char iflaIfNameStrValue[deviceName.length() + 1];
 size_t iflaIfNameLength =
        strlcpy(iflaIfNameStrValue, deviceName.c_str(), sizeof(iflaIfNameStrValue));
 size_t iflaIfNamePad = fillNlAttr(IFLA_IFNAME, iflaIfNameLength, &iflaIfName);

 const std::string infoKindValue = (family == AF_INET6) ? INFO_KIND_VTI6 : INFO_KIND_VTI;
    nlattr iflaIfInfoKind;
 char infoKindValueStrValue[infoKindValue.length() + 1];
 size_t iflaIfInfoKindLength =
        strlcpy(infoKindValueStrValue, infoKindValue.c_str(), sizeof(infoKindValueStrValue));
 size_t iflaIfInfoKindPad = fillNlAttr(IFLA_INFO_KIND, iflaIfInfoKindLength, &iflaIfInfoKind);

    nlattr iflaVtiLocal;
 uint8_t binaryLocalAddress[sizeof(in6_addr)];
 size_t iflaVtiLocalPad =
        fillNlAttrIpAddress(IFLA_VTI_LOCAL, family, localAddress, &iflaVtiLocal,
                            netdutils::makeSlice(binaryLocalAddress));

    nlattr iflaVtiRemote;
 uint8_t binaryRemoteAddress[sizeof(in6_addr)];
 size_t iflaVtiRemotePad =
        fillNlAttrIpAddress(IFLA_VTI_REMOTE, family, remoteAddress, &iflaVtiRemote,
                            netdutils::makeSlice(binaryRemoteAddress));

    nlattr iflaVtiIKey;
 uint32_t iKeyValue;
 size_t iflaVtiIKeyPad = fillNlAttrU32(IFLA_VTI_IKEY, ikey, &iflaVtiIKey, &iKeyValue);

    nlattr iflaVtiOKey;
 uint32_t oKeyValue;
 size_t iflaVtiOKeyPad = fillNlAttrU32(IFLA_VTI_OKEY, okey, &iflaVtiOKey, &oKeyValue);

 int iflaInfoDataPayloadLength = iflaVtiLocal.nla_len + iflaVtiLocalPad + iflaVtiRemote.nla_len +
                                    iflaVtiRemotePad + iflaVtiIKey.nla_len + iflaVtiIKeyPad +
                                    iflaVtiOKey.nla_len + iflaVtiOKeyPad;

    nlattr iflaInfoData;
 size_t iflaInfoDataPad = fillNlAttr(IFLA_INFO_DATA, iflaInfoDataPayloadLength, &iflaInfoData);

    nlattr iflaLinkInfo;
 size_t iflaLinkInfoPad = fillNlAttr(IFLA_LINKINFO,
                                        iflaInfoData.nla_len + iflaInfoDataPad +
                                            iflaIfInfoKind.nla_len + iflaIfInfoKindPad,
 &iflaLinkInfo);

    iovec iov[] = {
 {NULL, 0},
 {&ifInfoMsg, sizeof(ifInfoMsg)},

 {&iflaIfName, sizeof(iflaIfName)},
 {iflaIfNameStrValue, iflaIfNameLength},
 {&PADDING_BUFFER, iflaIfNamePad},

 {&iflaLinkInfo, sizeof(iflaLinkInfo)},

 {&iflaIfInfoKind, sizeof(iflaIfInfoKind)},
 {infoKindValueStrValue, iflaIfInfoKindLength},
 {&PADDING_BUFFER, iflaIfInfoKindPad},

 {&iflaInfoData, sizeof(iflaInfoData)},

 {&iflaVtiLocal, sizeof(iflaVtiLocal)},
 {&binaryLocalAddress, (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr)},
 {&PADDING_BUFFER, iflaVtiLocalPad},

 {&iflaVtiRemote, sizeof(iflaVtiRemote)},
 {&binaryRemoteAddress, (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr)},
 {&PADDING_BUFFER, iflaVtiRemotePad},

 {&iflaVtiIKey, sizeof(iflaVtiIKey)},
 {&iKeyValue, sizeof(iKeyValue)},
 {&PADDING_BUFFER, iflaVtiIKeyPad},

 {&iflaVtiOKey, sizeof(iflaVtiOKey)},
 {&oKeyValue, sizeof(oKeyValue)},
 {&PADDING_BUFFER, iflaVtiOKeyPad},

 {&PADDING_BUFFER, iflaInfoDataPad},

 {&PADDING_BUFFER, iflaLinkInfoPad},
 };

 uint16_t action = RTM_NEWLINK;
 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;

 if (!isUpdate) {
        flags |= NLM_F_EXCL | NLM_F_CREATE;
 }

 int ret = -1 * sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
 if (ret) {
        ALOGE("Error in %s virtual tunnel interface. Error Code: %d",
              isUpdate ? "updating" : "adding", ret);
 }
 return ret;
}

Project: Android

netdutils::Status XfrmController::allocateSpi(const XfrmSaInfo& record, uint32_t minSpi,
 uint32_t maxSpi, uint32_t* outSpi,
 const XfrmSocket& sock) {
    xfrm_userspi_info spiInfo{};

 enum { NLMSG_HDR, USERSAID, USERSAID_PAD };

    std::vector<iovec> iov = {
 {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR
 {&spiInfo, 0}, // main userspi_info struct
 {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
 };

 int len;
 if (fillUserSaInfo(record, &spiInfo.info) == 0) {
        ALOGE("Failed to fill transport SA Info");
 }

    len = iov[USERSAID].iov_len = sizeof(spiInfo);
    iov[USERSAID_PAD].iov_len = NLMSG_ALIGN(len) - len;

 RandomSpi spiGen = RandomSpi(minSpi, maxSpi);
 int spi;
    netdutils::Status ret;
 while ((spi = spiGen.next()) != INVALID_SPI) {
        spiInfo.min = spi;
        spiInfo.max = spi;
        ret = sock.sendMessage(XFRM_MSG_ALLOCSPI, NETLINK_REQUEST_FLAGS, 0, &iov);

 /* If the SPI is in use, we'll get ENOENT */
 if (netdutils::equalToErrno(ret, ENOENT))
 continue;

 if (isOk(ret)) {
 *outSpi = spi;
            ALOGD("Allocated an SPI: %x", *outSpi);
 } else {
 *outSpi = INVALID_SPI;
            ALOGE("SPI Allocation Failed with error %d", ret.code());
 }

 return ret;
 }

 return ret;
}

Project: Android

StatusOr<int> convertToXfrmAddr(const std::string& strAddr, xfrm_address_t* xfrmAddr) {
 if (strAddr.length() == 0) {
        memset(xfrmAddr, 0, sizeof(*xfrmAddr));
 return AF_UNSPEC;
 }

 if (inet_pton(AF_INET6, strAddr.c_str(), reinterpret_cast<void*>(xfrmAddr))) {
 return AF_INET6;
 } else if (inet_pton(AF_INET, strAddr.c_str(), reinterpret_cast<void*>(xfrmAddr))) {
 return AF_INET;
 } else {
 return netdutils::statusFromErrno(EAFNOSUPPORT, "Invalid address family");
 }
}

Project: Android

netdutils::Status XfrmController::fillXfrmId(const std::string& sourceAddress,
 const std::string& destinationAddress, int32_t spi,
 int32_t markValue, int32_t markMask,
 int32_t transformId, XfrmId* xfrmId) {
    xfrmId->transformId = transformId;
    xfrmId->spi = htonl(spi);
    xfrmId->mark.v = markValue;
    xfrmId->mark.m = markMask;

 xfrm_address_t sourceXfrmAddr{}, destXfrmAddr{};
 StatusOr<int> sourceFamily, destFamily;
    sourceFamily = convertToXfrmAddr(sourceAddress, &sourceXfrmAddr);
    destFamily = convertToXfrmAddr(destinationAddress, &destXfrmAddr);
 if (!isOk(sourceFamily) || !isOk(destFamily)) {
 return netdutils::statusFromErrno(EINVAL, "Invalid address " + sourceAddress + "/" +
                                                      destinationAddress);
 }

 if (destFamily.value() == AF_UNSPEC ||
 (sourceFamily.value() != AF_UNSPEC && sourceFamily.value() != destFamily.value())) {
        ALOGD("Invalid or Mismatched Address Families, %d != %d, line=%d", sourceFamily.value(),
              destFamily.value(), __LINE__);
 return netdutils::statusFromErrno(EINVAL, "Invalid or mismatched address families");
 }

    xfrmId->addrFamily = destFamily.value();

    xfrmId->dstAddr = destXfrmAddr;
    xfrmId->srcAddr = sourceXfrmAddr;
 return netdutils::status::ok;
}

Project: Android

netdutils::Status XfrmController::flushPolicyDb(const XfrmSocket& s) {
    std::vector<iovec> iov = {{NULL, 0}}; // reserved for the eventual addition of a NLMSG_HDR
 return s.sendMessage(XFRM_MSG_FLUSHPOLICY, NETLINK_REQUEST_FLAGS, 0, &iov);
}

Project: Android

netdutils::Status XfrmController::ipSecDeleteSecurityPolicy(int32_t transformId, int32_t direction,
 const std::string& localAddress,
 const std::string& remoteAddress,
 int32_t markValue, int32_t markMask) {
 return processSecurityPolicy(transformId, direction, localAddress, remoteAddress, 0, markValue,
                                 markMask, XFRM_MSG_DELPOLICY);
}

Project: Android

 uint32_t next() {
 if (!mCount)
 return 0;
        mCount--;
 return (mNext++ % mSize) + mMin;
 }

Project: Android

netdutils::Status XfrmController::updateTunnelModeSecurityPolicy(const XfrmSaInfo& record,
 const XfrmSocket& sock,
 XfrmDirection direction,
 uint16_t msgType) {
    xfrm_userpolicy_info userpolicy{};
    nlattr_user_tmpl usertmpl{};
    nlattr_xfrm_mark xfrmmark{};

 enum {
        NLMSG_HDR,
        USERPOLICY,
        USERPOLICY_PAD,
        USERTMPL,
        USERTMPL_PAD,
        MARK,
        MARK_PAD,
 };

    std::vector<iovec> iov = {
 {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR
 {&userpolicy, 0}, // main xfrm_userpolicy_info struct
 {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
 {&usertmpl, 0}, // adjust size if xfrm_user_tmpl struct is present
 {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
 {&xfrmmark, 0}, // adjust size if xfrm mark is present
 {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
 };

 int len;
    len = iov[USERPOLICY].iov_len = fillTransportModeUserSpInfo(record, direction, &userpolicy);
    iov[USERPOLICY_PAD].iov_len = NLMSG_ALIGN(len) - len;

    len = iov[USERTMPL].iov_len = fillNlAttrUserTemplate(record, &usertmpl);
    iov[USERTMPL_PAD].iov_len = NLA_ALIGN(len) - len;

    len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
    iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;

 return sock.sendMessage(msgType, NETLINK_REQUEST_FLAGS, 0, &iov);
}