OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
        OMX_BUFFERHEADERTYPE **header,
        OMX_U32 portIndex,
        OMX_PTR appPrivate,
        OMX_U32 size,
        OMX_U8 *ptr) {

     Mutex::Autolock autoLock(mLock);
     CHECK_LT(portIndex, mPorts.size());

    PortInfo *port = &mPorts.editItemAt(portIndex);
    if (size < port->mDef.nBufferSize) {
        ALOGE("b/63522430, Buffer size is too small.");
        android_errorWriteLog(0x534e4554, "63522430");
        return OMX_ErrorBadParameter;
    }

     *header = new OMX_BUFFERHEADERTYPE;
     (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE);
     (*header)->nVersion.s.nVersionMajor = 1;
 (*header)->nVersion.s.nVersionMinor = 0;
 (*header)->nVersion.s.nRevision = 0;
 (*header)->nVersion.s.nStep = 0;
 (*header)->pBuffer = ptr;
 (*header)->nAllocLen = size;
 (*header)->nFilledLen = 0;
 (*header)->nOffset = 0;
 (*header)->pAppPrivate = appPrivate;
 (*header)->pPlatformPrivate = NULL;
 (*header)->pInputPortPrivate = NULL;
 (*header)->pOutputPortPrivate = NULL;
 (*header)->hMarkTargetComponent = NULL;
 (*header)->pMarkData = NULL;
 (*header)->nTickCount = 0;
 (*header)->nTimeStamp = 0;
 (*header)->nFlags = 0;

     (*header)->nOutputPortIndex = portIndex;
     (*header)->nInputPortIndex = portIndex;

     CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);

     CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);

    port->mBuffers.push();

 BufferInfo *buffer =
 &port->mBuffers.editItemAt(port->mBuffers.size() - 1);

    buffer->mHeader = *header;
    buffer->mOwnedByUs = false;

 if (port->mBuffers.size() == port->mDef.nBufferCountActual) {
        port->mDef.bPopulated = OMX_TRUE;
        checkTransitions();
 }

 return OMX_ErrorNone;
}


sp<ABuffer> decodeBase64(const AString &s) {
 size_t n = s.size();
 if ((n % 4) != 0) {
 return NULL;
 }

 size_t padding = 0;
 if (n >= 1 && s.c_str()[n - 1] == '=') {
        padding = 1;

 if (n >= 2 && s.c_str()[n - 2] == '=') {
            padding = 2;

 if (n >= 3 && s.c_str()[n - 3] == '=') {
                padding = 3;
 }
 }
 }

 size_t outLen = (n / 4) * 3 - padding;

    sp<ABuffer> buffer = new ABuffer(outLen);

 uint8_t *out = buffer->data();
 if (out == NULL || buffer->size() < outLen) {
 return NULL;
 }
 size_t j = 0;
 uint32_t accum = 0;
 for (size_t i = 0; i < n; ++i) {
 char c = s.c_str()[i];
 unsigned value;
 if (c >= 'A' && c <= 'Z') {
            value = c - 'A';
 } else if (c >= 'a' && c <= 'z') {
            value = 26 + c - 'a';
 } else if (c >= '0' && c <= '9') {
            value = 52 + c - '0';
 } else if (c == '+') {
            value = 62;
 } else if (c == '/') {
            value = 63;
 } else if (c != '=') {
 return NULL;
 } else {
 if (i < n - padding) {
 return NULL;
 }

            value = 0;
 }

         accum = (accum << 6) | value;

         if (((i + 1) % 4) == 0) {
            out[j++] = (accum >> 16);
             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
             if (j < outLen) { out[j++] = accum & 0xff; }

            accum = 0;
 }
 }

 return buffer;
}

A remote code execution vulnerability in the Android media framework (libstagefright). Product: Android. Versions: 4.4.4, 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2, 8.0. Android ID: A-62673128.


sp<ABuffer> decodeBase64(const AString &s) {
 size_t n = s.size();
 if ((n % 4) != 0) {
 return NULL;
 }

 size_t padding = 0;
 if (n >= 1 && s.c_str()[n - 1] == '=') {
        padding = 1;

 if (n >= 2 && s.c_str()[n - 2] == '=') {
            padding = 2;

 if (n >= 3 && s.c_str()[n - 3] == '=') {
                padding = 3;
 }
 }
 }

 size_t outLen = (n / 4) * 3 - padding;

    sp<ABuffer> buffer = new ABuffer(outLen);

 uint8_t *out = buffer->data();
 if (out == NULL || buffer->size() < outLen) {
 return NULL;
 }
 size_t j = 0;
 uint32_t accum = 0;
 for (size_t i = 0; i < n; ++i) {
 char c = s.c_str()[i];
 unsigned value;
 if (c >= 'A' && c <= 'Z') {
            value = c - 'A';
 } else if (c >= 'a' && c <= 'z') {
            value = 26 + c - 'a';
 } else if (c >= '0' && c <= '9') {
            value = 52 + c - '0';
 } else if (c == '+') {
            value = 62;
 } else if (c == '/') {
            value = 63;
 } else if (c != '=') {
 return NULL;
 } else {
 if (i < n - padding) {
 return NULL;
 }

            value = 0;
 }

         accum = (accum << 6) | value;

         if (((i + 1) % 4) == 0) {
            if (j < outLen) { out[j++] = (accum >> 16); }
             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
             if (j < outLen) { out[j++] = accum & 0xff; }

            accum = 0;
 }
 }

 return buffer;
}


status_t BnSoundTriggerHwService::onTransact(
 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
 switch(code) {

         case LIST_MODULES: {
             CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
             unsigned int numModulesReq = data.readInt32();
             unsigned int numModules = numModulesReq;
             struct sound_trigger_module_descriptor *modules =
                     (struct sound_trigger_module_descriptor *)calloc(numModulesReq,
                                                    sizeof(struct sound_trigger_module_descriptor));
             status_t status = listModules(modules, &numModules);
             reply->writeInt32(status);
             reply->writeInt32(numModules);
            ALOGV("LIST_MODULES status %d got numModules %d", status, numModules);

 if (status == NO_ERROR) {
 if (numModulesReq > numModules) {
                    numModulesReq = numModules;
 }
                reply->write(modules,
                             numModulesReq * sizeof(struct sound_trigger_module_descriptor));
 }
            free(modules);
 return NO_ERROR;
 }

 case ATTACH: {
            CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
 sound_trigger_module_handle_t handle;
            data.read(&handle, sizeof(sound_trigger_module_handle_t));
            sp<ISoundTriggerClient> client =
                    interface_cast<ISoundTriggerClient>(data.readStrongBinder());
            sp<ISoundTrigger> module;
 status_t status = attach(handle, client, module);
            reply->writeInt32(status);
 if (module != 0) {
                reply->writeInt32(1);
                reply->writeStrongBinder(IInterface::asBinder(module));
 } else {
                reply->writeInt32(0);
 }
 return NO_ERROR;
 } break;

 case SET_CAPTURE_STATE: {
            CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
            reply->writeInt32(setCaptureState((bool)data.readInt32()));
 return NO_ERROR;
 } break;

 default:
 return BBinder::onTransact(code, data, reply, flags);
 }
}

Integer overflow in soundtrigger/ISoundTriggerHwService.cpp in Android allows attacks to cause a denial of service via unspecified vectors.


status_t BnSoundTriggerHwService::onTransact(
 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
 switch(code) {

         case LIST_MODULES: {
             CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
             unsigned int numModulesReq = data.readInt32();
            if (numModulesReq > MAX_ITEMS_PER_LIST) {
                numModulesReq = MAX_ITEMS_PER_LIST;
            }
             unsigned int numModules = numModulesReq;
             struct sound_trigger_module_descriptor *modules =
                     (struct sound_trigger_module_descriptor *)calloc(numModulesReq,
                                                    sizeof(struct sound_trigger_module_descriptor));
            if (modules == NULL) {
                reply->writeInt32(NO_MEMORY);
                reply->writeInt32(0);
                return NO_ERROR;
            }
             status_t status = listModules(modules, &numModules);
             reply->writeInt32(status);
             reply->writeInt32(numModules);
            ALOGV("LIST_MODULES status %d got numModules %d", status, numModules);

 if (status == NO_ERROR) {
 if (numModulesReq > numModules) {
                    numModulesReq = numModules;
 }
                reply->write(modules,
                             numModulesReq * sizeof(struct sound_trigger_module_descriptor));
 }
            free(modules);
 return NO_ERROR;
 }

 case ATTACH: {
            CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
 sound_trigger_module_handle_t handle;
            data.read(&handle, sizeof(sound_trigger_module_handle_t));
            sp<ISoundTriggerClient> client =
                    interface_cast<ISoundTriggerClient>(data.readStrongBinder());
            sp<ISoundTrigger> module;
 status_t status = attach(handle, client, module);
            reply->writeInt32(status);
 if (module != 0) {
                reply->writeInt32(1);
                reply->writeStrongBinder(IInterface::asBinder(module));
 } else {
                reply->writeInt32(0);
 }
 return NO_ERROR;
 } break;

 case SET_CAPTURE_STATE: {
            CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
            reply->writeInt32(setCaptureState((bool)data.readInt32()));
 return NO_ERROR;
 } break;

 default:
 return BBinder::onTransact(code, data, reply, flags);
 }
}


netdutils::Status XfrmController::ipSecSetEncapSocketOwner(const android::base::unique_fd& socket,
 int newUid, uid_t callerUid) {
    ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);

 const int fd = socket.get();
 struct stat info;
 if (fstat(fd, &info)) {
 return netdutils::statusFromErrno(errno, "Failed to stat socket file descriptor");
 }
 if (info.st_uid != callerUid) {
 return netdutils::statusFromErrno(EPERM, "fchown disabled for non-owner calls");
 }
 if (S_ISSOCK(info.st_mode) == 0) {
 return netdutils::statusFromErrno(EINVAL, "File descriptor was not a socket");

     }

     int optval;
    socklen_t optlen;
     netdutils::Status status =
         getSyscallInstance().getsockopt(Fd(socket), IPPROTO_UDP, UDP_ENCAP, &optval, &optlen);
     if (status != netdutils::status::ok) {
 return status;
 }
 if (optval != UDP_ENCAP_ESPINUDP && optval != UDP_ENCAP_ESPINUDP_NON_IKE) {
 return netdutils::statusFromErrno(EINVAL, "Socket did not have UDP-encap sockopt set");
 }
 if (fchown(fd, newUid, -1)) {
 return netdutils::statusFromErrno(errno, "Failed to fchown socket file descriptor");
 }

 return netdutils::status::ok;
}

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


netdutils::Status XfrmController::ipSecSetEncapSocketOwner(const android::base::unique_fd& socket,
 int newUid, uid_t callerUid) {
    ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);

 const int fd = socket.get();
 struct stat info;
 if (fstat(fd, &info)) {
 return netdutils::statusFromErrno(errno, "Failed to stat socket file descriptor");
 }
 if (info.st_uid != callerUid) {
 return netdutils::statusFromErrno(EPERM, "fchown disabled for non-owner calls");
 }
 if (S_ISSOCK(info.st_mode) == 0) {
 return netdutils::statusFromErrno(EINVAL, "File descriptor was not a socket");

     }

     int optval;
    socklen_t optlen = sizeof(optval);
     netdutils::Status status =
         getSyscallInstance().getsockopt(Fd(socket), IPPROTO_UDP, UDP_ENCAP, &optval, &optlen);
     if (status != netdutils::status::ok) {
 return status;
 }
 if (optval != UDP_ENCAP_ESPINUDP && optval != UDP_ENCAP_ESPINUDP_NON_IKE) {
 return netdutils::statusFromErrno(EINVAL, "Socket did not have UDP-encap sockopt set");
 }
 if (fchown(fd, newUid, -1)) {
 return netdutils::statusFromErrno(errno, "Failed to fchown socket file descriptor");
 }

 return netdutils::status::ok;
}


static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
                           BT_HDR* p_pkt) {
 uint8_t opcode;
  tAVRC_MSG msg;
 uint8_t* p_data;
 uint8_t* p_begin;
 bool drop = false;
 bool do_free = true;
  BT_HDR* p_rsp = NULL;
 uint8_t* p_rsp_data;
 int xx;
 bool reject = false;
 const char* p_drop_msg = "dropped";
  tAVRC_MSG_VENDOR* p_msg = &msg.vendor;

 if (cr == AVCT_CMD && (p_pkt->layer_specific & AVCT_DATA_CTRL &&
                         AVRC_PACKET_LEN < sizeof(p_pkt->len))) {
 /* Ignore the invalid AV/C command frame */
    p_drop_msg = "dropped - too long AV/C cmd frame size";
    osi_free(p_pkt);
 return;
 }

 if (cr == AVCT_REJ) {
 /* The peer thinks that this PID is no longer open - remove this handle */
 /*  */
    osi_free(p_pkt);
    AVCT_RemoveConn(handle);
 return;
 } else if (cr == AVCT_RSP) {
 /* Received response. Stop command timeout timer */
    AVRC_TRACE_DEBUG("AVRC: stopping timer (handle=0x%02x)", handle);
    alarm_cancel(avrc_cb.ccb_int[handle].tle);
 }

  p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
  memset(&msg, 0, sizeof(tAVRC_MSG));

 if (p_pkt->layer_specific == AVCT_DATA_BROWSE) {
    opcode = AVRC_OP_BROWSE;
    msg.browse.hdr.ctype = cr;
    msg.browse.p_browse_data = p_data;

     msg.browse.browse_len = p_pkt->len;
     msg.browse.p_browse_pkt = p_pkt;
   } else {
     msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
     AVRC_TRACE_DEBUG("%s handle:%d, ctype:%d, offset:%d, len: %d", __func__,
                      handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
    msg.hdr.subunit_type =
 (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
    msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
    opcode = p_data[2];
 }

 if (((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
 ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP))) {
 switch (opcode) {
 case AVRC_OP_UNIT_INFO:
 if (cr == AVCT_CMD) {
 /* send the response to the peer */
          p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
          p_rsp_data = avrc_get_data_ptr(p_rsp);
 *p_rsp_data = AVRC_RSP_IMPL_STBL;
 /* check & set the offset. set response code, set subunit_type &
             subunit_id,
             set AVRC_OP_UNIT_INFO */
 /* 3 bytes: ctype, subunit*, opcode */
          p_rsp_data += AVRC_AVC_HDR_SIZE;
 *p_rsp_data++ = 7;
 /* Panel subunit & id=0 */
 *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
          AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
          p_rsp->len =
 (uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);
          cr = AVCT_RSP;

           p_drop_msg = "auto respond";
         } else {
           /* parse response */
           p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
           msg.unit.unit_type =
               (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
          msg.unit.unit = *p_data & AVRC_SUBID_MASK;
          p_data++;
          AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
 }
 break;

 case AVRC_OP_SUB_INFO:
 if (cr == AVCT_CMD) {
 /* send the response to the peer */
          p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
          p_rsp_data = avrc_get_data_ptr(p_rsp);
 *p_rsp_data = AVRC_RSP_IMPL_STBL;
 /* check & set the offset. set response code, set (subunit_type &
             subunit_id),
             set AVRC_OP_SUB_INFO, set (page & extention code) */
          p_rsp_data += 4;
 /* Panel subunit & id=0 */
 *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
          memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
          p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
          p_rsp->len =
 (uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);
          cr = AVCT_RSP;

           p_drop_msg = "auto responded";
         } else {
           /* parse response */
           p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
           msg.sub.page =
               (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
          xx = 0;
 while (*p_data != AVRC_CMD_OPRND_PAD && xx < AVRC_SUB_TYPE_LEN) {
            msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
 if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
              msg.sub.panel = true;
            xx++;
 }
 }
 break;

 case AVRC_OP_VENDOR: {
        p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
        p_begin = p_data;
 if (p_pkt->len <
            AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
 {
 if (cr == AVCT_CMD)
            reject = true;
 else
            drop = true;
 break;
 }
        p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,
                                        opcode */
        AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
        p_msg->p_vendor_data = p_data;
        p_msg->vendor_len = p_pkt->len - (p_data - p_begin);

 uint8_t drop_code = 0;
 if (p_msg->company_id == AVRC_CO_METADATA) {
 /* Validate length for metadata message */
 if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)) {
 if (cr == AVCT_CMD)
              reject = true;
 else
              drop = true;
 break;
 }

 /* Check+handle fragmented messages */
          drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
 if (drop_code > 0) drop = true;
 }
 if (drop_code > 0) {
 if (drop_code != 4) do_free = false;
 switch (drop_code) {
 case 1:
              p_drop_msg = "sent_frag";
 break;
 case 2:
              p_drop_msg = "req_cont";
 break;
 case 3:
              p_drop_msg = "sent_frag3";
 break;
 case 4:
              p_drop_msg = "sent_frag_free";
 break;
 default:
              p_drop_msg = "sent_fragd";
 }
 }
 /* If vendor response received, and did not ask for continuation */
 /* then check queue for addition commands to send */
 if ((cr == AVCT_RSP) && (drop_code != 2)) {
          avrc_send_next_vendor_cmd(handle);
 }
 } break;

 case AVRC_OP_PASS_THRU:
 if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
 {
 if (cr == AVCT_CMD)
            reject = true;
 else
            drop = true;
 break;
 }
        p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,
                                        opcode */
        msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
 if (AVRC_PASS_STATE_MASK & *p_data)
          msg.pass.state = true;
 else
          msg.pass.state = false;
        p_data++;
        msg.pass.pass_len = *p_data++;
 if (msg.pass.pass_len != p_pkt->len - 5)
          msg.pass.pass_len = p_pkt->len - 5;
 if (msg.pass.pass_len)
          msg.pass.p_pass_data = p_data;
 else
          msg.pass.p_pass_data = NULL;
 break;

 case AVRC_OP_BROWSE:
 /* If browse response received, then check queue for addition commands
         * to send */
 if (cr == AVCT_RSP) {
          avrc_send_next_vendor_cmd(handle);
 }
 break;

 default:
 if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) &&
 (cr == AVCT_CMD)) {
 /* reject unsupported opcode */
          reject = true;
 }
        drop = true;
 break;
 }
 } else /* drop the event */
 {
 if (opcode != AVRC_OP_BROWSE) drop = true;
 }

 if (reject) {
 /* reject unsupported opcode */
    p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
    p_rsp_data = avrc_get_data_ptr(p_rsp);
 *p_rsp_data = AVRC_RSP_REJ;
    p_drop_msg = "rejected";
    cr = AVCT_RSP;
    drop = true;
 }

 if (p_rsp) {
 /* set to send response right away */
    AVCT_MsgReq(handle, label, cr, p_rsp);
    drop = true;
 }

 if (!drop) {
    msg.hdr.opcode = opcode;
    avrc_cb.ccb[handle].msg_cback.Run(handle, label, opcode, &msg);
 } else {
    AVRC_TRACE_WARNING("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
                       __func__, p_drop_msg, handle,
                       avrc_cb.ccb[handle].control, cr, opcode);
 }

 if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL) {
    do_free = false;
 }

 if (do_free) osi_free(p_pkt);
}

In avrc_msg_cback of avrc_api.cc, there is a possible out-of-bound read due to a missing bounds check. This could lead to remote information disclosure over Bluetooth with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-111803925


static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
                           BT_HDR* p_pkt) {
 uint8_t opcode;
  tAVRC_MSG msg;
 uint8_t* p_data;
 uint8_t* p_begin;
 bool drop = false;
 bool do_free = true;
  BT_HDR* p_rsp = NULL;
 uint8_t* p_rsp_data;
 int xx;
 bool reject = false;
 const char* p_drop_msg = "dropped";
  tAVRC_MSG_VENDOR* p_msg = &msg.vendor;

 if (cr == AVCT_CMD && (p_pkt->layer_specific & AVCT_DATA_CTRL &&
                         AVRC_PACKET_LEN < sizeof(p_pkt->len))) {
 /* Ignore the invalid AV/C command frame */
    p_drop_msg = "dropped - too long AV/C cmd frame size";
    osi_free(p_pkt);
 return;
 }

 if (cr == AVCT_REJ) {
 /* The peer thinks that this PID is no longer open - remove this handle */
 /*  */
    osi_free(p_pkt);
    AVCT_RemoveConn(handle);
 return;
 } else if (cr == AVCT_RSP) {
 /* Received response. Stop command timeout timer */
    AVRC_TRACE_DEBUG("AVRC: stopping timer (handle=0x%02x)", handle);
    alarm_cancel(avrc_cb.ccb_int[handle].tle);
 }

  p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
  memset(&msg, 0, sizeof(tAVRC_MSG));

 if (p_pkt->layer_specific == AVCT_DATA_BROWSE) {
    opcode = AVRC_OP_BROWSE;
    msg.browse.hdr.ctype = cr;
    msg.browse.p_browse_data = p_data;

     msg.browse.browse_len = p_pkt->len;
     msg.browse.p_browse_pkt = p_pkt;
   } else {
    if (p_pkt->len < AVRC_AVC_HDR_SIZE) {
      android_errorWriteLog(0x534e4554, "111803925");
      AVRC_TRACE_WARNING("%s: message length %d too short: must be at least %d",
                         __func__, p_pkt->len, AVRC_AVC_HDR_SIZE);
      osi_free(p_pkt);
      return;
    }
     msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
     AVRC_TRACE_DEBUG("%s handle:%d, ctype:%d, offset:%d, len: %d", __func__,
                      handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
    msg.hdr.subunit_type =
 (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
    msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
    opcode = p_data[2];
 }

 if (((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
 ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP))) {
 switch (opcode) {
 case AVRC_OP_UNIT_INFO:
 if (cr == AVCT_CMD) {
 /* send the response to the peer */
          p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
          p_rsp_data = avrc_get_data_ptr(p_rsp);
 *p_rsp_data = AVRC_RSP_IMPL_STBL;
 /* check & set the offset. set response code, set subunit_type &
             subunit_id,
             set AVRC_OP_UNIT_INFO */
 /* 3 bytes: ctype, subunit*, opcode */
          p_rsp_data += AVRC_AVC_HDR_SIZE;
 *p_rsp_data++ = 7;
 /* Panel subunit & id=0 */
 *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
          AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
          p_rsp->len =
 (uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);
          cr = AVCT_RSP;

           p_drop_msg = "auto respond";
         } else {
           /* parse response */
          if (p_pkt->len < AVRC_OP_UNIT_INFO_RSP_LEN) {
            AVRC_TRACE_WARNING(
                "%s: message length %d too short: must be at least %d",
                __func__, p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN);
            android_errorWriteLog(0x534e4554, "79883824");
            drop = true;
            p_drop_msg = "UNIT_INFO_RSP too short";
            break;
          }
           p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
           msg.unit.unit_type =
               (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
          msg.unit.unit = *p_data & AVRC_SUBID_MASK;
          p_data++;
          AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
 }
 break;

 case AVRC_OP_SUB_INFO:
 if (cr == AVCT_CMD) {
 /* send the response to the peer */
          p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
          p_rsp_data = avrc_get_data_ptr(p_rsp);
 *p_rsp_data = AVRC_RSP_IMPL_STBL;
 /* check & set the offset. set response code, set (subunit_type &
             subunit_id),
             set AVRC_OP_SUB_INFO, set (page & extention code) */
          p_rsp_data += 4;
 /* Panel subunit & id=0 */
 *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
          memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
          p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
          p_rsp->len =
 (uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);
          cr = AVCT_RSP;

           p_drop_msg = "auto responded";
         } else {
           /* parse response */
          if (p_pkt->len < AVRC_OP_SUB_UNIT_INFO_RSP_LEN) {
            AVRC_TRACE_WARNING(
                "%s: message length %d too short: must be at least %d",
                __func__, p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
            android_errorWriteLog(0x534e4554, "79883824");
            drop = true;
            p_drop_msg = "SUB_UNIT_INFO_RSP too short";
            break;
          }
           p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
           msg.sub.page =
               (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
          xx = 0;
 while (*p_data != AVRC_CMD_OPRND_PAD && xx < AVRC_SUB_TYPE_LEN) {
            msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
 if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
              msg.sub.panel = true;
            xx++;
 }
 }
 break;

 case AVRC_OP_VENDOR: {
        p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
        p_begin = p_data;
 if (p_pkt->len <
            AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
 {
 if (cr == AVCT_CMD)
            reject = true;
 else
            drop = true;
 break;
 }
        p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,
                                        opcode */
        AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
        p_msg->p_vendor_data = p_data;
        p_msg->vendor_len = p_pkt->len - (p_data - p_begin);

 uint8_t drop_code = 0;
 if (p_msg->company_id == AVRC_CO_METADATA) {
 /* Validate length for metadata message */
 if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)) {
 if (cr == AVCT_CMD)
              reject = true;
 else
              drop = true;
 break;
 }

 /* Check+handle fragmented messages */
          drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
 if (drop_code > 0) drop = true;
 }
 if (drop_code > 0) {
 if (drop_code != 4) do_free = false;
 switch (drop_code) {
 case 1:
              p_drop_msg = "sent_frag";
 break;
 case 2:
              p_drop_msg = "req_cont";
 break;
 case 3:
              p_drop_msg = "sent_frag3";
 break;
 case 4:
              p_drop_msg = "sent_frag_free";
 break;
 default:
              p_drop_msg = "sent_fragd";
 }
 }
 /* If vendor response received, and did not ask for continuation */
 /* then check queue for addition commands to send */
 if ((cr == AVCT_RSP) && (drop_code != 2)) {
          avrc_send_next_vendor_cmd(handle);
 }
 } break;

 case AVRC_OP_PASS_THRU:
 if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
 {
 if (cr == AVCT_CMD)
            reject = true;
 else
            drop = true;
 break;
 }
        p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,
                                        opcode */
        msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
 if (AVRC_PASS_STATE_MASK & *p_data)
          msg.pass.state = true;
 else
          msg.pass.state = false;
        p_data++;
        msg.pass.pass_len = *p_data++;
 if (msg.pass.pass_len != p_pkt->len - 5)
          msg.pass.pass_len = p_pkt->len - 5;
 if (msg.pass.pass_len)
          msg.pass.p_pass_data = p_data;
 else
          msg.pass.p_pass_data = NULL;
 break;

 case AVRC_OP_BROWSE:
 /* If browse response received, then check queue for addition commands
         * to send */
 if (cr == AVCT_RSP) {
          avrc_send_next_vendor_cmd(handle);
 }
 break;

 default:
 if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) &&
 (cr == AVCT_CMD)) {
 /* reject unsupported opcode */
          reject = true;
 }
        drop = true;
 break;
 }
 } else /* drop the event */
 {
 if (opcode != AVRC_OP_BROWSE) drop = true;
 }

 if (reject) {
 /* reject unsupported opcode */
    p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
    p_rsp_data = avrc_get_data_ptr(p_rsp);
 *p_rsp_data = AVRC_RSP_REJ;
    p_drop_msg = "rejected";
    cr = AVCT_RSP;
    drop = true;
 }

 if (p_rsp) {
 /* set to send response right away */
    AVCT_MsgReq(handle, label, cr, p_rsp);
    drop = true;
 }

 if (!drop) {
    msg.hdr.opcode = opcode;
    avrc_cb.ccb[handle].msg_cback.Run(handle, label, opcode, &msg);
 } else {
    AVRC_TRACE_WARNING("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
                       __func__, p_drop_msg, handle,
                       avrc_cb.ccb[handle].control, cr, opcode);
 }

 if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL) {
    do_free = false;
 }

 if (do_free) osi_free(p_pkt);
}


WORD32 ih264d_parse_sps(dec_struct_t *ps_dec, dec_bit_stream_t *ps_bitstrm)

 {
     UWORD8 i;
     dec_seq_params_t *ps_seq = NULL;
    UWORD8 u1_profile_idc, u1_level_idc, u1_seq_parameter_set_id;
     UWORD16 i2_max_frm_num;
     UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;
     UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;
    UWORD8 u1_frm, uc_constraint_set0_flag, uc_constraint_set1_flag;
    WORD32 i4_cropped_ht, i4_cropped_wd;
    UWORD32 u4_temp;
    WORD32 pic_height_in_map_units_minus1 = 0;
    UWORD32 u2_pic_wd = 0;
    UWORD32 u2_pic_ht = 0;
    UWORD32 u2_frm_wd_y = 0;
    UWORD32 u2_frm_ht_y = 0;
    UWORD32 u2_frm_wd_uv = 0;
    UWORD32 u2_frm_ht_uv = 0;
    UWORD32 u2_crop_offset_y = 0;
    UWORD32 u2_crop_offset_uv = 0;
    WORD32 ret;
    UWORD32 u4_num_reorder_frames;
 /* High profile related syntax element */
    WORD32 i4_i;
 /* G050 */
    UWORD8 u1_frame_cropping_flag, u1_frame_cropping_rect_left_ofst,
                    u1_frame_cropping_rect_right_ofst,
                    u1_frame_cropping_rect_top_ofst,
                    u1_frame_cropping_rect_bottom_ofst;
 /* G050 */
 /*--------------------------------------------------------------------*/
 /* Decode seq_parameter_set_id and profile and level values           */
 /*--------------------------------------------------------------------*/
    SWITCHONTRACE;
    u1_profile_idc = ih264d_get_bits_h264(ps_bitstrm, 8);
    COPYTHECONTEXT("SPS: profile_idc",u1_profile_idc);

 /* G050 */
    uc_constraint_set0_flag = ih264d_get_bit_h264(ps_bitstrm);
    uc_constraint_set1_flag = ih264d_get_bit_h264(ps_bitstrm);
    ih264d_get_bit_h264(ps_bitstrm);

 /*****************************************************/
 /* Read 5 bits for uc_constraint_set3_flag (1 bit)   */
 /* and reserved_zero_4bits (4 bits) - Sushant        */
 /*****************************************************/
    ih264d_get_bits_h264(ps_bitstrm, 5);
 /* G050 */

 /* Check whether particular profile is suported or not */
 /* Check whether particular profile is suported or not */
 if((u1_profile_idc != MAIN_PROFILE_IDC) &&

 (u1_profile_idc != BASE_PROFILE_IDC) &&

 (u1_profile_idc != HIGH_PROFILE_IDC)

 )
 {

 /* Apart from Baseline, main and high profile,
         * only extended profile is supported provided
         * uc_constraint_set0_flag or uc_constraint_set1_flag are set to 1
         */
 if((u1_profile_idc != EXTENDED_PROFILE_IDC) ||
 ((uc_constraint_set1_flag != 1) && (uc_constraint_set0_flag != 1)))
 {
 return (ERROR_FEATURE_UNAVAIL);
 }
 }

    u1_level_idc = ih264d_get_bits_h264(ps_bitstrm, 8);

    COPYTHECONTEXT("SPS: u4_level_idc",u1_level_idc);

    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp & MASK_ERR_SEQ_SET_ID)
 return ERROR_INV_SPS_PPS_T;
    u1_seq_parameter_set_id = u4_temp;
    COPYTHECONTEXT("SPS: seq_parameter_set_id",
                    u1_seq_parameter_set_id);

 /*--------------------------------------------------------------------*/
 /* Find an seq param entry in seqparam array of decStruct             */
 /*--------------------------------------------------------------------*/

    ps_seq = ps_dec->pv_scratch_sps_pps;
 if(ps_dec->i4_header_decoded & 1)
 {
 *ps_seq = *ps_dec->ps_cur_sps;
 }

 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_profile_idc != u1_profile_idc))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_level_idc != u1_level_idc))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

    ps_seq->u1_profile_idc = u1_profile_idc;
    ps_seq->u1_level_idc = u1_level_idc;
    ps_seq->u1_seq_parameter_set_id = u1_seq_parameter_set_id;

 /*******************************************************************/
 /* Initializations for high profile - Sushant                      */
 /*******************************************************************/
    ps_seq->i4_chroma_format_idc = 1;
    ps_seq->i4_bit_depth_luma_minus8 = 0;
    ps_seq->i4_bit_depth_chroma_minus8 = 0;
    ps_seq->i4_qpprime_y_zero_transform_bypass_flag = 0;
    ps_seq->i4_seq_scaling_matrix_present_flag = 0;
 if(u1_profile_idc == HIGH_PROFILE_IDC)
 {

 /* reading chroma_format_idc   */
        ps_seq->i4_chroma_format_idc = ih264d_uev(pu4_bitstrm_ofst,
                                                  pu4_bitstrm_buf);

 /* Monochrome is not supported */
 if(ps_seq->i4_chroma_format_idc != 1)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading bit_depth_luma_minus8   */
        ps_seq->i4_bit_depth_luma_minus8 = ih264d_uev(pu4_bitstrm_ofst,
                                                      pu4_bitstrm_buf);

 if(ps_seq->i4_bit_depth_luma_minus8 != 0)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading bit_depth_chroma_minus8   */
        ps_seq->i4_bit_depth_chroma_minus8 = ih264d_uev(pu4_bitstrm_ofst,
                                                        pu4_bitstrm_buf);

 if(ps_seq->i4_bit_depth_chroma_minus8 != 0)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading qpprime_y_zero_transform_bypass_flag   */
        ps_seq->i4_qpprime_y_zero_transform_bypass_flag =
 (WORD32)ih264d_get_bit_h264(ps_bitstrm);

 if(ps_seq->i4_qpprime_y_zero_transform_bypass_flag != 0)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading seq_scaling_matrix_present_flag   */
        ps_seq->i4_seq_scaling_matrix_present_flag =
 (WORD32)ih264d_get_bit_h264(ps_bitstrm);

 if(ps_seq->i4_seq_scaling_matrix_present_flag)
 {
 for(i4_i = 0; i4_i < 8; i4_i++)
 {
                ps_seq->u1_seq_scaling_list_present_flag[i4_i] =
                                ih264d_get_bit_h264(ps_bitstrm);

 /* initialize u1_use_default_scaling_matrix_flag[i4_i] to zero */
 /* before calling scaling list                             */
                ps_seq->u1_use_default_scaling_matrix_flag[i4_i] = 0;

 if(ps_seq->u1_seq_scaling_list_present_flag[i4_i])
 {
 if(i4_i < 6)
 {
                        ih264d_scaling_list(
                                        ps_seq->i2_scalinglist4x4[i4_i],
 16,
 &ps_seq->u1_use_default_scaling_matrix_flag[i4_i],
                                        ps_bitstrm);
 }
 else
 {
                        ih264d_scaling_list(
                                        ps_seq->i2_scalinglist8x8[i4_i - 6],
 64,
 &ps_seq->u1_use_default_scaling_matrix_flag[i4_i],
                                        ps_bitstrm);
 }
 }
 }
 }
 }
 /*--------------------------------------------------------------------*/
 /* Decode MaxFrameNum                                                 */
 /*--------------------------------------------------------------------*/
    u4_temp = 4 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp > MAX_BITS_IN_FRAME_NUM)
 {
 return ERROR_INV_SPS_PPS_T;
 }
    ps_seq->u1_bits_in_frm_num = u4_temp;
    COPYTHECONTEXT("SPS: log2_max_frame_num_minus4",
 (ps_seq->u1_bits_in_frm_num - 4));

    i2_max_frm_num = (1 << (ps_seq->u1_bits_in_frm_num));
    ps_seq->u2_u4_max_pic_num_minus1 = i2_max_frm_num - 1;
 /*--------------------------------------------------------------------*/
 /* Decode picture order count and related values                      */
 /*--------------------------------------------------------------------*/
    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);

 if(u4_temp > MAX_PIC_ORDER_CNT_TYPE)
 {
 return ERROR_INV_POC_TYPE_T;
 }
    ps_seq->u1_pic_order_cnt_type = u4_temp;
    COPYTHECONTEXT("SPS: pic_order_cnt_type",ps_seq->u1_pic_order_cnt_type);

    ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle = 1;
 if(ps_seq->u1_pic_order_cnt_type == 0)
 {
        u4_temp = 4 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp > MAX_BITS_IN_POC_LSB)
 {
 return ERROR_INV_SPS_PPS_T;
 }
        ps_seq->u1_log2_max_pic_order_cnt_lsb_minus = u4_temp;
        ps_seq->i4_max_pic_order_cntLsb = (1 << u4_temp);
        COPYTHECONTEXT("SPS: log2_max_pic_order_cnt_lsb_minus4",(u4_temp - 4));
 }
 else if(ps_seq->u1_pic_order_cnt_type == 1)
 {
        ps_seq->u1_delta_pic_order_always_zero_flag = ih264d_get_bit_h264(
                        ps_bitstrm);
        COPYTHECONTEXT("SPS: delta_pic_order_always_zero_flag",
                        ps_seq->u1_delta_pic_order_always_zero_flag);

        ps_seq->i4_ofst_for_non_ref_pic = ih264d_sev(pu4_bitstrm_ofst,
                                                     pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: offset_for_non_ref_pic",
                        ps_seq->i4_ofst_for_non_ref_pic);

        ps_seq->i4_ofst_for_top_to_bottom_field = ih264d_sev(
                        pu4_bitstrm_ofst, pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: offset_for_top_to_bottom_field",
                        ps_seq->i4_ofst_for_top_to_bottom_field);

        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp > 255)
 return ERROR_INV_SPS_PPS_T;
        ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle = u4_temp;
        COPYTHECONTEXT("SPS: num_ref_frames_in_pic_order_cnt_cycle",
                        ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle);

 for(i = 0; i < ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle; i++)
 {
            ps_seq->i4_ofst_for_ref_frame[i] = ih264d_sev(
                            pu4_bitstrm_ofst, pu4_bitstrm_buf);
            COPYTHECONTEXT("SPS: offset_for_ref_frame",
                            ps_seq->i4_ofst_for_ref_frame[i]);
 }
 }

    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);

 if((u4_temp > H264_MAX_REF_PICS))
 {
 return ERROR_NUM_REF;
 }

 /* Compare with older num_ref_frames is header is already once */
 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_num_ref_frames != u4_temp))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

    ps_seq->u1_num_ref_frames = u4_temp;
    COPYTHECONTEXT("SPS: num_ref_frames",ps_seq->u1_num_ref_frames);

    ps_seq->u1_gaps_in_frame_num_value_allowed_flag = ih264d_get_bit_h264(
                    ps_bitstrm);
    COPYTHECONTEXT("SPS: gaps_in_frame_num_value_allowed_flag",
                    ps_seq->u1_gaps_in_frame_num_value_allowed_flag);

 /*--------------------------------------------------------------------*/
 /* Decode FrameWidth and FrameHeight and related values               */
 /*--------------------------------------------------------------------*/
    ps_seq->u2_frm_wd_in_mbs = 1
 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
    COPYTHECONTEXT("SPS: pic_width_in_mbs_minus1",
                    ps_seq->u2_frm_wd_in_mbs - 1);
    u2_pic_wd = (ps_seq->u2_frm_wd_in_mbs << 4);

    pic_height_in_map_units_minus1 = ih264d_uev(pu4_bitstrm_ofst,
                                                pu4_bitstrm_buf);
    ps_seq->u2_frm_ht_in_mbs = 1 + pic_height_in_map_units_minus1;

    u2_pic_ht = (ps_seq->u2_frm_ht_in_mbs << 4);

 /*--------------------------------------------------------------------*/
 /* Get the value of MaxMbAddress and Number of bits needed for it     */
 /*--------------------------------------------------------------------*/
    ps_seq->u2_max_mb_addr = (ps_seq->u2_frm_wd_in_mbs
 * ps_seq->u2_frm_ht_in_mbs) - 1;

    ps_seq->u2_total_num_of_mbs = ps_seq->u2_max_mb_addr + 1;

    ps_seq->u1_level_idc = ih264d_correct_level_idc(
                    u1_level_idc, ps_seq->u2_total_num_of_mbs);

    u1_frm = ih264d_get_bit_h264(ps_bitstrm);
 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_frame_mbs_only_flag != u1_frm))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

    ps_seq->u1_frame_mbs_only_flag = u1_frm;

     COPYTHECONTEXT("SPS: frame_mbs_only_flag", u1_frm);

     if(!u1_frm)
     {
         u2_pic_ht <<= 1;
        ps_seq->u1_mb_aff_flag = ih264d_get_bit_h264(ps_bitstrm);
         COPYTHECONTEXT("SPS: mb_adaptive_frame_field_flag",
                         ps_seq->u1_mb_aff_flag);

 }
 else
        ps_seq->u1_mb_aff_flag = 0;

    ps_seq->u1_direct_8x8_inference_flag = ih264d_get_bit_h264(ps_bitstrm);

    COPYTHECONTEXT("SPS: direct_8x8_inference_flag",
                    ps_seq->u1_direct_8x8_inference_flag);

 /* G050 */
    u1_frame_cropping_flag = ih264d_get_bit_h264(ps_bitstrm);
    COPYTHECONTEXT("SPS: frame_cropping_flag",u1_frame_cropping_flag);

 if(u1_frame_cropping_flag)
 {
        u1_frame_cropping_rect_left_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                      pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_left_offset",
                        u1_frame_cropping_rect_left_ofst);
        u1_frame_cropping_rect_right_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                       pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_right_offset",
                        u1_frame_cropping_rect_right_ofst);
        u1_frame_cropping_rect_top_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                     pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_top_offset",
                        u1_frame_cropping_rect_top_ofst);
        u1_frame_cropping_rect_bottom_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                        pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_bottom_offset",
                        u1_frame_cropping_rect_bottom_ofst);
 }
 /* G050 */

    ps_seq->u1_vui_parameters_present_flag = ih264d_get_bit_h264(ps_bitstrm);
    COPYTHECONTEXT("SPS: vui_parameters_present_flag",
                    ps_seq->u1_vui_parameters_present_flag);

    u2_frm_wd_y = u2_pic_wd + (UWORD8)(PAD_LEN_Y_H << 1);
 if(1 == ps_dec->u4_share_disp_buf)
 {
 if(ps_dec->u4_app_disp_width > u2_frm_wd_y)
            u2_frm_wd_y = ps_dec->u4_app_disp_width;
 }

    u2_frm_ht_y = u2_pic_ht + (UWORD8)(PAD_LEN_Y_V << 2);
    u2_frm_wd_uv = u2_pic_wd + (UWORD8)(PAD_LEN_UV_H << 2);
    u2_frm_wd_uv = MAX(u2_frm_wd_uv, u2_frm_wd_y);

    u2_frm_ht_uv = (u2_pic_ht >> 1) + (UWORD8)(PAD_LEN_UV_V << 2);
    u2_frm_ht_uv = MAX(u2_frm_ht_uv, (u2_frm_ht_y >> 1));

 /* Calculate display picture width, height and start u4_ofst from YUV420 */
 /* pictute buffers as per cropping information parsed above             */
 {
        UWORD16 u2_rgt_ofst = 0;
        UWORD16 u2_lft_ofst = 0;
        UWORD16 u2_top_ofst = 0;
        UWORD16 u2_btm_ofst = 0;
        UWORD8 u1_frm_mbs_flag;
        UWORD8 u1_vert_mult_factor;

 if(u1_frame_cropping_flag)
 {
 /* Calculate right and left u4_ofst for cropped picture           */
            u2_rgt_ofst = u1_frame_cropping_rect_right_ofst << 1;
            u2_lft_ofst = u1_frame_cropping_rect_left_ofst << 1;

 /* Know frame MBs only u4_flag                                      */
            u1_frm_mbs_flag = (1 == ps_seq->u1_frame_mbs_only_flag);

 /* Simplify the vertical u4_ofst calculation from field/frame     */
            u1_vert_mult_factor = (2 - u1_frm_mbs_flag);

 /* Calculate bottom and top u4_ofst for cropped  picture          */
            u2_btm_ofst = (u1_frame_cropping_rect_bottom_ofst
 << u1_vert_mult_factor);
            u2_top_ofst = (u1_frame_cropping_rect_top_ofst
 << u1_vert_mult_factor);
 }

 /* Calculate u4_ofst from start of YUV 420 picture buffer to start of*/
 /* cropped picture buffer                                           */
        u2_crop_offset_y = (u2_frm_wd_y * u2_top_ofst) + (u2_lft_ofst);
        u2_crop_offset_uv = (u2_frm_wd_uv * (u2_top_ofst >> 1))
 + (u2_lft_ofst >> 1) * YUV420SP_FACTOR;
 /* Calculate the display picture width and height based on crop      */
 /* information                                                       */
        i4_cropped_ht = u2_pic_ht - (u2_btm_ofst + u2_top_ofst);
        i4_cropped_wd = u2_pic_wd - (u2_rgt_ofst + u2_lft_ofst);

 if((i4_cropped_ht < MB_SIZE) || (i4_cropped_wd < MB_SIZE))
 {
 return ERROR_INV_SPS_PPS_T;
 }

 if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_pic_wd != u2_pic_wd))
 {
            ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }
 if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_pic_ht != u2_pic_ht))
 {
            ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

 /* Check for unsupported resolutions */
 if((u2_pic_wd > H264_MAX_FRAME_WIDTH) || (u2_pic_ht > H264_MAX_FRAME_HEIGHT)
 || (u2_pic_wd < H264_MIN_FRAME_WIDTH) || (u2_pic_ht < H264_MIN_FRAME_HEIGHT)
 || (u2_pic_wd * (UWORD32)u2_pic_ht > H264_MAX_FRAME_SIZE))
 {
 return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;
 }

 /* If MBAff is enabled, decoder support is limited to streams with
         * width less than half of H264_MAX_FRAME_WIDTH.
         * In case of MBAff decoder processes two rows at a time
         */
 if((u2_pic_wd << ps_seq->u1_mb_aff_flag) > H264_MAX_FRAME_WIDTH)
 {
 return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;
 }

 }

 /* Backup u4_num_reorder_frames if header is already decoded */
 if((ps_dec->i4_header_decoded & 1) &&
 (1 == ps_seq->u1_vui_parameters_present_flag) &&
 (1 == ps_seq->s_vui.u1_bitstream_restriction_flag))
 {
        u4_num_reorder_frames =  ps_seq->s_vui.u4_num_reorder_frames;
 }
 else
 {
        u4_num_reorder_frames = -1;
 }
 if(1 == ps_seq->u1_vui_parameters_present_flag)
 {
        ret = ih264d_parse_vui_parametres(&ps_seq->s_vui, ps_bitstrm);
 if(ret != OK)
 return ret;
 }

 /* Compare older u4_num_reorder_frames with the new one if header is already decoded */
 if((ps_dec->i4_header_decoded & 1) &&
 (-1 != (WORD32)u4_num_reorder_frames) &&
 (1 == ps_seq->u1_vui_parameters_present_flag) &&
 (1 == ps_seq->s_vui.u1_bitstream_restriction_flag) &&
 (ps_seq->s_vui.u4_num_reorder_frames != u4_num_reorder_frames))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

 /* In case bitstream read has exceeded the filled size, then
     return an error */
 if (ps_bitstrm->u4_ofst > ps_bitstrm->u4_max_ofst)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /*--------------------------------------------------------------------*/
 /* All initializations to ps_dec are beyond this point                */
 /*--------------------------------------------------------------------*/
    ps_dec->u2_disp_height = i4_cropped_ht;
    ps_dec->u2_disp_width = i4_cropped_wd;

    ps_dec->u2_pic_wd = u2_pic_wd;
    ps_dec->u2_pic_ht = u2_pic_ht;

 /* Determining the Width and Height of Frame from that of Picture */
    ps_dec->u2_frm_wd_y = u2_frm_wd_y;
    ps_dec->u2_frm_ht_y = u2_frm_ht_y;

    ps_dec->u2_frm_wd_uv = u2_frm_wd_uv;
    ps_dec->u2_frm_ht_uv = u2_frm_ht_uv;
    ps_dec->s_pad_mgr.u1_pad_len_y_v = (UWORD8)(PAD_LEN_Y_V << (1 - u1_frm));
    ps_dec->s_pad_mgr.u1_pad_len_cr_v = (UWORD8)(PAD_LEN_UV_V << (1 - u1_frm));

    ps_dec->u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;
    ps_dec->u2_frm_ht_in_mbs = ps_seq->u2_frm_ht_in_mbs;

    ps_dec->u2_crop_offset_y = u2_crop_offset_y;
    ps_dec->u2_crop_offset_uv = u2_crop_offset_uv;

    ps_seq->u1_is_valid = TRUE;
    ps_dec->ps_sps[u1_seq_parameter_set_id] = *ps_seq;
    ps_dec->ps_cur_sps = &ps_dec->ps_sps[u1_seq_parameter_set_id];

 return OK;
}

An information disclosure vulnerability in the Android media framework (libavc). Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0, 8.1. Android ID: A-64380237.


WORD32 ih264d_parse_sps(dec_struct_t *ps_dec, dec_bit_stream_t *ps_bitstrm)

 {
     UWORD8 i;
     dec_seq_params_t *ps_seq = NULL;
    UWORD8 u1_profile_idc, u1_level_idc, u1_seq_parameter_set_id, u1_mb_aff_flag = 0;
     UWORD16 i2_max_frm_num;
     UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;
     UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;
    UWORD8 u1_frm, uc_constraint_set0_flag, uc_constraint_set1_flag;
    WORD32 i4_cropped_ht, i4_cropped_wd;
    UWORD32 u4_temp;
    WORD32 pic_height_in_map_units_minus1 = 0;
    UWORD32 u2_pic_wd = 0;
    UWORD32 u2_pic_ht = 0;
    UWORD32 u2_frm_wd_y = 0;
    UWORD32 u2_frm_ht_y = 0;
    UWORD32 u2_frm_wd_uv = 0;
    UWORD32 u2_frm_ht_uv = 0;
    UWORD32 u2_crop_offset_y = 0;
    UWORD32 u2_crop_offset_uv = 0;
    WORD32 ret;
    UWORD32 u4_num_reorder_frames;
 /* High profile related syntax element */
    WORD32 i4_i;
 /* G050 */
    UWORD8 u1_frame_cropping_flag, u1_frame_cropping_rect_left_ofst,
                    u1_frame_cropping_rect_right_ofst,
                    u1_frame_cropping_rect_top_ofst,
                    u1_frame_cropping_rect_bottom_ofst;
 /* G050 */
 /*--------------------------------------------------------------------*/
 /* Decode seq_parameter_set_id and profile and level values           */
 /*--------------------------------------------------------------------*/
    SWITCHONTRACE;
    u1_profile_idc = ih264d_get_bits_h264(ps_bitstrm, 8);
    COPYTHECONTEXT("SPS: profile_idc",u1_profile_idc);

 /* G050 */
    uc_constraint_set0_flag = ih264d_get_bit_h264(ps_bitstrm);
    uc_constraint_set1_flag = ih264d_get_bit_h264(ps_bitstrm);
    ih264d_get_bit_h264(ps_bitstrm);

 /*****************************************************/
 /* Read 5 bits for uc_constraint_set3_flag (1 bit)   */
 /* and reserved_zero_4bits (4 bits) - Sushant        */
 /*****************************************************/
    ih264d_get_bits_h264(ps_bitstrm, 5);
 /* G050 */

 /* Check whether particular profile is suported or not */
 /* Check whether particular profile is suported or not */
 if((u1_profile_idc != MAIN_PROFILE_IDC) &&

 (u1_profile_idc != BASE_PROFILE_IDC) &&

 (u1_profile_idc != HIGH_PROFILE_IDC)

 )
 {

 /* Apart from Baseline, main and high profile,
         * only extended profile is supported provided
         * uc_constraint_set0_flag or uc_constraint_set1_flag are set to 1
         */
 if((u1_profile_idc != EXTENDED_PROFILE_IDC) ||
 ((uc_constraint_set1_flag != 1) && (uc_constraint_set0_flag != 1)))
 {
 return (ERROR_FEATURE_UNAVAIL);
 }
 }

    u1_level_idc = ih264d_get_bits_h264(ps_bitstrm, 8);

    COPYTHECONTEXT("SPS: u4_level_idc",u1_level_idc);

    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp & MASK_ERR_SEQ_SET_ID)
 return ERROR_INV_SPS_PPS_T;
    u1_seq_parameter_set_id = u4_temp;
    COPYTHECONTEXT("SPS: seq_parameter_set_id",
                    u1_seq_parameter_set_id);

 /*--------------------------------------------------------------------*/
 /* Find an seq param entry in seqparam array of decStruct             */
 /*--------------------------------------------------------------------*/

    ps_seq = ps_dec->pv_scratch_sps_pps;
 if(ps_dec->i4_header_decoded & 1)
 {
 *ps_seq = *ps_dec->ps_cur_sps;
 }

 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_profile_idc != u1_profile_idc))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_level_idc != u1_level_idc))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

    ps_seq->u1_profile_idc = u1_profile_idc;
    ps_seq->u1_level_idc = u1_level_idc;
    ps_seq->u1_seq_parameter_set_id = u1_seq_parameter_set_id;

 /*******************************************************************/
 /* Initializations for high profile - Sushant                      */
 /*******************************************************************/
    ps_seq->i4_chroma_format_idc = 1;
    ps_seq->i4_bit_depth_luma_minus8 = 0;
    ps_seq->i4_bit_depth_chroma_minus8 = 0;
    ps_seq->i4_qpprime_y_zero_transform_bypass_flag = 0;
    ps_seq->i4_seq_scaling_matrix_present_flag = 0;
 if(u1_profile_idc == HIGH_PROFILE_IDC)
 {

 /* reading chroma_format_idc   */
        ps_seq->i4_chroma_format_idc = ih264d_uev(pu4_bitstrm_ofst,
                                                  pu4_bitstrm_buf);

 /* Monochrome is not supported */
 if(ps_seq->i4_chroma_format_idc != 1)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading bit_depth_luma_minus8   */
        ps_seq->i4_bit_depth_luma_minus8 = ih264d_uev(pu4_bitstrm_ofst,
                                                      pu4_bitstrm_buf);

 if(ps_seq->i4_bit_depth_luma_minus8 != 0)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading bit_depth_chroma_minus8   */
        ps_seq->i4_bit_depth_chroma_minus8 = ih264d_uev(pu4_bitstrm_ofst,
                                                        pu4_bitstrm_buf);

 if(ps_seq->i4_bit_depth_chroma_minus8 != 0)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading qpprime_y_zero_transform_bypass_flag   */
        ps_seq->i4_qpprime_y_zero_transform_bypass_flag =
 (WORD32)ih264d_get_bit_h264(ps_bitstrm);

 if(ps_seq->i4_qpprime_y_zero_transform_bypass_flag != 0)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /* reading seq_scaling_matrix_present_flag   */
        ps_seq->i4_seq_scaling_matrix_present_flag =
 (WORD32)ih264d_get_bit_h264(ps_bitstrm);

 if(ps_seq->i4_seq_scaling_matrix_present_flag)
 {
 for(i4_i = 0; i4_i < 8; i4_i++)
 {
                ps_seq->u1_seq_scaling_list_present_flag[i4_i] =
                                ih264d_get_bit_h264(ps_bitstrm);

 /* initialize u1_use_default_scaling_matrix_flag[i4_i] to zero */
 /* before calling scaling list                             */
                ps_seq->u1_use_default_scaling_matrix_flag[i4_i] = 0;

 if(ps_seq->u1_seq_scaling_list_present_flag[i4_i])
 {
 if(i4_i < 6)
 {
                        ih264d_scaling_list(
                                        ps_seq->i2_scalinglist4x4[i4_i],
 16,
 &ps_seq->u1_use_default_scaling_matrix_flag[i4_i],
                                        ps_bitstrm);
 }
 else
 {
                        ih264d_scaling_list(
                                        ps_seq->i2_scalinglist8x8[i4_i - 6],
 64,
 &ps_seq->u1_use_default_scaling_matrix_flag[i4_i],
                                        ps_bitstrm);
 }
 }
 }
 }
 }
 /*--------------------------------------------------------------------*/
 /* Decode MaxFrameNum                                                 */
 /*--------------------------------------------------------------------*/
    u4_temp = 4 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp > MAX_BITS_IN_FRAME_NUM)
 {
 return ERROR_INV_SPS_PPS_T;
 }
    ps_seq->u1_bits_in_frm_num = u4_temp;
    COPYTHECONTEXT("SPS: log2_max_frame_num_minus4",
 (ps_seq->u1_bits_in_frm_num - 4));

    i2_max_frm_num = (1 << (ps_seq->u1_bits_in_frm_num));
    ps_seq->u2_u4_max_pic_num_minus1 = i2_max_frm_num - 1;
 /*--------------------------------------------------------------------*/
 /* Decode picture order count and related values                      */
 /*--------------------------------------------------------------------*/
    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);

 if(u4_temp > MAX_PIC_ORDER_CNT_TYPE)
 {
 return ERROR_INV_POC_TYPE_T;
 }
    ps_seq->u1_pic_order_cnt_type = u4_temp;
    COPYTHECONTEXT("SPS: pic_order_cnt_type",ps_seq->u1_pic_order_cnt_type);

    ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle = 1;
 if(ps_seq->u1_pic_order_cnt_type == 0)
 {
        u4_temp = 4 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp > MAX_BITS_IN_POC_LSB)
 {
 return ERROR_INV_SPS_PPS_T;
 }
        ps_seq->u1_log2_max_pic_order_cnt_lsb_minus = u4_temp;
        ps_seq->i4_max_pic_order_cntLsb = (1 << u4_temp);
        COPYTHECONTEXT("SPS: log2_max_pic_order_cnt_lsb_minus4",(u4_temp - 4));
 }
 else if(ps_seq->u1_pic_order_cnt_type == 1)
 {
        ps_seq->u1_delta_pic_order_always_zero_flag = ih264d_get_bit_h264(
                        ps_bitstrm);
        COPYTHECONTEXT("SPS: delta_pic_order_always_zero_flag",
                        ps_seq->u1_delta_pic_order_always_zero_flag);

        ps_seq->i4_ofst_for_non_ref_pic = ih264d_sev(pu4_bitstrm_ofst,
                                                     pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: offset_for_non_ref_pic",
                        ps_seq->i4_ofst_for_non_ref_pic);

        ps_seq->i4_ofst_for_top_to_bottom_field = ih264d_sev(
                        pu4_bitstrm_ofst, pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: offset_for_top_to_bottom_field",
                        ps_seq->i4_ofst_for_top_to_bottom_field);

        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
 if(u4_temp > 255)
 return ERROR_INV_SPS_PPS_T;
        ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle = u4_temp;
        COPYTHECONTEXT("SPS: num_ref_frames_in_pic_order_cnt_cycle",
                        ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle);

 for(i = 0; i < ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle; i++)
 {
            ps_seq->i4_ofst_for_ref_frame[i] = ih264d_sev(
                            pu4_bitstrm_ofst, pu4_bitstrm_buf);
            COPYTHECONTEXT("SPS: offset_for_ref_frame",
                            ps_seq->i4_ofst_for_ref_frame[i]);
 }
 }

    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);

 if((u4_temp > H264_MAX_REF_PICS))
 {
 return ERROR_NUM_REF;
 }

 /* Compare with older num_ref_frames is header is already once */
 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_num_ref_frames != u4_temp))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

    ps_seq->u1_num_ref_frames = u4_temp;
    COPYTHECONTEXT("SPS: num_ref_frames",ps_seq->u1_num_ref_frames);

    ps_seq->u1_gaps_in_frame_num_value_allowed_flag = ih264d_get_bit_h264(
                    ps_bitstrm);
    COPYTHECONTEXT("SPS: gaps_in_frame_num_value_allowed_flag",
                    ps_seq->u1_gaps_in_frame_num_value_allowed_flag);

 /*--------------------------------------------------------------------*/
 /* Decode FrameWidth and FrameHeight and related values               */
 /*--------------------------------------------------------------------*/
    ps_seq->u2_frm_wd_in_mbs = 1
 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);
    COPYTHECONTEXT("SPS: pic_width_in_mbs_minus1",
                    ps_seq->u2_frm_wd_in_mbs - 1);
    u2_pic_wd = (ps_seq->u2_frm_wd_in_mbs << 4);

    pic_height_in_map_units_minus1 = ih264d_uev(pu4_bitstrm_ofst,
                                                pu4_bitstrm_buf);
    ps_seq->u2_frm_ht_in_mbs = 1 + pic_height_in_map_units_minus1;

    u2_pic_ht = (ps_seq->u2_frm_ht_in_mbs << 4);

 /*--------------------------------------------------------------------*/
 /* Get the value of MaxMbAddress and Number of bits needed for it     */
 /*--------------------------------------------------------------------*/
    ps_seq->u2_max_mb_addr = (ps_seq->u2_frm_wd_in_mbs
 * ps_seq->u2_frm_ht_in_mbs) - 1;

    ps_seq->u2_total_num_of_mbs = ps_seq->u2_max_mb_addr + 1;

    ps_seq->u1_level_idc = ih264d_correct_level_idc(
                    u1_level_idc, ps_seq->u2_total_num_of_mbs);

    u1_frm = ih264d_get_bit_h264(ps_bitstrm);
 if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_frame_mbs_only_flag != u1_frm))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

    ps_seq->u1_frame_mbs_only_flag = u1_frm;

     COPYTHECONTEXT("SPS: frame_mbs_only_flag", u1_frm);

     if(!u1_frm)
        u1_mb_aff_flag = ih264d_get_bit_h264(ps_bitstrm);

    if((ps_dec->i4_header_decoded & 1)
                    && (ps_seq->u1_mb_aff_flag != u1_mb_aff_flag))
    {
        ps_dec->u1_res_changed = 1;
        return IVD_RES_CHANGED;
    }

    if(!u1_frm)
     {
         u2_pic_ht <<= 1;
        ps_seq->u1_mb_aff_flag = u1_mb_aff_flag;
         COPYTHECONTEXT("SPS: mb_adaptive_frame_field_flag",
                         ps_seq->u1_mb_aff_flag);

 }
 else
        ps_seq->u1_mb_aff_flag = 0;

    ps_seq->u1_direct_8x8_inference_flag = ih264d_get_bit_h264(ps_bitstrm);

    COPYTHECONTEXT("SPS: direct_8x8_inference_flag",
                    ps_seq->u1_direct_8x8_inference_flag);

 /* G050 */
    u1_frame_cropping_flag = ih264d_get_bit_h264(ps_bitstrm);
    COPYTHECONTEXT("SPS: frame_cropping_flag",u1_frame_cropping_flag);

 if(u1_frame_cropping_flag)
 {
        u1_frame_cropping_rect_left_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                      pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_left_offset",
                        u1_frame_cropping_rect_left_ofst);
        u1_frame_cropping_rect_right_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                       pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_right_offset",
                        u1_frame_cropping_rect_right_ofst);
        u1_frame_cropping_rect_top_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                     pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_top_offset",
                        u1_frame_cropping_rect_top_ofst);
        u1_frame_cropping_rect_bottom_ofst = ih264d_uev(pu4_bitstrm_ofst,
                                                        pu4_bitstrm_buf);
        COPYTHECONTEXT("SPS: frame_cropping_rect_bottom_offset",
                        u1_frame_cropping_rect_bottom_ofst);
 }
 /* G050 */

    ps_seq->u1_vui_parameters_present_flag = ih264d_get_bit_h264(ps_bitstrm);
    COPYTHECONTEXT("SPS: vui_parameters_present_flag",
                    ps_seq->u1_vui_parameters_present_flag);

    u2_frm_wd_y = u2_pic_wd + (UWORD8)(PAD_LEN_Y_H << 1);
 if(1 == ps_dec->u4_share_disp_buf)
 {
 if(ps_dec->u4_app_disp_width > u2_frm_wd_y)
            u2_frm_wd_y = ps_dec->u4_app_disp_width;
 }

    u2_frm_ht_y = u2_pic_ht + (UWORD8)(PAD_LEN_Y_V << 2);
    u2_frm_wd_uv = u2_pic_wd + (UWORD8)(PAD_LEN_UV_H << 2);
    u2_frm_wd_uv = MAX(u2_frm_wd_uv, u2_frm_wd_y);

    u2_frm_ht_uv = (u2_pic_ht >> 1) + (UWORD8)(PAD_LEN_UV_V << 2);
    u2_frm_ht_uv = MAX(u2_frm_ht_uv, (u2_frm_ht_y >> 1));

 /* Calculate display picture width, height and start u4_ofst from YUV420 */
 /* pictute buffers as per cropping information parsed above             */
 {
        UWORD16 u2_rgt_ofst = 0;
        UWORD16 u2_lft_ofst = 0;
        UWORD16 u2_top_ofst = 0;
        UWORD16 u2_btm_ofst = 0;
        UWORD8 u1_frm_mbs_flag;
        UWORD8 u1_vert_mult_factor;

 if(u1_frame_cropping_flag)
 {
 /* Calculate right and left u4_ofst for cropped picture           */
            u2_rgt_ofst = u1_frame_cropping_rect_right_ofst << 1;
            u2_lft_ofst = u1_frame_cropping_rect_left_ofst << 1;

 /* Know frame MBs only u4_flag                                      */
            u1_frm_mbs_flag = (1 == ps_seq->u1_frame_mbs_only_flag);

 /* Simplify the vertical u4_ofst calculation from field/frame     */
            u1_vert_mult_factor = (2 - u1_frm_mbs_flag);

 /* Calculate bottom and top u4_ofst for cropped  picture          */
            u2_btm_ofst = (u1_frame_cropping_rect_bottom_ofst
 << u1_vert_mult_factor);
            u2_top_ofst = (u1_frame_cropping_rect_top_ofst
 << u1_vert_mult_factor);
 }

 /* Calculate u4_ofst from start of YUV 420 picture buffer to start of*/
 /* cropped picture buffer                                           */
        u2_crop_offset_y = (u2_frm_wd_y * u2_top_ofst) + (u2_lft_ofst);
        u2_crop_offset_uv = (u2_frm_wd_uv * (u2_top_ofst >> 1))
 + (u2_lft_ofst >> 1) * YUV420SP_FACTOR;
 /* Calculate the display picture width and height based on crop      */
 /* information                                                       */
        i4_cropped_ht = u2_pic_ht - (u2_btm_ofst + u2_top_ofst);
        i4_cropped_wd = u2_pic_wd - (u2_rgt_ofst + u2_lft_ofst);

 if((i4_cropped_ht < MB_SIZE) || (i4_cropped_wd < MB_SIZE))
 {
 return ERROR_INV_SPS_PPS_T;
 }

 if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_pic_wd != u2_pic_wd))
 {
            ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }
 if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_pic_ht != u2_pic_ht))
 {
            ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

 /* Check for unsupported resolutions */
 if((u2_pic_wd > H264_MAX_FRAME_WIDTH) || (u2_pic_ht > H264_MAX_FRAME_HEIGHT)
 || (u2_pic_wd < H264_MIN_FRAME_WIDTH) || (u2_pic_ht < H264_MIN_FRAME_HEIGHT)
 || (u2_pic_wd * (UWORD32)u2_pic_ht > H264_MAX_FRAME_SIZE))
 {
 return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;
 }

 /* If MBAff is enabled, decoder support is limited to streams with
         * width less than half of H264_MAX_FRAME_WIDTH.
         * In case of MBAff decoder processes two rows at a time
         */
 if((u2_pic_wd << ps_seq->u1_mb_aff_flag) > H264_MAX_FRAME_WIDTH)
 {
 return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;
 }

 }

 /* Backup u4_num_reorder_frames if header is already decoded */
 if((ps_dec->i4_header_decoded & 1) &&
 (1 == ps_seq->u1_vui_parameters_present_flag) &&
 (1 == ps_seq->s_vui.u1_bitstream_restriction_flag))
 {
        u4_num_reorder_frames =  ps_seq->s_vui.u4_num_reorder_frames;
 }
 else
 {
        u4_num_reorder_frames = -1;
 }
 if(1 == ps_seq->u1_vui_parameters_present_flag)
 {
        ret = ih264d_parse_vui_parametres(&ps_seq->s_vui, ps_bitstrm);
 if(ret != OK)
 return ret;
 }

 /* Compare older u4_num_reorder_frames with the new one if header is already decoded */
 if((ps_dec->i4_header_decoded & 1) &&
 (-1 != (WORD32)u4_num_reorder_frames) &&
 (1 == ps_seq->u1_vui_parameters_present_flag) &&
 (1 == ps_seq->s_vui.u1_bitstream_restriction_flag) &&
 (ps_seq->s_vui.u4_num_reorder_frames != u4_num_reorder_frames))
 {
        ps_dec->u1_res_changed = 1;
 return IVD_RES_CHANGED;
 }

 /* In case bitstream read has exceeded the filled size, then
     return an error */
 if (ps_bitstrm->u4_ofst > ps_bitstrm->u4_max_ofst)
 {
 return ERROR_INV_SPS_PPS_T;
 }

 /*--------------------------------------------------------------------*/
 /* All initializations to ps_dec are beyond this point                */
 /*--------------------------------------------------------------------*/
    ps_dec->u2_disp_height = i4_cropped_ht;
    ps_dec->u2_disp_width = i4_cropped_wd;

    ps_dec->u2_pic_wd = u2_pic_wd;
    ps_dec->u2_pic_ht = u2_pic_ht;

 /* Determining the Width and Height of Frame from that of Picture */
    ps_dec->u2_frm_wd_y = u2_frm_wd_y;
    ps_dec->u2_frm_ht_y = u2_frm_ht_y;

    ps_dec->u2_frm_wd_uv = u2_frm_wd_uv;
    ps_dec->u2_frm_ht_uv = u2_frm_ht_uv;
    ps_dec->s_pad_mgr.u1_pad_len_y_v = (UWORD8)(PAD_LEN_Y_V << (1 - u1_frm));
    ps_dec->s_pad_mgr.u1_pad_len_cr_v = (UWORD8)(PAD_LEN_UV_V << (1 - u1_frm));

    ps_dec->u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;
    ps_dec->u2_frm_ht_in_mbs = ps_seq->u2_frm_ht_in_mbs;

    ps_dec->u2_crop_offset_y = u2_crop_offset_y;
    ps_dec->u2_crop_offset_uv = u2_crop_offset_uv;

    ps_seq->u1_is_valid = TRUE;
    ps_dec->ps_sps[u1_seq_parameter_set_id] = *ps_seq;
    ps_dec->ps_cur_sps = &ps_dec->ps_sps[u1_seq_parameter_set_id];

 return OK;
}


static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
{
/*
	This is how the time string is formatted:

   snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
      ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
*/

	time_t ret;
	struct tm thetime;
	char * strbuf;
        char * thestr;
        long gmadjust = 0;

       if (timestr->length < 13) {
               php_error_docref(NULL TSRMLS_CC, E_WARNING, "extension author too lazy to parse %s correctly", timestr->data);
                return (time_t)-1;
        }

       strbuf = estrdup((char *)timestr->data);

        memset(&thetime, 0, sizeof(thetime));

        /* we work backwards so that we can use atoi more easily */

       thestr = strbuf + timestr->length - 3;

        thetime.tm_sec = atoi(thestr);
        *thestr = '\0';
	thetime.tm_mon = atoi(thestr)-1;
	*thestr = '\0';
	thestr -= 2;
	thetime.tm_year = atoi(thestr);

	if (thetime.tm_year < 68) {
		thetime.tm_year += 100;
	}

	thetime.tm_isdst = -1;
	ret = mktime(&thetime);

#if HAVE_TM_GMTOFF
	gmadjust = thetime.tm_gmtoff;
#else
	/*
	** If correcting for daylight savings time, we set the adjustment to
	** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
	** set the adjustment to the main timezone + 3600 seconds.
	*/
	gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
#endif
	ret += gmadjust;

	efree(strbuf);

	return ret;
}
/* }}} */

The asn1_time_to_time_t function in ext/openssl/openssl.c in PHP before 5.3.28, 5.4.x before 5.4.23, and 5.5.x before 5.5.7 does not properly parse (1) notBefore and (2) notAfter timestamps in X.509 certificates, which allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted certificate that is not properly handled by the openssl_x509_parse function.


static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
{
/*
	This is how the time string is formatted:

   snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
      ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
*/

	time_t ret;
	struct tm thetime;
	char * strbuf;
        char * thestr;
        long gmadjust = 0;

       if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME) {
               php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal ASN1 data type for timestamp");
                return (time_t)-1;
        }

       if (ASN1_STRING_length(timestr) != strlen(ASN1_STRING_data(timestr))) {
               php_error_docref(NULL TSRMLS_CC, E_WARNING, "illegal length in timestamp");
               return (time_t)-1;
       }

       if (ASN1_STRING_length(timestr) < 13) {
               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to parse time string %s correctly", timestr->data);
               return (time_t)-1;
       }

       strbuf = estrdup((char *)ASN1_STRING_data(timestr));

        memset(&thetime, 0, sizeof(thetime));

        /* we work backwards so that we can use atoi more easily */

       thestr = strbuf + ASN1_STRING_length(timestr) - 3;

        thetime.tm_sec = atoi(thestr);
        *thestr = '\0';
	thetime.tm_mon = atoi(thestr)-1;
	*thestr = '\0';
	thestr -= 2;
	thetime.tm_year = atoi(thestr);

	if (thetime.tm_year < 68) {
		thetime.tm_year += 100;
	}

	thetime.tm_isdst = -1;
	ret = mktime(&thetime);

#if HAVE_TM_GMTOFF
	gmadjust = thetime.tm_gmtoff;
#else
	/*
	** If correcting for daylight savings time, we set the adjustment to
	** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
	** set the adjustment to the main timezone + 3600 seconds.
	*/
	gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
#endif
	ret += gmadjust;

	efree(strbuf);

	return ret;
}
/* }}} */


static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC) /* {{{ */
{
	HashTable *data;
	int dirlen = strlen(dir);
	phar_zstr key;
	char *entry, *found, *save, *str_key;
	uint keylen;
	ulong unused;

	ALLOC_HASHTABLE(data);
	zend_hash_init(data, 64, zend_get_hash_value, NULL, 0);

	if ((*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) || (dirlen >= sizeof(".phar")-1 && !memcmp(dir, ".phar", sizeof(".phar")-1))) {
		/* make empty root directory for empty phar */
		/* make empty directory for .phar magic directory */
		efree(dir);
		return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
	}

        zend_hash_internal_pointer_reset(manifest);

        while (FAILURE != zend_hash_has_more_elements(manifest)) {
               if (HASH_KEY_IS_STRING != zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) {
                        break;
                }

		PHAR_STR(key, str_key);

		if (keylen <= (uint)dirlen) {
			if (keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) {
				PHAR_STR_FREE(str_key);
				if (SUCCESS != zend_hash_move_forward(manifest)) {
					break;
				}
				continue;
			}
		}

		if (*dir == '/') {
			/* root directory */
			if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
				PHAR_STR_FREE(str_key);
				/* do not add any magic entries to this directory */
				if (SUCCESS != zend_hash_move_forward(manifest)) {
					break;
				}
				continue;
			}

			if (NULL != (found = (char *) memchr(str_key, '/', keylen))) {
				/* the entry has a path separator and is a subdirectory */
				entry = (char *) safe_emalloc(found - str_key, 1, 1);
				memcpy(entry, str_key, found - str_key);
				keylen = found - str_key;
				entry[keylen] = '\0';
			} else {
				entry = (char *) safe_emalloc(keylen, 1, 1);
				memcpy(entry, str_key, keylen);
				entry[keylen] = '\0';
			}

			PHAR_STR_FREE(str_key);
			goto PHAR_ADD_ENTRY;
		} else {
			if (0 != memcmp(str_key, dir, dirlen)) {
				/* entry in directory not found */
				PHAR_STR_FREE(str_key);
				if (SUCCESS != zend_hash_move_forward(manifest)) {
					break;
				}
				continue;
			} else {
				if (str_key[dirlen] != '/') {
					PHAR_STR_FREE(str_key);
					if (SUCCESS != zend_hash_move_forward(manifest)) {
						break;
					}
					continue;
				}
			}
		}

		save = str_key;
		save += dirlen + 1; /* seek to just past the path separator */

		if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
			/* is subdirectory */
			save -= dirlen + 1;
			entry = (char *) safe_emalloc(found - save + dirlen, 1, 1);
			memcpy(entry, save + dirlen + 1, found - save - dirlen - 1);
			keylen = found - save - dirlen - 1;
			entry[keylen] = '\0';
		} else {
			/* is file */
			save -= dirlen + 1;
			entry = (char *) safe_emalloc(keylen - dirlen, 1, 1);
			memcpy(entry, save + dirlen + 1, keylen - dirlen - 1);
			entry[keylen - dirlen - 1] = '\0';
			keylen = keylen - dirlen - 1;
		}
		PHAR_STR_FREE(str_key);
PHAR_ADD_ENTRY:
		if (keylen) {
			phar_add_empty(data, entry, keylen);
		}

		efree(entry);

		if (SUCCESS != zend_hash_move_forward(manifest)) {
			break;
		}
	}

	if (FAILURE != zend_hash_has_more_elements(data)) {
		efree(dir);
		if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) {
			FREE_HASHTABLE(data);
			return NULL;
		}
		return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
	} else {
		efree(dir);
		return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
	}
}
/* }}}*/

Off-by-one error in the phar_parse_zipfile function in ext/phar/zip.c in PHP before 5.5.30 and 5.6.x before 5.6.14 allows remote attackers to cause a denial of service (uninitialized pointer dereference and application crash) by including the / filename in a .zip PHAR archive.


static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC) /* {{{ */
{
	HashTable *data;
	int dirlen = strlen(dir);
	phar_zstr key;
	char *entry, *found, *save, *str_key;
	uint keylen;
	ulong unused;

	ALLOC_HASHTABLE(data);
	zend_hash_init(data, 64, zend_get_hash_value, NULL, 0);

	if ((*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) || (dirlen >= sizeof(".phar")-1 && !memcmp(dir, ".phar", sizeof(".phar")-1))) {
		/* make empty root directory for empty phar */
		/* make empty directory for .phar magic directory */
		efree(dir);
		return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
	}

        zend_hash_internal_pointer_reset(manifest);

        while (FAILURE != zend_hash_has_more_elements(manifest)) {
               if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) {
                        break;
                }

		PHAR_STR(key, str_key);

		if (keylen <= (uint)dirlen) {
			if (keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) {
				PHAR_STR_FREE(str_key);
				if (SUCCESS != zend_hash_move_forward(manifest)) {
					break;
				}
				continue;
			}
		}

		if (*dir == '/') {
			/* root directory */
			if (keylen >= sizeof(".phar")-1 && !memcmp(str_key, ".phar", sizeof(".phar")-1)) {
				PHAR_STR_FREE(str_key);
				/* do not add any magic entries to this directory */
				if (SUCCESS != zend_hash_move_forward(manifest)) {
					break;
				}
				continue;
			}

			if (NULL != (found = (char *) memchr(str_key, '/', keylen))) {
				/* the entry has a path separator and is a subdirectory */
				entry = (char *) safe_emalloc(found - str_key, 1, 1);
				memcpy(entry, str_key, found - str_key);
				keylen = found - str_key;
				entry[keylen] = '\0';
			} else {
				entry = (char *) safe_emalloc(keylen, 1, 1);
				memcpy(entry, str_key, keylen);
				entry[keylen] = '\0';
			}

			PHAR_STR_FREE(str_key);
			goto PHAR_ADD_ENTRY;
		} else {
			if (0 != memcmp(str_key, dir, dirlen)) {
				/* entry in directory not found */
				PHAR_STR_FREE(str_key);
				if (SUCCESS != zend_hash_move_forward(manifest)) {
					break;
				}
				continue;
			} else {
				if (str_key[dirlen] != '/') {
					PHAR_STR_FREE(str_key);
					if (SUCCESS != zend_hash_move_forward(manifest)) {
						break;
					}
					continue;
				}
			}
		}

		save = str_key;
		save += dirlen + 1; /* seek to just past the path separator */

		if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
			/* is subdirectory */
			save -= dirlen + 1;
			entry = (char *) safe_emalloc(found - save + dirlen, 1, 1);
			memcpy(entry, save + dirlen + 1, found - save - dirlen - 1);
			keylen = found - save - dirlen - 1;
			entry[keylen] = '\0';
		} else {
			/* is file */
			save -= dirlen + 1;
			entry = (char *) safe_emalloc(keylen - dirlen, 1, 1);
			memcpy(entry, save + dirlen + 1, keylen - dirlen - 1);
			entry[keylen - dirlen - 1] = '\0';
			keylen = keylen - dirlen - 1;
		}
		PHAR_STR_FREE(str_key);
PHAR_ADD_ENTRY:
		if (keylen) {
			phar_add_empty(data, entry, keylen);
		}

		efree(entry);

		if (SUCCESS != zend_hash_move_forward(manifest)) {
			break;
		}
	}

	if (FAILURE != zend_hash_has_more_elements(data)) {
		efree(dir);
		if (zend_hash_sort(data, zend_qsort, phar_compare_dir_name, 0 TSRMLS_CC) == FAILURE) {
			FREE_HASHTABLE(data);
			return NULL;
		}
		return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
	} else {
		efree(dir);
		return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
	}
}
/* }}}*/


void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
{
	const char *s;

        while ((s = zend_memrchr(filename, '/', filename_len))) {
                filename_len = s - filename;
               if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
                        break;
                }
        }
}
/* }}} */


void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
{
	const char *s;

        while ((s = zend_memrchr(filename, '/', filename_len))) {
                filename_len = s - filename;
               if (!filename_len || FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
                        break;
                }
        }
}
/* }}} */


XcursorCommentCreate (XcursorUInt comment_type, int length)
{
    XcursorComment  *comment;

    if (length > XCURSOR_COMMENT_MAX_LEN)
	return NULL;
 {
     XcursorComment  *comment;

    if (length > XCURSOR_COMMENT_MAX_LEN)
 	return NULL;

     comment = malloc (sizeof (XcursorComment) + length + 1);
    comment->comment[0] = '\0';
    return comment;
}

void
XcursorCommentDestroy (XcursorComment *comment)
{
    free (comment);
}

XcursorComments *
XcursorCommentsCreate (int size)
{
    XcursorComments *comments;

    comments = malloc (sizeof (XcursorComments) +
		       size * sizeof (XcursorComment *));
    if (!comments)
	return NULL;
    comments->ncomment = 0;
    comments->comments = (XcursorComment **) (comments + 1);
    return comments;
}

void
XcursorCommentsDestroy (XcursorComments *comments)
{
    int	n;

    if (!comments)
        return;

    for (n = 0; n < comments->ncomment; n++)
	XcursorCommentDestroy (comments->comments[n]);
    free (comments);
}

static XcursorBool
_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
{
    unsigned char   bytes[4];

    if (!file || !u)
        return XcursorFalse;

    if ((*file->read) (file, bytes, 4) != 4)
	return XcursorFalse;
    *u = ((bytes[0] << 0) |
	  (bytes[1] << 8) |
	  (bytes[2] << 16) |
	  (bytes[3] << 24));
    return XcursorTrue;
}

static XcursorBool
_XcursorReadBytes (XcursorFile *file, char *bytes, int length)
{
    if (!file || !bytes || (*file->read) (file, (unsigned char *) bytes, length) != length)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorWriteUInt (XcursorFile *file, XcursorUInt u)
{
    unsigned char   bytes[4];

    if (!file)
        return XcursorFalse;

    bytes[0] = u;
    bytes[1] = u >>  8;
    bytes[2] = u >> 16;
    bytes[3] = u >> 24;
    if ((*file->write) (file, bytes, 4) != 4)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorWriteBytes (XcursorFile *file, char *bytes, int length)
{
    if (!file || !bytes || (*file->write) (file, (unsigned char *) bytes, length) != length)
	return XcursorFalse;
    return XcursorTrue;
}

static void
_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
{
    free (fileHeader);
}

static XcursorFileHeader *
_XcursorFileHeaderCreate (XcursorUInt ntoc)
{
    XcursorFileHeader	*fileHeader;

    if (ntoc > 0x10000)
	return NULL;
    fileHeader = malloc (sizeof (XcursorFileHeader) +
			 ntoc * sizeof (XcursorFileToc));
    if (!fileHeader)
	return NULL;
    fileHeader->magic = XCURSOR_MAGIC;
    fileHeader->header = XCURSOR_FILE_HEADER_LEN;
    fileHeader->version = XCURSOR_FILE_VERSION;
    fileHeader->ntoc = ntoc;
    fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
    return fileHeader;
}

static XcursorFileHeader *
_XcursorReadFileHeader (XcursorFile *file)
{
    XcursorFileHeader	head, *fileHeader;
    XcursorUInt		skip;
    int			n;

    if (!file)
        return NULL;

    if (!_XcursorReadUInt (file, &head.magic))
	return NULL;
    if (head.magic != XCURSOR_MAGIC)
	return NULL;
    if (!_XcursorReadUInt (file, &head.header))
	return NULL;
    if (!_XcursorReadUInt (file, &head.version))
	return NULL;
    if (!_XcursorReadUInt (file, &head.ntoc))
	return NULL;
    skip = head.header - XCURSOR_FILE_HEADER_LEN;
    if (skip)
	if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
	    return NULL;
    fileHeader = _XcursorFileHeaderCreate (head.ntoc);
    if (!fileHeader)
	return NULL;
    fileHeader->magic = head.magic;
    fileHeader->header = head.header;
    fileHeader->version = head.version;
    fileHeader->ntoc = head.ntoc;
    for (n = 0; n < fileHeader->ntoc; n++)
    {
	if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
	    break;
	if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
	    break;
	if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
	    break;
    }
    if (n != fileHeader->ntoc)
    {
	_XcursorFileHeaderDestroy (fileHeader);
	return NULL;
    }
    return fileHeader;
}

static XcursorUInt
_XcursorFileHeaderLength (XcursorFileHeader *fileHeader)
{
    return (XCURSOR_FILE_HEADER_LEN +
	    fileHeader->ntoc * XCURSOR_FILE_TOC_LEN);
}

static XcursorBool
_XcursorWriteFileHeader (XcursorFile *file, XcursorFileHeader *fileHeader)
{
    int	toc;

    if (!file || !fileHeader)
        return XcursorFalse;

    if (!_XcursorWriteUInt (file, fileHeader->magic))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, fileHeader->header))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, fileHeader->version))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, fileHeader->ntoc))
	return XcursorFalse;
    for (toc = 0; toc < fileHeader->ntoc; toc++)
    {
	if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].type))
	    return XcursorFalse;
	if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].subtype))
	    return XcursorFalse;
	if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].position))
	    return XcursorFalse;
    }
    return XcursorTrue;
}

static XcursorBool
_XcursorSeekToToc (XcursorFile		*file,
		   XcursorFileHeader	*fileHeader,
		   int			toc)
{
    if (!file || !fileHeader || \
        (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorFileReadChunkHeader (XcursorFile	*file,
			     XcursorFileHeader	*fileHeader,
			     int		toc,
			     XcursorChunkHeader	*chunkHeader)
{
    if (!file || !fileHeader || !chunkHeader)
        return XcursorFalse;
    if (!_XcursorSeekToToc (file, fileHeader, toc))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->header))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->type))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->subtype))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->version))
	return XcursorFalse;
    /* sanity check */
    if (chunkHeader->type != fileHeader->tocs[toc].type ||
	chunkHeader->subtype != fileHeader->tocs[toc].subtype)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorFileWriteChunkHeader (XcursorFile	    *file,
			      XcursorFileHeader	    *fileHeader,
			      int		    toc,
			      XcursorChunkHeader    *chunkHeader)
{
    if (!file || !fileHeader || !chunkHeader)
        return XcursorFalse;
    if (!_XcursorSeekToToc (file, fileHeader, toc))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->header))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->type))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->subtype))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->version))
	return XcursorFalse;
    return XcursorTrue;
}

#define dist(a,b)   ((a) > (b) ? (a) - (b) : (b) - (a))

static XcursorDim
_XcursorFindBestSize (XcursorFileHeader *fileHeader,
		      XcursorDim	size,
		      int		*nsizesp)
{
    int		n;
    int		nsizes = 0;
    XcursorDim	bestSize = 0;
    XcursorDim	thisSize;

    if (!fileHeader || !nsizesp)
        return 0;

    for (n = 0; n < fileHeader->ntoc; n++)
    {
	if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
	    continue;
	thisSize = fileHeader->tocs[n].subtype;
	if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
	{
	    bestSize = thisSize;
	    nsizes = 1;
	}
	else if (thisSize == bestSize)
	    nsizes++;
    }
    *nsizesp = nsizes;
    return bestSize;
}

static int
_XcursorFindImageToc (XcursorFileHeader	*fileHeader,
		      XcursorDim	size,
		      int		count)
{
    int			toc;
    XcursorDim		thisSize;

    if (!fileHeader)
        return 0;

    for (toc = 0; toc < fileHeader->ntoc; toc++)
    {
	if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
	    continue;
	thisSize = fileHeader->tocs[toc].subtype;
	if (thisSize != size)
	    continue;
	if (!count)
	    break;
	count--;
    }
    if (toc == fileHeader->ntoc)
	return -1;
    return toc;
}

static XcursorImage *
_XcursorReadImage (XcursorFile		*file,
		   XcursorFileHeader	*fileHeader,
		   int			toc)
{
    XcursorChunkHeader	chunkHeader;
    XcursorImage	head;
    XcursorImage	*image;
    int			n;
    XcursorPixel	*p;

    if (!file || !fileHeader)
        return NULL;

    if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
	return NULL;
    if (!_XcursorReadUInt (file, &head.width))
	return NULL;
    if (!_XcursorReadUInt (file, &head.height))
	return NULL;
    if (!_XcursorReadUInt (file, &head.xhot))
	return NULL;
    if (!_XcursorReadUInt (file, &head.yhot))
	return NULL;
    if (!_XcursorReadUInt (file, &head.delay))
	return NULL;
    /* sanity check data */
    if (head.width >= 0x10000 || head.height > 0x10000)
	return NULL;
     if (!_XcursorReadUInt (file, &head.delay))
 	return NULL;
     /* sanity check data */
    if (head.width >= 0x10000 || head.height > 0x10000)
 	return NULL;
     if (head.width == 0 || head.height == 0)
 	return NULL;
	image->version = chunkHeader.version;
    image->size = chunkHeader.subtype;

     /* Create the image and initialize it */
     image = XcursorImageCreate (head.width, head.height);
     if (chunkHeader.version < image->version)
 	image->version = chunkHeader.version;
     image->size = chunkHeader.subtype;
	{
	    XcursorImageDestroy (image);
	    return NULL;
	}
	p++;
    }
    return image;
}

libXcursor before 1.1.15 has various integer overflows that could lead to heap buffer overflows when processing malicious cursors, e.g., with programs like GIMP. It is also possible that an attack vector exists against the related code in cursor/xcursor.c in Wayland through 1.14.0.


XcursorCommentCreate (XcursorUInt comment_type, int length)
{
    XcursorComment  *comment;

    if (length > XCURSOR_COMMENT_MAX_LEN)
	return NULL;
 {
     XcursorComment  *comment;

    if (length < 0 || length > XCURSOR_COMMENT_MAX_LEN)
 	return NULL;

     comment = malloc (sizeof (XcursorComment) + length + 1);
    comment->comment[0] = '\0';
    return comment;
}

void
XcursorCommentDestroy (XcursorComment *comment)
{
    free (comment);
}

XcursorComments *
XcursorCommentsCreate (int size)
{
    XcursorComments *comments;

    comments = malloc (sizeof (XcursorComments) +
		       size * sizeof (XcursorComment *));
    if (!comments)
	return NULL;
    comments->ncomment = 0;
    comments->comments = (XcursorComment **) (comments + 1);
    return comments;
}

void
XcursorCommentsDestroy (XcursorComments *comments)
{
    int	n;

    if (!comments)
        return;

    for (n = 0; n < comments->ncomment; n++)
	XcursorCommentDestroy (comments->comments[n]);
    free (comments);
}

static XcursorBool
_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
{
    unsigned char   bytes[4];

    if (!file || !u)
        return XcursorFalse;

    if ((*file->read) (file, bytes, 4) != 4)
	return XcursorFalse;
    *u = ((bytes[0] << 0) |
	  (bytes[1] << 8) |
	  (bytes[2] << 16) |
	  (bytes[3] << 24));
    return XcursorTrue;
}

static XcursorBool
_XcursorReadBytes (XcursorFile *file, char *bytes, int length)
{
    if (!file || !bytes || (*file->read) (file, (unsigned char *) bytes, length) != length)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorWriteUInt (XcursorFile *file, XcursorUInt u)
{
    unsigned char   bytes[4];

    if (!file)
        return XcursorFalse;

    bytes[0] = u;
    bytes[1] = u >>  8;
    bytes[2] = u >> 16;
    bytes[3] = u >> 24;
    if ((*file->write) (file, bytes, 4) != 4)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorWriteBytes (XcursorFile *file, char *bytes, int length)
{
    if (!file || !bytes || (*file->write) (file, (unsigned char *) bytes, length) != length)
	return XcursorFalse;
    return XcursorTrue;
}

static void
_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
{
    free (fileHeader);
}

static XcursorFileHeader *
_XcursorFileHeaderCreate (XcursorUInt ntoc)
{
    XcursorFileHeader	*fileHeader;

    if (ntoc > 0x10000)
	return NULL;
    fileHeader = malloc (sizeof (XcursorFileHeader) +
			 ntoc * sizeof (XcursorFileToc));
    if (!fileHeader)
	return NULL;
    fileHeader->magic = XCURSOR_MAGIC;
    fileHeader->header = XCURSOR_FILE_HEADER_LEN;
    fileHeader->version = XCURSOR_FILE_VERSION;
    fileHeader->ntoc = ntoc;
    fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
    return fileHeader;
}

static XcursorFileHeader *
_XcursorReadFileHeader (XcursorFile *file)
{
    XcursorFileHeader	head, *fileHeader;
    XcursorUInt		skip;
    int			n;

    if (!file)
        return NULL;

    if (!_XcursorReadUInt (file, &head.magic))
	return NULL;
    if (head.magic != XCURSOR_MAGIC)
	return NULL;
    if (!_XcursorReadUInt (file, &head.header))
	return NULL;
    if (!_XcursorReadUInt (file, &head.version))
	return NULL;
    if (!_XcursorReadUInt (file, &head.ntoc))
	return NULL;
    skip = head.header - XCURSOR_FILE_HEADER_LEN;
    if (skip)
	if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
	    return NULL;
    fileHeader = _XcursorFileHeaderCreate (head.ntoc);
    if (!fileHeader)
	return NULL;
    fileHeader->magic = head.magic;
    fileHeader->header = head.header;
    fileHeader->version = head.version;
    fileHeader->ntoc = head.ntoc;
    for (n = 0; n < fileHeader->ntoc; n++)
    {
	if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
	    break;
	if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
	    break;
	if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
	    break;
    }
    if (n != fileHeader->ntoc)
    {
	_XcursorFileHeaderDestroy (fileHeader);
	return NULL;
    }
    return fileHeader;
}

static XcursorUInt
_XcursorFileHeaderLength (XcursorFileHeader *fileHeader)
{
    return (XCURSOR_FILE_HEADER_LEN +
	    fileHeader->ntoc * XCURSOR_FILE_TOC_LEN);
}

static XcursorBool
_XcursorWriteFileHeader (XcursorFile *file, XcursorFileHeader *fileHeader)
{
    int	toc;

    if (!file || !fileHeader)
        return XcursorFalse;

    if (!_XcursorWriteUInt (file, fileHeader->magic))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, fileHeader->header))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, fileHeader->version))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, fileHeader->ntoc))
	return XcursorFalse;
    for (toc = 0; toc < fileHeader->ntoc; toc++)
    {
	if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].type))
	    return XcursorFalse;
	if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].subtype))
	    return XcursorFalse;
	if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].position))
	    return XcursorFalse;
    }
    return XcursorTrue;
}

static XcursorBool
_XcursorSeekToToc (XcursorFile		*file,
		   XcursorFileHeader	*fileHeader,
		   int			toc)
{
    if (!file || !fileHeader || \
        (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorFileReadChunkHeader (XcursorFile	*file,
			     XcursorFileHeader	*fileHeader,
			     int		toc,
			     XcursorChunkHeader	*chunkHeader)
{
    if (!file || !fileHeader || !chunkHeader)
        return XcursorFalse;
    if (!_XcursorSeekToToc (file, fileHeader, toc))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->header))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->type))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->subtype))
	return XcursorFalse;
    if (!_XcursorReadUInt (file, &chunkHeader->version))
	return XcursorFalse;
    /* sanity check */
    if (chunkHeader->type != fileHeader->tocs[toc].type ||
	chunkHeader->subtype != fileHeader->tocs[toc].subtype)
	return XcursorFalse;
    return XcursorTrue;
}

static XcursorBool
_XcursorFileWriteChunkHeader (XcursorFile	    *file,
			      XcursorFileHeader	    *fileHeader,
			      int		    toc,
			      XcursorChunkHeader    *chunkHeader)
{
    if (!file || !fileHeader || !chunkHeader)
        return XcursorFalse;
    if (!_XcursorSeekToToc (file, fileHeader, toc))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->header))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->type))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->subtype))
	return XcursorFalse;
    if (!_XcursorWriteUInt (file, chunkHeader->version))
	return XcursorFalse;
    return XcursorTrue;
}

#define dist(a,b)   ((a) > (b) ? (a) - (b) : (b) - (a))

static XcursorDim
_XcursorFindBestSize (XcursorFileHeader *fileHeader,
		      XcursorDim	size,
		      int		*nsizesp)
{
    int		n;
    int		nsizes = 0;
    XcursorDim	bestSize = 0;
    XcursorDim	thisSize;

    if (!fileHeader || !nsizesp)
        return 0;

    for (n = 0; n < fileHeader->ntoc; n++)
    {
	if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
	    continue;
	thisSize = fileHeader->tocs[n].subtype;
	if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
	{
	    bestSize = thisSize;
	    nsizes = 1;
	}
	else if (thisSize == bestSize)
	    nsizes++;
    }
    *nsizesp = nsizes;
    return bestSize;
}

static int
_XcursorFindImageToc (XcursorFileHeader	*fileHeader,
		      XcursorDim	size,
		      int		count)
{
    int			toc;
    XcursorDim		thisSize;

    if (!fileHeader)
        return 0;

    for (toc = 0; toc < fileHeader->ntoc; toc++)
    {
	if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
	    continue;
	thisSize = fileHeader->tocs[toc].subtype;
	if (thisSize != size)
	    continue;
	if (!count)
	    break;
	count--;
    }
    if (toc == fileHeader->ntoc)
	return -1;
    return toc;
}

static XcursorImage *
_XcursorReadImage (XcursorFile		*file,
		   XcursorFileHeader	*fileHeader,
		   int			toc)
{
    XcursorChunkHeader	chunkHeader;
    XcursorImage	head;
    XcursorImage	*image;
    int			n;
    XcursorPixel	*p;

    if (!file || !fileHeader)
        return NULL;

    if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
	return NULL;
    if (!_XcursorReadUInt (file, &head.width))
	return NULL;
    if (!_XcursorReadUInt (file, &head.height))
	return NULL;
    if (!_XcursorReadUInt (file, &head.xhot))
	return NULL;
    if (!_XcursorReadUInt (file, &head.yhot))
	return NULL;
    if (!_XcursorReadUInt (file, &head.delay))
	return NULL;
    /* sanity check data */
    if (head.width >= 0x10000 || head.height > 0x10000)
	return NULL;
     if (!_XcursorReadUInt (file, &head.delay))
 	return NULL;
     /* sanity check data */
    if (head.width > XCURSOR_IMAGE_MAX_SIZE  ||
	head.height > XCURSOR_IMAGE_MAX_SIZE)
 	return NULL;
     if (head.width == 0 || head.height == 0)
 	return NULL;
	image->version = chunkHeader.version;
    image->size = chunkHeader.subtype;

     /* Create the image and initialize it */
     image = XcursorImageCreate (head.width, head.height);
    if (image == NULL)
	return NULL;
     if (chunkHeader.version < image->version)
 	image->version = chunkHeader.version;
     image->size = chunkHeader.subtype;
	{
	    XcursorImageDestroy (image);
	    return NULL;
	}
	p++;
    }
    return image;
}