Exemplo n.º 1
0
/**
 * Calculates the decoded string length.
 *
 * @returns Number of chars (excluding the terminator).
 * @param   pszString       The string to decode.
 * @param   cchMax          The maximum string length (e.g. RTSTR_MAX).
 */
static size_t rtUriCalcDecodedLength(const char *pszString, size_t cchMax)
{
    size_t cchDecoded;
    if (pszString)
    {
        size_t cchSrcLeft = cchDecoded = RTStrNLen(pszString, cchMax);
        while (cchSrcLeft-- > 0)
        {
            char const ch = *pszString++;
            if (ch != '%')
            { /* typical */}
            else if (   cchSrcLeft >= 2
                     && RT_C_IS_XDIGIT(pszString[0])
                     && RT_C_IS_XDIGIT(pszString[1]))
            {
                cchDecoded -= 2;
                pszString  += 2;
                cchSrcLeft -= 2;
            }
        }
    }
    else
        cchDecoded = 0;
    return cchDecoded;
}
Exemplo n.º 2
0
/**
 * Encodes an URI into a caller allocated buffer.
 *
 * @returns IPRT status code.
 * @param   pszString       The string to encode.
 * @param   cchMax          The maximum string length (e.g. RTSTR_MAX).
 * @param   fEncodeDosSlash Whether to encode DOS slashes or not.
 * @param   pszDst          The destination buffer.
 * @param   cbDst           The size of the destination buffer.
 */
static int rtUriEncodeIntoBuffer(const char *pszString, size_t cchMax, bool fEncodeDosSlash, char *pszDst, size_t cbDst)
{
    AssertReturn(pszString, VERR_INVALID_POINTER);
    AssertPtrReturn(pszDst, VERR_INVALID_POINTER);

    /*
     * We do buffer size checking up front and every time we encode a special
     * character.  That's faster than checking for each char.
     */
    size_t cchSrcLeft = RTStrNLen(pszString, cchMax);
    AssertMsgReturn(cbDst > cchSrcLeft, ("cbDst=%zu cchSrcLeft=%zu\n", cbDst, cchSrcLeft), VERR_BUFFER_OVERFLOW);
    cbDst -= cchSrcLeft;

    while (cchSrcLeft-- > 0)
    {
        char const ch = *pszString++;
        if (!URI_EXCLUDED(ch) || (ch == '\\' && !fEncodeDosSlash))
            *pszDst++ = ch;
        else
        {
            AssertReturn(cbDst >= 3, VERR_BUFFER_OVERFLOW); /* 2 extra bytes + zero terminator. */
            cbDst -= 2;

            *pszDst++ = '%';
            ssize_t cchTmp = RTStrFormatU8(pszDst, 3, (unsigned char)ch, 16, 2, 2, RTSTR_F_CAPITAL | RTSTR_F_ZEROPAD);
            Assert(cchTmp == 2); NOREF(cchTmp);
            pszDst += 2;
        }
    }

    *pszDst = '\0';
    return VINF_SUCCESS;
}
Exemplo n.º 3
0
Arquivo: tftp.c Projeto: ryenus/vbox
DECLINLINE(bool) tftpIsAcceptableOption(const char *pszOptionName)
{
    int idxOptDesc = 0;
    AssertPtrReturn(pszOptionName, false);
    AssertReturn(RTStrNLen(pszOptionName,10) >= 4, false);
    AssertReturn(RTStrNLen(pszOptionName,10) < 8, false);
    for(idxOptDesc = 0; idxOptDesc < RT_ELEMENTS(g_TftpTransferFmtDesc); ++idxOptDesc)
    {
        if (!RTStrNICmp(pszOptionName, g_TftpTransferFmtDesc[idxOptDesc].pszName, 10))
            return true;
    }
    for(idxOptDesc = 0; idxOptDesc < RT_ELEMENTS(g_TftpDesc); ++idxOptDesc)
    {
        if (!RTStrNICmp(pszOptionName, g_TftpDesc[idxOptDesc].pszName, 10))
            return true;
    }
    return false;
}
Exemplo n.º 4
0
RTDECL(int) RTStrAAppendExNVTag(char **ppsz, size_t cPairs, va_list va, const char *pszTag)
{
    AssertPtr(ppsz);
    if (!cPairs)
        return VINF_SUCCESS;

    /*
     * Determine the length of each string and calc the new total.
     */
    struct RTStrAAppendExNVStruct
    {
        const char *psz;
        size_t      cch;
    } *paPairs = (struct RTStrAAppendExNVStruct *)alloca(cPairs * sizeof(*paPairs));
    AssertReturn(paPairs, VERR_NO_STR_MEMORY);

    size_t  cchOrg      = *ppsz ? strlen(*ppsz) : 0;
    size_t  cchNewTotal = cchOrg;
    for (size_t i = 0; i < cPairs; i++)
    {
        const char *psz = va_arg(va, const char *);
        size_t      cch = va_arg(va, size_t);
        AssertPtrNull(psz);
        Assert(cch == RTSTR_MAX || cch == RTStrNLen(psz, cch));

        if (cch == RTSTR_MAX)
            cch = psz ? strlen(psz) : 0;
        cchNewTotal += cch;

        paPairs[i].cch = cch;
        paPairs[i].psz = psz;
    }
    cchNewTotal++;                      /* '\0' */

    /*
     * Try reallocate the string.
     */
    char *pszNew = (char *)RTMemReallocTag(*ppsz, cchNewTotal, pszTag);
    if (!pszNew)
        return VERR_NO_STR_MEMORY;

    /*
     * Do the appending.
     */
    size_t off = cchOrg;
    for (size_t i = 0; i < cPairs; i++)
    {
        memcpy(&pszNew[off], paPairs[i].psz, paPairs[i].cch);
        off += paPairs[i].cch;
    }
    Assert(off + 1 == cchNewTotal);
    pszNew[off] = '\0';

    /* done */
    *ppsz = pszNew;
    return VINF_SUCCESS;
}
Exemplo n.º 5
0
Arquivo: tftp.c Projeto: ryenus/vbox
DECLINLINE(void) tftpProcessRRQ(PNATState pData, PCTFTPIPHDR pTftpIpHeader, int pktlen)
{
    PTFTPSESSION pTftpSession = NULL;
    uint8_t *pu8Payload = NULL;
    int     cbPayload = 0;
    size_t cbFileName = 0;
    int rc = VINF_SUCCESS;

    AssertPtrReturnVoid(pTftpIpHeader);
    AssertPtrReturnVoid(pData);
    AssertReturnVoid(pktlen > sizeof(TFTPIPHDR));
    LogFlowFunc(("ENTER: pTftpIpHeader:%p, pktlen:%d\n", pTftpIpHeader, pktlen));

    rc = tftpAllocateSession(pData, pTftpIpHeader, &pTftpSession);
    if (   RT_FAILURE(rc)
        || pTftpSession == NULL)
    {
        LogFlowFuncLeave();
        return;
    }

    pu8Payload = (uint8_t *)&pTftpIpHeader->Core;
    cbPayload = pktlen - sizeof(TFTPIPHDR);

    cbFileName = RTStrNLen((char *)pu8Payload, cbPayload);
    /* We assume that file name should finish with '\0' and shouldn't bigger
     *  than buffer for name storage.
     */
    AssertReturnVoid(   cbFileName < cbPayload
                     && cbFileName < TFTP_FILENAME_MAX /* current limit in tftp session handle */
                     && cbFileName);

    /* Dont't bother with rest processing in case of invalid access */
    if (RT_FAILURE(tftpSecurityFilenameCheck(pData, pTftpSession)))
    {
        tftpSendError(pData, pTftpSession, 2, "Access violation", pTftpIpHeader);
        LogFlowFuncLeave();
        return;
    }



    if (RT_UNLIKELY(!tftpIsSupportedTransferMode(pTftpSession)))
    {
        tftpSendError(pData, pTftpSession, 4, "Unsupported transfer mode", pTftpIpHeader);
        LogFlowFuncLeave();
        return;
    }


    tftpSendOACK(pData, pTftpSession, pTftpIpHeader);
    LogFlowFuncLeave();
    return;
}
Exemplo n.º 6
0
/**
 * Calculates the encoded string length.
 *
 * @returns Number of chars (excluding the terminator).
 * @param   pszString       The string to encode.
 * @param   cchMax          The maximum string length (e.g. RTSTR_MAX).
 * @param   fEncodeDosSlash Whether to encode DOS slashes or not.
 */
static size_t rtUriCalcEncodedLength(const char *pszString, size_t cchMax, bool fEncodeDosSlash)
{
    size_t cchEncoded = 0;
    if (pszString)
    {
        size_t cchSrcLeft = RTStrNLen(pszString, cchMax);
        while (cchSrcLeft-- > 0)
        {
            char const ch = *pszString++;
            if (!URI_EXCLUDED(ch) || (ch == '\\' && !fEncodeDosSlash))
                cchEncoded += 1;
            else
                cchEncoded += 3;
        }
    }
    return cchEncoded;
}
Exemplo n.º 7
0
Arquivo: tftp.c Projeto: ryenus/vbox
/**
 * This function evaluate file name.
 * @param pu8Payload
 * @param cbPayload
 * @param cbFileName
 * @return VINF_SUCCESS -
 *         VERR_INVALID_PARAMETER -
 */
DECLINLINE(int) tftpSecurityFilenameCheck(PNATState pData, PCTFTPSESSION pcTftpSession)
{
    size_t cbSessionFilename = 0;
    int rc = VINF_SUCCESS;
    AssertPtrReturn(pcTftpSession, VERR_INVALID_PARAMETER);
    cbSessionFilename = RTStrNLen((const char *)pcTftpSession->pszFilename, TFTP_FILENAME_MAX);
    if (   !RTStrNCmp((const char*)pcTftpSession->pszFilename, "../", 3)
        || (pcTftpSession->pszFilename[cbSessionFilename - 1] == '/')
        ||  RTStrStr((const char *)pcTftpSession->pszFilename, "/../"))
        rc = VERR_FILE_NOT_FOUND;

    /* only allow exported prefixes */
    if (   RT_SUCCESS(rc)
        && !tftp_prefix)
        rc = VERR_INTERNAL_ERROR;
    LogFlowFuncLeaveRC(rc);
    return rc;
}
Exemplo n.º 8
0
RTDECL(int) RTPathJoinEx(char *pszPathDst, size_t cbPathDst,
                         const char *pszPathSrc, size_t cchPathSrcMax,
                         const char *pszAppend, size_t cchAppendMax)
{
    AssertPtr(pszPathDst);
    AssertPtr(pszPathSrc);
    AssertPtr(pszAppend);

    /*
     * The easy way: Copy the path into the buffer and call RTPathAppend.
     */
    size_t cchPathSrc = RTStrNLen(pszPathSrc, cchPathSrcMax);
    if (cchPathSrc >= cbPathDst)
        return VERR_BUFFER_OVERFLOW;
    memcpy(pszPathDst, pszPathSrc, cchPathSrc);
    pszPathDst[cchPathSrc] = '\0';

    return RTPathAppendEx(pszPathDst, cbPathDst, pszAppend, cchAppendMax);
}
Exemplo n.º 9
0
RTDECL(int) RTStrAAppendNTag(char **ppsz, const char *pszAppend, size_t cchAppend, const char *pszTag)
{
    size_t cchOrg;
    char  *pszNew;

    if (!cchAppend)
        return VINF_SUCCESS;
    if (cchAppend == RTSTR_MAX)
        cchAppend = strlen(pszAppend);
    else
        Assert(cchAppend == RTStrNLen(pszAppend, cchAppend));

    cchOrg = *ppsz ? strlen(*ppsz) : 0;
    pszNew = (char *)RTMemReallocTag(*ppsz, cchOrg + cchAppend + 1, pszTag);
    if (!pszNew)
        return VERR_NO_STR_MEMORY;

    memcpy(&pszNew[cchOrg], pszAppend, cchAppend);
    pszNew[cchOrg + cchAppend] = '\0';

    *ppsz = pszNew;
    return VINF_SUCCESS;
}
Exemplo n.º 10
0
void Bstr::copyFromN(const char *a_pszSrc, size_t a_cchMax)
{
    /*
     * Initialie m_bstr first in case of throws further down in the code, then
     * check for empty input (m_bstr == NULL means empty, there are no NULL
     * strings).
     */
    m_bstr = NULL;
    if (!a_cchMax || !a_pszSrc || !*a_pszSrc)
        return;

    /*
     * Calculate the length and allocate a BSTR string buffer of the right
     * size, i.e. optimize heap usage.
     */
    size_t cwc;
    int vrc = ::RTStrCalcUtf16LenEx(a_pszSrc, a_cchMax, &cwc);
    if (RT_SUCCESS(vrc))
    {
        m_bstr = ::SysAllocStringByteLen(NULL, (unsigned)(cwc * sizeof(OLECHAR)));
        if (RT_LIKELY(m_bstr))
        {
            PRTUTF16 pwsz = (PRTUTF16)m_bstr;
            vrc = ::RTStrToUtf16Ex(a_pszSrc, a_cchMax, &pwsz, cwc + 1, NULL);
            if (RT_SUCCESS(vrc))
                return;

            /* This should not happen! */
            AssertRC(vrc);
            cleanup();
        }
    }
    else /* ASSUME: input is valid Utf-8. Fake out of memory error. */
        AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTStrNLen(a_pszSrc, a_cchMax), a_pszSrc));
    throw std::bad_alloc();
}
Exemplo n.º 11
0
RTDECL(int) RTPathAppendEx(char *pszPath, size_t cbPathDst, const char *pszAppend, size_t cchAppendMax)
{
    char *pszPathEnd = RTStrEnd(pszPath, cbPathDst);
    AssertReturn(pszPathEnd, VERR_INVALID_PARAMETER);

    /*
     * Special cases.
     */
    if (!pszAppend)
        return VINF_SUCCESS;
    size_t cchAppend = RTStrNLen(pszAppend, cchAppendMax);
    if (!cchAppend)
        return VINF_SUCCESS;
    if (pszPathEnd == pszPath)
    {
        if (cchAppend >= cbPathDst)
            return VERR_BUFFER_OVERFLOW;
        memcpy(pszPath, pszAppend, cchAppend);
        pszPath[cchAppend] = '\0';
        return VINF_SUCCESS;
    }

    /*
     * Balance slashes and check for buffer overflow.
     */
    if (!RTPATH_IS_SLASH(pszPathEnd[-1]))
    {
        if (!RTPATH_IS_SLASH(pszAppend[0]))
        {
#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
            if (    (size_t)(pszPathEnd - pszPath) == 2
                &&  pszPath[1] == ':'
                &&  RT_C_IS_ALPHA(pszPath[0]))
            {
                if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
                    return VERR_BUFFER_OVERFLOW;
            }
            else
#endif
            {
                if ((size_t)(pszPathEnd - pszPath) + 1 + cchAppend >= cbPathDst)
                    return VERR_BUFFER_OVERFLOW;
                *pszPathEnd++ = RTPATH_SLASH;
            }
        }
        else
        {
            /* One slash is sufficient at this point. */
            while (cchAppend > 1 && RTPATH_IS_SLASH(pszAppend[1]))
                pszAppend++, cchAppend--;

            if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
                return VERR_BUFFER_OVERFLOW;
        }
    }
    else
    {
        /* No slashes needed in the appended bit. */
        while (cchAppend && RTPATH_IS_SLASH(*pszAppend))
            pszAppend++, cchAppend--;

        /* In the leading path we can skip unnecessary trailing slashes, but
           be sure to leave one. */
        size_t const cchRoot = rtPathRootSpecLen2(pszPath);
        while (     (size_t)(pszPathEnd - pszPath) > RT_MAX(1, cchRoot)
               &&   RTPATH_IS_SLASH(pszPathEnd[-2]))
            pszPathEnd--;

        if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
            return VERR_BUFFER_OVERFLOW;
    }

    /*
     * What remains now is the just the copying.
     */
    memcpy(pszPathEnd, pszAppend, cchAppend);
    pszPathEnd[cchAppend] = '\0';
    return VINF_SUCCESS;
}
Exemplo n.º 12
0
/**
 * Parses and validates a TAR header.
 *
 * @returns IPRT status code.
 * @param   pThis               The TAR reader stat.
 * @param   pTar                The TAR header that has been read.
 */
static int rtZipTarReaderParseHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr)
{
    switch (pThis->enmState)
    {
        /*
         * The first record for a file/directory/whatever.
         */
        case RTZIPTARREADERSTATE_FIRST:
            pThis->Hdr.Common.typeflag  = 0x7f;
            pThis->enmPrevType          = pThis->enmType;
            pThis->enmType              = RTZIPTARTYPE_INVALID;
            pThis->offGnuLongCur        = 0;
            pThis->cbGnuLongExpect      = 0;
            pThis->szName[0]            = '\0';
            pThis->szTarget[0]          = '\0';
            return rtZipTarReaderParseNextHeader(pThis, pHdr, true /*fFirst*/);

        /*
         * There should only be so many zero headers at the end of the file as
         * it is a function of the block size used when writing.  Don't go on
         * reading them forever in case someone points us to /dev/zero.
         */
        case RTZIPTARREADERSTATE_ZERO:
            if (ASMMemIsAllU32(pHdr, sizeof(*pHdr), 0) != NULL)
                return VERR_TAR_ZERO_HEADER;
            pThis->cZeroHdrs++;
            if (pThis->cZeroHdrs <= _64K / 512 + 2)
                return VINF_SUCCESS;
            return VERR_TAR_ZERO_HEADER;

        case RTZIPTARREADERSTATE_GNU_LONGNAME:
        case RTZIPTARREADERSTATE_GNU_LONGLINK:
        {
            size_t cbIncoming = RTStrNLen((const char *)pHdr->ab, sizeof(*pHdr));
            if (cbIncoming < sizeof(*pHdr))
                cbIncoming += 1;

            if (cbIncoming + pThis->offGnuLongCur > pThis->cbGnuLongExpect)
                return VERR_TAR_MALFORMED_GNU_LONGXXXX;
            if (   cbIncoming < sizeof(*pHdr)
                && cbIncoming + pThis->offGnuLongCur != pThis->cbGnuLongExpect)
                return VERR_TAR_MALFORMED_GNU_LONGXXXX;

            char *pszDst = pThis->enmState == RTZIPTARREADERSTATE_GNU_LONGNAME ? pThis->szName : pThis->szTarget;
            pszDst += pThis->offGnuLongCur;
            memcpy(pszDst, pHdr->ab, cbIncoming);

            pThis->offGnuLongCur += (uint32_t)cbIncoming;
            if (pThis->offGnuLongCur == pThis->cbGnuLongExpect)
                pThis->enmState = RTZIPTARREADERSTATE_GNU_NEXT;
            return VINF_SUCCESS;
        }

        case RTZIPTARREADERSTATE_GNU_NEXT:
            pThis->enmState = RTZIPTARREADERSTATE_FIRST;
            return rtZipTarReaderParseNextHeader(pThis, pHdr, false /*fFirst*/);

        default:
            return VERR_INTERNAL_ERROR_5;
    }
}
Exemplo n.º 13
0
Arquivo: tftp.c Projeto: ryenus/vbox
DECLINLINE(int) tftpSessionOptionParse(PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeader)
{
    int rc = VINF_SUCCESS;
    char *pszTftpRRQRaw;
    size_t idxTftpRRQRaw = 0;
    int cbTftpRRQRaw = 0;
    int fWithArg = 0;
    int idxOptionArg = 0;
    AssertPtrReturn(pTftpSession, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pcTftpIpHeader, VERR_INVALID_PARAMETER);
    AssertReturn(RT_N2H_U16(pcTftpIpHeader->u16TftpOpType) == TFTP_RRQ, VERR_INVALID_PARAMETER);
    LogFlowFunc(("pTftpSession:%p, pcTftpIpHeader:%p\n", pTftpSession, pcTftpIpHeader));
    pszTftpRRQRaw = (char *)&pcTftpIpHeader->Core;
    cbTftpRRQRaw = RT_H2N_U16(pcTftpIpHeader->UdpHdr.uh_ulen) + sizeof(struct ip) - RT_OFFSETOF(TFTPIPHDR, Core);
    while(cbTftpRRQRaw)
    {
        idxTftpRRQRaw = RTStrNLen(pszTftpRRQRaw, 512 - idxTftpRRQRaw) + 1;
        if (RTStrNLen((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX) == 0)
        {
            rc = RTStrCopy((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX, pszTftpRRQRaw);
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
        }
        else if (pTftpSession->enmTftpFmt == TFTPFMT_NONE)
        {
            int idxFmt = 0;
            rc = tftpFindTransferFormatIdxbyName(&idxFmt, pszTftpRRQRaw);
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR);
                return VERR_INTERNAL_ERROR;
            }
            AssertReturn(   g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NONE
                         && g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NOT_FMT, VERR_INTERNAL_ERROR);
            pTftpSession->enmTftpFmt = g_TftpTransferFmtDesc[idxFmt].enmType;
        }
        else if (fWithArg)
        {
            if (!RTStrICmp("blksize", g_TftpDesc[idxOptionArg].pszName))
            {
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionBlkSize);
                if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX)
                    rc = VERR_INVALID_PARAMETER;
            }

            if (   RT_SUCCESS(rc)
                && !RTStrICmp("tsize", g_TftpDesc[idxOptionArg].pszName))
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTSize);

            /* @todo: we don't use timeout, but its value in the range 0-255 */
            if (   RT_SUCCESS(rc)
                && !RTStrICmp("timeout", g_TftpDesc[idxOptionArg].pszName))
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTimeout);

            /* @todo: unknown option detection */
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
            fWithArg = 0;
            idxOptionArg = 0;
        }
        else
        {
            rc = tftpFindOptionIdxbyName(&idxOptionArg, pszTftpRRQRaw);
            if (RT_SUCCESS(rc))
                fWithArg = 1;
            else
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
        }
        pszTftpRRQRaw += idxTftpRRQRaw;
        cbTftpRRQRaw -= idxTftpRRQRaw;
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}
Exemplo n.º 14
0
/**
 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
 */
static DECLCALLBACK(int) dbgDiggerLinuxIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
                                                            char *pszBuf, size_t cbBuf, size_t *pcbActual)
{
    PDBGDIGGERLINUX pData = RT_FROM_MEMBER(pThis, DBGDIGGERLINUX, IDmesg);

    if (cMessages < 1)
        return VERR_INVALID_PARAMETER;

    /*
     * Resolve the symbols we need and read their values.
     */
    RTDBGAS  hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
    RTDBGMOD hMod;
    int rc = RTDbgAsModuleByName(hAs, "vmlinux", 0, &hMod);
    if (RT_FAILURE(rc))
        return VERR_NOT_FOUND;
    RTDbgAsRelease(hAs);

    RTGCPTR  GCPtrLogBuf;
    uint32_t cbLogBuf;
    uint32_t idxFirst;
    uint32_t idxNext;

    struct { void *pvVar; size_t cbHost, cbGuest; const char *pszSymbol; } aSymbols[] =
    {
        { &GCPtrLogBuf, sizeof(GCPtrLogBuf),    pData->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t),   "log_buf" },
        { &cbLogBuf,    sizeof(cbLogBuf),       sizeof(cbLogBuf),                                      "log_buf_len" },
        { &idxFirst,    sizeof(idxFirst),       sizeof(idxFirst),                                      "log_first_idx" },
        { &idxNext,     sizeof(idxNext),        sizeof(idxNext),                                       "log_next_idx" },
    };
    for (uint32_t i = 0; i < RT_ELEMENTS(aSymbols); i++)
    {
        RTDBGSYMBOL SymInfo;
        rc = RTDbgModSymbolByName(hMod, aSymbols[i].pszSymbol, &SymInfo);
        if (RT_SUCCESS(rc))
        {
            RT_BZERO(aSymbols[i].pvVar, aSymbols[i].cbHost);
            Assert(aSymbols[i].cbHost >= aSymbols[i].cbGuest);
            DBGFADDRESS Addr;
            rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
                               DBGFR3AddrFromFlat(pUVM, &Addr, (RTGCPTR)SymInfo.Value + pData->AddrKernelBase.FlatPtr),
                               aSymbols[i].pvVar,  aSymbols[i].cbGuest);
            if (RT_SUCCESS(rc))
                continue;
            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Reading '%s' at %RGv: %Rrc\n", aSymbols[i].pszSymbol, Addr.FlatPtr, rc));
        }
        else
            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error looking up '%s': %Rrc\n", aSymbols[i].pszSymbol, rc));
        RTDbgModRelease(hMod);
        return VERR_NOT_FOUND;
    }

    /*
     * Check if the values make sense.
     */
    if (pData->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
    {
        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf' value %RGv is not valid.\n", GCPtrLogBuf));
        return VERR_NOT_FOUND;
    }
    if (   cbLogBuf < 4096
        || !RT_IS_POWER_OF_TWO(cbLogBuf)
        || cbLogBuf > 16*_1M)
    {
        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf_len' value %#x is not valid.\n", cbLogBuf));
        return VERR_NOT_FOUND;
    }
    uint32_t const cbLogAlign = 4;
    if (   idxFirst > cbLogBuf - sizeof(LNXPRINTKHDR)
        || (idxFirst & (cbLogAlign - 1)) != 0)
    {
        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_first_idx' value %#x is not valid.\n", idxFirst));
        return VERR_NOT_FOUND;
    }
    if (   idxNext > cbLogBuf - sizeof(LNXPRINTKHDR)
        || (idxNext & (cbLogAlign - 1)) != 0)
    {
        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_next_idx' value %#x is not valid.\n", idxNext));
        return VERR_NOT_FOUND;
    }

    /*
     * Read the whole log buffer.
     */
    uint8_t *pbLogBuf = (uint8_t *)RTMemAlloc(cbLogBuf);
    if (!pbLogBuf)
    {
        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Failed to allocate %#x bytes for log buffer\n", cbLogBuf));
        return VERR_NO_MEMORY;
    }
    DBGFADDRESS Addr;
    rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrLogBuf), pbLogBuf, cbLogBuf);
    if (RT_FAILURE(rc))
    {
        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error reading %#x bytes of log buffer at %RGv: %Rrc\n",
             cbLogBuf, Addr.FlatPtr, rc));
        RTMemFree(pbLogBuf);
        return VERR_NOT_FOUND;
    }

    /*
     * Count the messages in the buffer while doing some basic validation.
     */
    uint32_t const cbUsed = idxFirst == idxNext ? cbLogBuf /* could be empty... */
                          : idxFirst < idxNext  ? idxNext - idxFirst : cbLogBuf - idxFirst + idxNext;
    uint32_t cbLeft    = cbUsed;
    uint32_t offCur    = idxFirst;
    uint32_t cLogMsgs  = 0;

    while (cbLeft > 0)
    {
        PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
        if (!pHdr->cbTotal)
        {
            /* Wrap around packet, most likely... */
            if (cbLogBuf - offCur >= cbLeft)
                break;
            offCur = 0;
            pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
        }
        if (RT_UNLIKELY(   pHdr->cbTotal > cbLogBuf - sizeof(*pHdr) - offCur
                        || pHdr->cbTotal > cbLeft
                        || (pHdr->cbTotal & (cbLogAlign - 1)) != 0
                        || pHdr->cbTotal < (uint32_t)pHdr->cbText + (uint32_t)pHdr->cbDict + sizeof(*pHdr) ))
        {
            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Invalid printk_log record at %#x: cbTotal=%#x cbText=%#x cbDict=%#x cbLogBuf=%#x cbLeft=%#x\n",
                 offCur, pHdr->cbTotal, pHdr->cbText, pHdr->cbDict, cbLogBuf, cbLeft));
            rc = VERR_INVALID_STATE;
            break;
        }

        if (pHdr->cbText > 0)
            cLogMsgs++;

        /* next */
        offCur += pHdr->cbTotal;
        cbLeft -= pHdr->cbTotal;
    }
    if (RT_FAILURE(rc))
    {
        RTMemFree(pbLogBuf);
        return rc;
    }

    /*
     * Copy the messages into the output buffer.
     */
    offCur = idxFirst;
    cbLeft = cbUsed;

    /* Skip messages that the caller doesn't want. */
    if (cMessages < cLogMsgs)
    {
        uint32_t cToSkip = cLogMsgs - cMessages;
        while (cToSkip > 0)
        {
            PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
            if (!pHdr->cbTotal)
            {
                offCur = 0;
                pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
            }
            if (pHdr->cbText > 0)
                cToSkip--;

            /* next */
            offCur += pHdr->cbTotal;
            cbLeft -= pHdr->cbTotal;
        }
    }

    /* Now copy the messages. */
    size_t offDst = 0;
    while (cbLeft > 0)
    {
        PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
        if (!pHdr->cbTotal)
        {
            if (cbLogBuf - offCur >= cbLeft)
                break;
            offCur = 0;
            pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
        }

        if (pHdr->cbText > 0)
        {
            char  *pchText = (char *)(pHdr + 1);
            size_t cchText = RTStrNLen(pchText, pHdr->cbText);
            if (offDst + cchText < cbBuf)
            {
                memcpy(&pszBuf[offDst], pHdr + 1, cchText);
                pszBuf[offDst + cchText] = '\n';
            }
            else if (offDst < cbBuf)
                memcpy(&pszBuf[offDst], pHdr + 1, cbBuf - offDst);
            offDst += cchText + 1;
        }

        /* next */
        offCur += pHdr->cbTotal;
        cbLeft -= pHdr->cbTotal;
    }

    /* Done with the buffer. */
    RTMemFree(pbLogBuf);

    /* Make sure we've reserved a char for the terminator. */
    if (!offDst)
        offDst = 1;

    /* Set return size value. */
    if (pcbActual)
        *pcbActual = offDst;

    /*
     * All VBox strings are UTF-8 and bad things may in theory happen if we
     * pass bad UTF-8 to code which assumes it's all valid.  So, we enforce
     * UTF-8 upon the guest kernel messages here even if they (probably) have
     * no defined code set in reality.
     */
    if (offDst <= cbBuf)
    {
        pszBuf[offDst - 1] = '\0';
        RTStrPurgeEncoding(pszBuf);
        return VINF_SUCCESS;
    }

    if (cbBuf)
    {
        pszBuf[cbBuf - 1] = '\0';
        RTStrPurgeEncoding(pszBuf);
    }
    return VERR_BUFFER_OVERFLOW;
}
Exemplo n.º 15
0
/**
 * Calculates the UTF-16 length of a Latin1 string.  In fact this is just the
 * original length, but the function saves us nasty comments to that effect
 * all over the place.
 *
 * @returns IPRT status code.
 * @param   psz     Pointer to the Latin1 string.
 * @param   cch     The max length of the string. (btw cch = cb)
 *                  Use RTSTR_MAX if all of the string is to be examined.s
 * @param   pcwc    Where to store the length of the UTF-16 string as a number of RTUTF16 characters.
 */
static int rtLatin1CalcUtf16Length(const char *psz, size_t cch, size_t *pcwc)
{
    *pcwc = RTStrNLen(psz, cch);
    return VINF_SUCCESS;
}
Exemplo n.º 16
0
/**
 * Decodes a string into a buffer.
 *
 * @returns IPRT status code.
 * @param   pchSrc      The source string.
 * @param   cchSrc      The max number of bytes to decode in the source string.
 * @param   pszDst      The destination buffer.
 * @param   cbDst       The size of the buffer (including terminator).
 */
static int rtUriDecodeIntoBuffer(const char *pchSrc, size_t cchSrc, char *pszDst, size_t cbDst)
{
    AssertPtrReturn(pchSrc, VERR_INVALID_POINTER);
    AssertPtrReturn(pszDst, VERR_INVALID_POINTER);

    /*
     * Knowing that the pszString itself is valid UTF-8, we only have to
     * validate the escape sequences.
     */
    cchSrc = RTStrNLen(pchSrc, cchSrc);
    while (cchSrc > 0)
    {
        const char *pchPct = (const char *)memchr(pchSrc, '%', cchSrc);
        if (pchPct)
        {
            size_t cchBefore = pchPct - pchSrc;
            AssertReturn(cchBefore + 1 < cbDst, VERR_BUFFER_OVERFLOW);
            if (cchBefore)
            {
                memcpy(pszDst, pchSrc, cchBefore);
                pszDst += cchBefore;
                cbDst  -= cchBefore;
                pchSrc += cchBefore;
                cchSrc -= cchBefore;
            }

            char chHigh, chLow;
            if (   cchSrc >= 3
                && RT_C_IS_XDIGIT(chHigh = pchSrc[1])
                && RT_C_IS_XDIGIT(chLow  = pchSrc[2]))
            {
                uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
                b <<= 4;
                b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;
                *pszDst++ = (char)b;
                pchSrc += 3;
                cchSrc -= 3;
            }
            else
            {
                AssertFailed();
                *pszDst++ = *pchSrc++;
                cchSrc--;
            }
            cbDst -= 1;
        }
        else
        {
            AssertReturn(cchSrc < cbDst, VERR_BUFFER_OVERFLOW);
            memcpy(pszDst, pchSrc, cchSrc);
            pszDst += cchSrc;
            cbDst  -= cchSrc;
            pchSrc += cchSrc;
            cchSrc  = 0;
            break;
        }
    }

    AssertReturn(cbDst > 0, VERR_BUFFER_OVERFLOW);
    *pszDst = '\0';
    return VINF_SUCCESS;
}