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

 RandomSpi(int min, int max) : mMin(min) {
        std::mt19937 rnd = std::mt19937(std::random_device()());
        mNext = std::uniform_int_distribution<>(1, INT_MAX)(rnd);
        mSize = max - min + 1;
        mCount = mSize;
 }

Project: Android

XfrmController::XfrmController(void) {}

Project: Android

StatusOr<uint16_t> convertStringAddress(std::string addr, uint8_t* buffer) {
 if (inet_pton(AF_INET, addr.c_str(), buffer) == 1) {
 return AF_INET;
 } else if (inet_pton(AF_INET6, addr.c_str(), buffer) == 1) {
 return AF_INET6;
 } else {
 return Status(EAFNOSUPPORT);
 }
}

Project: Android

netdutils::Status XfrmController::deleteSecurityAssociation(const XfrmId& record,
 const XfrmSocket& sock) {
    xfrm_usersa_id said{};
    nlattr_xfrm_mark xfrmmark{};

 enum { NLMSG_HDR, USERSAID, USERSAID_PAD, MARK, MARK_PAD };

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

 int len;
    len = iov[USERSAID].iov_len = fillUserSaId(record, &said);
    iov[USERSAID_PAD].iov_len = NLMSG_ALIGN(len) - len;

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

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

Project: Android

netdutils::Status XfrmController::deleteTunnelModeSecurityPolicy(const XfrmSaInfo& record,
 const XfrmSocket& sock,
 XfrmDirection direction) {
    xfrm_userpolicy_id policyid{};
    nlattr_xfrm_mark xfrmmark{};

 enum {
        NLMSG_HDR,
        USERPOLICYID,
        USERPOLICYID_PAD,
        MARK,
        MARK_PAD,
 };

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

 int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, direction, &policyid);
    iov[USERPOLICYID_PAD].iov_len = NLMSG_ALIGN(len) - len;

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

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

Project: Android

size_t fillNlAttr(__u16 nlaType, size_t valueSize, nlattr* nlAttr) {
 size_t dataLen = valueSize;
 int padLength = NLMSG_ALIGN(dataLen) - dataLen;
    nlAttr->nla_len = (__u16)(dataLen + sizeof(nlattr));
    nlAttr->nla_type = nlaType;
 return padLength;
}

Project: Android

size_t fillNlAttrIpAddress(__u16 nlaType, int family, const std::string& value, nlattr* nlAttr,
 Slice ipAddress) {
    inet_pton(family, value.c_str(), ipAddress.base());
 return fillNlAttr(nlaType, (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr), nlAttr);
}

Project: Android

size_t fillNlAttrU32(__u16 nlaType, int32_t value, nlattr* nlAttr, uint32_t* u32Value) {
 *u32Value = htonl(value);
 return fillNlAttr(nlaType, sizeof((*u32Value)), nlAttr);
}

Project: Android

int XfrmController::fillNlAttrUserTemplate(const XfrmSaInfo& record, nlattr_user_tmpl* tmpl) {
    fillUserTemplate(record, &tmpl->tmpl);

 int len = NLA_HDRLEN + sizeof(xfrm_user_tmpl);
    fillXfrmNlaHdr(&tmpl->hdr, XFRMA_TMPL, len);
 return len;
}

Project: Android

int XfrmController::fillNlAttrXfrmAlgoAead(const XfrmAlgo& inAlgo, nlattr_algo_aead* algo) {
 if (inAlgo.name.empty()) { // Do not fill anything if algorithm not provided
 return 0;
 }

 int len = NLA_HDRLEN + sizeof(xfrm_algo_aead);
    strncpy(algo->aead.alg_name, inAlgo.name.c_str(), sizeof(algo->aead.alg_name));
    algo->aead.alg_key_len = inAlgo.key.size() * 8; // bits

    algo->aead.alg_icv_len = inAlgo.truncLenBits;

    memcpy(algo->key, &inAlgo.key[0], inAlgo.key.size());
    len += inAlgo.key.size();

    fillXfrmNlaHdr(&algo->hdr, XFRMA_ALG_AEAD, len);
 return len;
}

Project: Android

int XfrmController::fillNlAttrXfrmAlgoAuth(const XfrmAlgo& inAlgo, nlattr_algo_auth* algo) {
 if (inAlgo.name.empty()) { // Do not fill anything if algorithm not provided
 return 0;
 }

 int len = NLA_HDRLEN + sizeof(xfrm_algo_auth);
    strncpy(algo->auth.alg_name, inAlgo.name.c_str(), sizeof(algo->auth.alg_name));
    algo->auth.alg_key_len = inAlgo.key.size() * 8; // bits

    algo->auth.alg_trunc_len = inAlgo.truncLenBits;

    memcpy(algo->key, &inAlgo.key[0], inAlgo.key.size());
    len += inAlgo.key.size();

    fillXfrmNlaHdr(&algo->hdr, XFRMA_ALG_AUTH_TRUNC, len);
 return len;
}

Project: Android

int XfrmController::fillNlAttrXfrmAlgoEnc(const XfrmAlgo& inAlgo, nlattr_algo_crypt* algo) {
 if (inAlgo.name.empty()) { // Do not fill anything if algorithm not provided
 return 0;
 }

 int len = NLA_HDRLEN + sizeof(xfrm_algo);
    strncpy(algo->crypt.alg_name, inAlgo.name.c_str(), sizeof(algo->crypt.alg_name));
    algo->crypt.alg_key_len = inAlgo.key.size() * 8; // bits
    memcpy(algo->key, &inAlgo.key[0], inAlgo.key.size());
    len += inAlgo.key.size();
    fillXfrmNlaHdr(&algo->hdr, XFRMA_ALG_CRYPT, len);
 return len;
}

Project: Android

int XfrmController::fillNlAttrXfrmEncapTmpl(const XfrmSaInfo& record, nlattr_encap_tmpl* tmpl) {
 if (record.encap.type == XfrmEncapType::NONE) {
 return 0;
 }

 int len = NLA_HDRLEN + sizeof(xfrm_encap_tmpl);
    tmpl->tmpl.encap_type = static_cast<uint16_t>(record.encap.type);
    tmpl->tmpl.encap_sport = htons(record.encap.srcPort);
    tmpl->tmpl.encap_dport = htons(record.encap.dstPort);
    fillXfrmNlaHdr(&tmpl->hdr, XFRMA_ENCAP, len);
 return len;
}

Project: Android

int XfrmController::fillNlAttrXfrmMark(const XfrmId& record, nlattr_xfrm_mark* mark) {
    mark->mark.v = record.mark.v; // set to 0 if it's not used
    mark->mark.m = record.mark.m; // set to 0 if it's not used
 int len = NLA_HDRLEN + sizeof(xfrm_mark);
    fillXfrmNlaHdr(&mark->hdr, XFRMA_MARK, len);
 return len;
}

Project: Android

int XfrmController::fillNlAttrXfrmOutputMark(const __u32 output_mark_value,
                                             nlattr_xfrm_output_mark* output_mark) {
 if (output_mark_value == 0) {
 return 0;
 }

    output_mark->outputMark = output_mark_value;
 int len = NLA_HDRLEN + sizeof(__u32);
    fillXfrmNlaHdr(&output_mark->hdr, XFRMA_OUTPUT_MARK, len);
 return len;
}

Project: Android

int XfrmController::fillTransportModeUserSpInfo(const XfrmSaInfo& record, XfrmDirection direction,
                                                xfrm_userpolicy_info* usersp) {
    fillXfrmSelector(record, &usersp->sel);
    fillXfrmLifetimeDefaults(&usersp->lft);
    fillXfrmCurLifetimeDefaults(&usersp->curlft);
 /* if (index) index & 0x3 == dir -- must be true
     * xfrm_user.c:verify_newpolicy_info() */
    usersp->index = 0;
    usersp->dir = static_cast<uint8_t>(direction);
    usersp->action = XFRM_POLICY_ALLOW;
    usersp->flags = XFRM_POLICY_LOCALOK;
    usersp->share = XFRM_SHARE_UNIQUE;
 return sizeof(*usersp);
}

Project: Android

int XfrmController::fillUserPolicyId(const XfrmSaInfo& record, XfrmDirection direction,
                                     xfrm_userpolicy_id* usersp) {
    fillXfrmSelector(record, &usersp->sel);
    usersp->dir = static_cast<uint8_t>(direction);
 return sizeof(*usersp);
}

Project: Android

int XfrmController::fillUserSaId(const XfrmId& record, xfrm_usersa_id* said) {
    said->daddr = record.dstAddr;
    said->spi = record.spi;
    said->family = record.addrFamily;
    said->proto = IPPROTO_ESP;

 return sizeof(*said);
}

Project: Android

int XfrmController::fillUserSaInfo(const XfrmSaInfo& record, xfrm_usersa_info* usersa) {
    fillXfrmSelector(record, &usersa->sel);

    usersa->id.proto = IPPROTO_ESP;
    usersa->id.spi = record.spi;
    usersa->id.daddr = record.dstAddr;

    usersa->saddr = record.srcAddr;

    fillXfrmLifetimeDefaults(&usersa->lft);
    fillXfrmCurLifetimeDefaults(&usersa->curlft);
    memset(&usersa->stats, 0, sizeof(usersa->stats)); // leave stats zeroed out
    usersa->reqid = record.transformId;
    usersa->family = record.addrFamily;
    usersa->mode = static_cast<uint8_t>(record.mode);
    usersa->replay_window = REPLAY_WINDOW_SIZE;

 if (record.mode == XfrmMode::TRANSPORT) {
        usersa->flags = 0; // TODO: should we actually set flags, XFRM_SA_XFLAG_DONT_ENCAP_DSCP?
 } else {
        usersa->flags = XFRM_STATE_AF_UNSPEC;
 }

 return sizeof(*usersa);
}

Project: Android

int XfrmController::fillUserTemplate(const XfrmSaInfo& record, xfrm_user_tmpl* tmpl) {
    tmpl->id.daddr = record.dstAddr;
    tmpl->id.spi = record.spi;
    tmpl->id.proto = IPPROTO_ESP;

    tmpl->family = record.addrFamily;
    tmpl->saddr = record.srcAddr;
    tmpl->reqid = record.transformId;
    tmpl->mode = static_cast<uint8_t>(record.mode);
    tmpl->share = XFRM_SHARE_UNIQUE;
    tmpl->optional = 0; // if this is true, then a failed state lookup will be considered OK:
    tmpl->aalgos = ALGO_MASK_AUTH_ALL; // TODO: if there's a bitmask somewhere of
    tmpl->ealgos = ALGO_MASK_CRYPT_ALL; // TODO: if there's a bitmask somewhere...
 return sizeof(xfrm_user_tmpl*);
}

Project: Android

void fillXfrmNlaHdr(nlattr* hdr, uint16_t type, uint16_t len) {
    hdr->nla_type = type;
    hdr->nla_len = len;
}

Project: Android

void XfrmController::fillXfrmSelector(const XfrmSaInfo& record, xfrm_selector* selector) {
    selector->family = record.addrFamily;
    selector->proto = AF_UNSPEC; // TODO: do we need to match the protocol? it's
}

Project: Android

netdutils::Status XfrmController::flushInterfaces() {
 const auto& ifaces = InterfaceController::getIfaceNames();
    RETURN_IF_NOT_OK(ifaces);
 const String8 ifPrefix8 = String8(INetd::IPSEC_INTERFACE_PREFIX().string());

 for (const std::string& iface : ifaces.value()) {
 int status = 0;
 if (!iface.compare(0, ifPrefix8.length(), ifPrefix8.c_str()) &&
 (status = removeVirtualTunnelInterface(iface)) < 0) {
            ALOGE("Failed to delete ipsec tunnel %s.", iface.c_str());
 return netdutils::statusFromErrno(status, "Failed to remove ipsec tunnel.");
 }
 }
 return netdutils::status::ok;
}

Project: Android

netdutils::Status XfrmController::flushSaDb(const XfrmSocket& s) {
 struct xfrm_usersa_flush flushUserSa = {.proto = IPSEC_PROTO_ANY};

    std::vector<iovec> iov = {{NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR
 {&flushUserSa, sizeof(flushUserSa)}, // xfrm_usersa_flush structure
 {kPadBytes, NLMSG_ALIGN(sizeof(flushUserSa)) - sizeof(flushUserSa)}};

 return s.sendMessage(XFRM_MSG_FLUSHSA, NETLINK_REQUEST_FLAGS, 0, &iov);
}

Project: Android

inline Syscalls& getSyscallInstance() { return netdutils::sSyscalls.get(); }

Project: Android

netdutils::Status XfrmController::ipSecAddSecurityAssociation(
 int32_t transformId, int32_t mode, const std::string& sourceAddress,
 const std::string& destinationAddress, int32_t underlyingNetId, int32_t spi, int32_t markValue,
 int32_t markMask, const std::string& authAlgo, const std::vector<uint8_t>& authKey,
 int32_t authTruncBits, const std::string& cryptAlgo, const std::vector<uint8_t>& cryptKey,
 int32_t cryptTruncBits, const std::string& aeadAlgo, const std::vector<uint8_t>& aeadKey,
 int32_t aeadIcvBits, int32_t encapType, int32_t encapLocalPort, int32_t encapRemotePort) {
    ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
    ALOGD("transformId=%d", transformId);
    ALOGD("mode=%d", mode);
    ALOGD("sourceAddress=%s", sourceAddress.c_str());
    ALOGD("destinationAddress=%s", destinationAddress.c_str());
    ALOGD("underlyingNetworkId=%d", underlyingNetId);
    ALOGD("spi=%0.8x", spi);
    ALOGD("markValue=%x", markValue);
    ALOGD("markMask=%x", markMask);
    ALOGD("authAlgo=%s", authAlgo.c_str());
    ALOGD("authTruncBits=%d", authTruncBits);
    ALOGD("cryptAlgo=%s", cryptAlgo.c_str());
    ALOGD("cryptTruncBits=%d,", cryptTruncBits);
    ALOGD("aeadAlgo=%s", aeadAlgo.c_str());
    ALOGD("aeadIcvBits=%d,", aeadIcvBits);
    ALOGD("encapType=%d", encapType);
    ALOGD("encapLocalPort=%d", encapLocalPort);
    ALOGD("encapRemotePort=%d", encapRemotePort);

 XfrmSaInfo saInfo{};
    netdutils::Status ret = fillXfrmId(sourceAddress, destinationAddress, spi, markValue, markMask,
                                       transformId, &saInfo);
 if (!isOk(ret)) {
 return ret;
 }

    saInfo.auth = XfrmAlgo{
 .name = authAlgo, .key = authKey, .truncLenBits = static_cast<uint16_t>(authTruncBits)};

    saInfo.crypt = XfrmAlgo{
 .name = cryptAlgo, .key = cryptKey, .truncLenBits = static_cast<uint16_t>(cryptTruncBits)};

    saInfo.aead = XfrmAlgo{
 .name = aeadAlgo, .key = aeadKey, .truncLenBits = static_cast<uint16_t>(aeadIcvBits)};

 switch (static_cast<XfrmMode>(mode)) {
 case XfrmMode::TRANSPORT:
 case XfrmMode::TUNNEL:
            saInfo.mode = static_cast<XfrmMode>(mode);
 break;
 default:
 return netdutils::statusFromErrno(EINVAL, "Invalid xfrm mode");
 }

 XfrmSocketImpl sock;
    netdutils::Status socketStatus = sock.open();
 if (!isOk(socketStatus)) {
        ALOGD("Sock open failed for XFRM, line=%d", __LINE__);
 return socketStatus;
 }

 switch (static_cast<XfrmEncapType>(encapType)) {
 case XfrmEncapType::ESPINUDP:
 case XfrmEncapType::ESPINUDP_NON_IKE:
 if (saInfo.addrFamily != AF_INET) {
 return netdutils::statusFromErrno(EAFNOSUPPORT, "IPv6 encap not supported");
 }
            saInfo.encap.srcPort = encapLocalPort;
            saInfo.encap.dstPort = encapRemotePort;
 case XfrmEncapType::NONE:
            saInfo.encap.type = static_cast<XfrmEncapType>(encapType);
 break;
 default:
 return netdutils::statusFromErrno(EINVAL, "Invalid encap type");
 }

    saInfo.netId = underlyingNetId;

    ret = updateSecurityAssociation(saInfo, sock);
 if (!isOk(ret)) {
        ALOGD("Failed updating a Security Association, line=%d", __LINE__);
 }

 return ret;
}

Project: Android

netdutils::Status XfrmController::ipSecAddSecurityPolicy(int32_t transformId, int32_t direction,
 const std::string& localAddress,
 const std::string& remoteAddress,
 int32_t spi, int32_t markValue,
 int32_t markMask) {
 return processSecurityPolicy(transformId, direction, localAddress, remoteAddress, spi,
                                 markValue, markMask, XFRM_MSG_NEWPOLICY);
}

Project: Android

netdutils::Status XfrmController::ipSecAllocateSpi(int32_t transformId,
 const std::string& sourceAddress,
 const std::string& destinationAddress,
 int32_t inSpi, int32_t* outSpi) {
    ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);
    ALOGD("transformId=%d", transformId);
    ALOGD("sourceAddress=%s", sourceAddress.c_str());
    ALOGD("destinationAddress=%s", destinationAddress.c_str());
    ALOGD("inSpi=%0.8x", inSpi);

 XfrmSaInfo saInfo{};
    netdutils::Status ret =
        fillXfrmId(sourceAddress, destinationAddress, INVALID_SPI, 0, 0, transformId, &saInfo);
 if (!isOk(ret)) {
 return ret;
 }

 XfrmSocketImpl sock;
    netdutils::Status socketStatus = sock.open();
 if (!isOk(socketStatus)) {
        ALOGD("Sock open failed for XFRM, line=%d", __LINE__);
 return socketStatus;
 }

 int minSpi = RAND_SPI_MIN, maxSpi = RAND_SPI_MAX;

 if (inSpi)
        minSpi = maxSpi = inSpi;

    ret = allocateSpi(saInfo, minSpi, maxSpi, reinterpret_cast<uint32_t*>(outSpi), sock);
 if (!isOk(ret)) {
        ALOGD("Failed to Allocate an SPI, line=%d", __LINE__);
 *outSpi = INVALID_SPI;
 }

 return ret;
}

Project: Android

netdutils::Status XfrmController::ipSecApplyTransportModeTransform(
 const android::base::unique_fd& socket, int32_t transformId, int32_t direction,
 const std::string& sourceAddress, const std::string& destinationAddress, int32_t spi) {
    ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
    ALOGD("transformId=%d", transformId);
    ALOGD("direction=%d", direction);
    ALOGD("sourceAddress=%s", sourceAddress.c_str());
    ALOGD("destinationAddress=%s", destinationAddress.c_str());
    ALOGD("spi=%0.8x", spi);

 StatusOr<sockaddr_storage> ret = getSyscallInstance().getsockname<sockaddr_storage>(Fd(socket));
 if (!isOk(ret)) {
        ALOGE("Failed to get socket info in %s", __FUNCTION__);
 return ret;
 }
 struct sockaddr_storage saddr = ret.value();

 XfrmSaInfo saInfo{};
    netdutils::Status status =
        fillXfrmId(sourceAddress, destinationAddress, spi, 0, 0, transformId, &saInfo);
 if (!isOk(status)) {
        ALOGE("Couldn't build SA ID %s", __FUNCTION__);
 return status;
 }

 if (saddr.ss_family == AF_INET && saInfo.addrFamily != AF_INET) {
        ALOGE("IPV4 socket address family(%d) should match IPV4 Transform "
 "address family(%d)!",
              saddr.ss_family, saInfo.addrFamily);
 return netdutils::statusFromErrno(EINVAL, "Mismatched address family");
 }

 struct {
        xfrm_userpolicy_info info;
        xfrm_user_tmpl tmpl;
 } policy{};

    fillTransportModeUserSpInfo(saInfo, static_cast<XfrmDirection>(direction), &policy.info);
    fillUserTemplate(saInfo, &policy.tmpl);

    LOG_HEX("XfrmUserPolicy", reinterpret_cast<char*>(&policy), sizeof(policy));

 int sockOpt, sockLayer;
 switch (saddr.ss_family) {
 case AF_INET:
            sockOpt = IP_XFRM_POLICY;
            sockLayer = SOL_IP;
 break;
 case AF_INET6:
            sockOpt = IPV6_XFRM_POLICY;
            sockLayer = SOL_IPV6;
 break;
 default:
 return netdutils::statusFromErrno(EAFNOSUPPORT, "Invalid address family");
 }

    status = getSyscallInstance().setsockopt(Fd(socket), sockLayer, sockOpt, policy);
 if (!isOk(status)) {
        ALOGE("Error setting socket option for XFRM! (%s)", toString(status).c_str());
 }

 return status;
}

Project: Android

netdutils::Status XfrmController::ipSecDeleteSecurityAssociation(
 int32_t transformId, const std::string& sourceAddress, const std::string& destinationAddress,
 int32_t spi, int32_t markValue, int32_t markMask) {
    ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);
    ALOGD("transformId=%d", transformId);
    ALOGD("sourceAddress=%s", sourceAddress.c_str());
    ALOGD("destinationAddress=%s", destinationAddress.c_str());
    ALOGD("spi=%0.8x", spi);
    ALOGD("markValue=%x", markValue);
    ALOGD("markMask=%x", markMask);

 XfrmId saId{};
    netdutils::Status ret =
        fillXfrmId(sourceAddress, destinationAddress, spi, markValue, markMask, transformId, &saId);
 if (!isOk(ret)) {
 return ret;
 }

 XfrmSocketImpl sock;
    netdutils::Status socketStatus = sock.open();
 if (!isOk(socketStatus)) {
        ALOGD("Sock open failed for XFRM, line=%d", __LINE__);
 return socketStatus;
 }

    ret = deleteSecurityAssociation(saId, sock);
 if (!isOk(ret)) {
        ALOGD("Failed to delete Security Association, line=%d", __LINE__);
 }

 return ret;
}

Project: Android

XfrmController::ipSecRemoveTransportModeTransform(const android::base::unique_fd& socket) {
    ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);

 StatusOr<sockaddr_storage> ret = getSyscallInstance().getsockname<sockaddr_storage>(Fd(socket));
 if (!isOk(ret)) {
        ALOGE("Failed to get socket info in %s! (%s)", __FUNCTION__, toString(ret).c_str());
 return ret;
 }

 int sockOpt, sockLayer;
 switch (ret.value().ss_family) {
 case AF_INET:
            sockOpt = IP_XFRM_POLICY;
            sockLayer = SOL_IP;
 break;
 case AF_INET6:
            sockOpt = IPV6_XFRM_POLICY;
            sockLayer = SOL_IPV6;
 break;
 default:
 return netdutils::statusFromErrno(EAFNOSUPPORT, "Invalid address family");
 }

    netdutils::Status status =
        getSyscallInstance().setsockopt(Fd(socket), sockLayer, sockOpt, NULL, 0);
 if (!isOk(status)) {
        ALOGE("Error removing socket option for XFRM! (%s)", toString(status).c_str());
 }

 return status;
}

Project: Android

netdutils::Status XfrmController::ipSecUpdateSecurityPolicy(int32_t transformId, int32_t direction,
 const std::string& localAddress,
 const std::string& remoteAddress,
 int32_t spi, int32_t markValue,
 int32_t markMask) {
 return processSecurityPolicy(transformId, direction, localAddress, remoteAddress, spi,
                                 markValue, markMask, XFRM_MSG_UPDPOLICY);
}

Project: Android

static inline bool isEngBuild() {
 static const std::string sBuildType = android::base::GetProperty("ro.build.type", "user");
 return sBuildType == "eng";
}

Project: Android

void logIov(const std::vector<iovec>& iov) {
 for (const iovec& row : iov) {
        logHex(0, reinterpret_cast<char*>(row.iov_base), row.iov_len);
 }
}

Project: Android

netdutils::Status XfrmController::processSecurityPolicy(int32_t transformId, int32_t direction,
 const std::string& localAddress,
 const std::string& remoteAddress,
 int32_t spi, int32_t markValue,
 int32_t markMask, int32_t msgType) {
    ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
    ALOGD("transformId=%d", transformId);
    ALOGD("direction=%d", direction);
    ALOGD("localAddress=%s", localAddress.c_str());
    ALOGD("remoteAddress=%s", remoteAddress.c_str());
    ALOGD("spi=%0.8x", spi);
    ALOGD("markValue=%d", markValue);
    ALOGD("markMask=%d", markMask);
    ALOGD("msgType=%d", msgType);

 XfrmSaInfo saInfo{};
    saInfo.mode = XfrmMode::TUNNEL;

 XfrmSocketImpl sock;
    RETURN_IF_NOT_OK(sock.open());

    RETURN_IF_NOT_OK(
        fillXfrmId(localAddress, remoteAddress, spi, markValue, markMask, transformId, &saInfo));

 if (msgType == XFRM_MSG_DELPOLICY) {
 return deleteTunnelModeSecurityPolicy(saInfo, sock, static_cast<XfrmDirection>(direction));
 } else {
 return updateTunnelModeSecurityPolicy(saInfo, sock, static_cast<XfrmDirection>(direction),
                                              msgType);
 }
}

Project: Android

int XfrmController::removeVirtualTunnelInterface(const std::string& deviceName) {
    ALOGD("XfrmController::%s, line=%d", __FUNCTION__, __LINE__);
    ALOGD("deviceName=%s", deviceName.c_str());

 if (deviceName.empty()) {
 return EINVAL;
 }

 uint8_t PADDING_BUFFER[] = {0, 0, 0, 0};

    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);

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

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

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

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

Project: Android

netdutils::Status XfrmController::updateSecurityAssociation(const XfrmSaInfo& record,
 const XfrmSocket& sock) {
    xfrm_usersa_info usersa{};
    nlattr_algo_crypt crypt{};
    nlattr_algo_auth auth{};
    nlattr_algo_aead aead{};
    nlattr_xfrm_mark xfrmmark{};
    nlattr_xfrm_output_mark xfrmoutputmark{};
    nlattr_encap_tmpl encap{};

 enum {
        NLMSG_HDR,
        USERSA,
        USERSA_PAD,
        CRYPT,
        CRYPT_PAD,
        AUTH,
        AUTH_PAD,
        AEAD,
        AEAD_PAD,
        MARK,
        MARK_PAD,
        OUTPUT_MARK,
        OUTPUT_MARK_PAD,
        ENCAP,
        ENCAP_PAD,
 };

    std::vector<iovec> iov = {
 {NULL, 0}, // reserved for the eventual addition of a NLMSG_HDR
 {&usersa, 0}, // main usersa_info struct
 {kPadBytes, 0}, // up to NLMSG_ALIGNTO pad bytes of padding
 {&crypt, 0}, // adjust size if crypt algo is present
 {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
 {&auth, 0}, // adjust size if auth algo is present
 {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
 {&aead, 0}, // adjust size if aead algo 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
 {&xfrmoutputmark, 0}, // adjust size if xfrm output mark is present
 {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
 {&encap, 0}, // adjust size if encapsulating
 {kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
 };

 if (!record.aead.name.empty() && (!record.auth.name.empty() || !record.crypt.name.empty())) {
 return netdutils::statusFromErrno(EINVAL, "Invalid xfrm algo selection; AEAD is mutually "
 "exclusive with both Authentication and "
 "Encryption");
 }

 if (record.aead.key.size() > MAX_KEY_LENGTH || record.auth.key.size() > MAX_KEY_LENGTH ||
        record.crypt.key.size() > MAX_KEY_LENGTH) {
 return netdutils::statusFromErrno(EINVAL, "Key length invalid; exceeds MAX_KEY_LENGTH");
 }

 int len;
    len = iov[USERSA].iov_len = fillUserSaInfo(record, &usersa);
    iov[USERSA_PAD].iov_len = NLMSG_ALIGN(len) - len;

    len = iov[CRYPT].iov_len = fillNlAttrXfrmAlgoEnc(record.crypt, &crypt);
    iov[CRYPT_PAD].iov_len = NLA_ALIGN(len) - len;

    len = iov[AUTH].iov_len = fillNlAttrXfrmAlgoAuth(record.auth, &auth);
    iov[AUTH_PAD].iov_len = NLA_ALIGN(len) - len;

    len = iov[AEAD].iov_len = fillNlAttrXfrmAlgoAead(record.aead, &aead);
    iov[AEAD_PAD].iov_len = NLA_ALIGN(len) - len;

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

    len = iov[OUTPUT_MARK].iov_len = fillNlAttrXfrmOutputMark(record.netId, &xfrmoutputmark);
    iov[OUTPUT_MARK_PAD].iov_len = NLA_ALIGN(len) - len;

    len = iov[ENCAP].iov_len = fillNlAttrXfrmEncapTmpl(record, &encap);
    iov[ENCAP_PAD].iov_len = NLA_ALIGN(len) - len;

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

Project: Android

 static netdutils::Status validateResponse(NetlinkResponse response, size_t len) {
 if (len < sizeof(nlmsghdr)) {
            ALOGW("Invalid response message received over netlink");
 return netdutils::statusFromErrno(EBADMSG, "Invalid message");
 }

 switch (response.hdr.nlmsg_type) {
 case NLMSG_NOOP:
 case NLMSG_DONE:
 return netdutils::status::ok;
 case NLMSG_OVERRUN:
                ALOGD("Netlink request overran kernel buffer");
 return netdutils::statusFromErrno(EBADMSG, "Kernel buffer overrun");
 case NLMSG_ERROR:
 if (len < sizeof(NetlinkResponse::_err_)) {
                    ALOGD("Netlink message received malformed error response");
 return netdutils::statusFromErrno(EBADMSG, "Malformed error response");
 }
 return netdutils::statusFromErrno(
 -response.err.err.error,
 "Error netlink message"); // Netlink errors are negative errno.
 case XFRM_MSG_NEWSA:
 break;
 }

 if (response.hdr.nlmsg_type < XFRM_MSG_BASE /*== NLMSG_MIN_TYPE*/ ||
            response.hdr.nlmsg_type > XFRM_MSG_MAX) {
            ALOGD("Netlink message responded with an out-of-range message ID");
 return netdutils::statusFromErrno(EBADMSG, "Invalid message ID");
 }

 return netdutils::status::ok;
 }

Project: Android

const char* xfrmMsgTypeToString(uint16_t msg) {
 switch (msg) {
        XFRM_MSG_TRANS(XFRM_MSG_NEWSA)
        XFRM_MSG_TRANS(XFRM_MSG_DELSA)
        XFRM_MSG_TRANS(XFRM_MSG_GETSA)
        XFRM_MSG_TRANS(XFRM_MSG_NEWPOLICY)
        XFRM_MSG_TRANS(XFRM_MSG_DELPOLICY)
        XFRM_MSG_TRANS(XFRM_MSG_GETPOLICY)
        XFRM_MSG_TRANS(XFRM_MSG_ALLOCSPI)
        XFRM_MSG_TRANS(XFRM_MSG_ACQUIRE)
        XFRM_MSG_TRANS(XFRM_MSG_EXPIRE)
        XFRM_MSG_TRANS(XFRM_MSG_UPDPOLICY)
        XFRM_MSG_TRANS(XFRM_MSG_UPDSA)
        XFRM_MSG_TRANS(XFRM_MSG_POLEXPIRE)
        XFRM_MSG_TRANS(XFRM_MSG_FLUSHSA)
        XFRM_MSG_TRANS(XFRM_MSG_FLUSHPOLICY)
        XFRM_MSG_TRANS(XFRM_MSG_NEWAE)
        XFRM_MSG_TRANS(XFRM_MSG_GETAE)
        XFRM_MSG_TRANS(XFRM_MSG_REPORT)
        XFRM_MSG_TRANS(XFRM_MSG_MIGRATE)
        XFRM_MSG_TRANS(XFRM_MSG_NEWSADINFO)
        XFRM_MSG_TRANS(XFRM_MSG_GETSADINFO)
        XFRM_MSG_TRANS(XFRM_MSG_GETSPDINFO)
        XFRM_MSG_TRANS(XFRM_MSG_NEWSPDINFO)
        XFRM_MSG_TRANS(XFRM_MSG_MAPPING)
 default:
 return "XFRM_MSG UNKNOWN";
 }
}