FORTIFY: vsprintf: запрещена 33-байтовая запись в 32-байтовый буфер - PullRequest
0 голосов
/ 18 апреля 2020

Доброе утро, я использую нативную библиотеку для проекта Android, это просто md5ha sh подписи пакета, но я сталкиваюсь с проблемой на 64-разрядных устройствах с функцией JNI:

char *getSignatureMd5(JNIEnv *env, jobject obj) {
    char *sign = loadSignature(env, obj);
    MD5_CTX context = {0};
    MD5Init(&context);
    MD5Update(&context, (unsigned char *) sign, strlen(sign));
    unsigned char dest[16] = {0};
    MD5Final(dest, &context);
    int i;
    static char destination[32] = {0};
    for (i = 0; i < 16; i++) {
        sprintf(destination, "%s%02x", destination, dest[i]);
    }
    LOGD("MD5 Chacksum : %s", destination);
    return destination;
}

Я использую его с годами, поэтому в самом коде ничего не изменилось, но я думаю, что обновление NDK или Cmake вызывает это :-( Это отчет Cra sh, который я получаю:

2020-04-18 08:38:13.038 5621-5621/? A/DEBUG: Revision: '10'
2020-04-18 08:38:13.038 5621-5621/? A/DEBUG: ABI: 'arm64'
2020-04-18 08:38:13.038 5621-5621/? A/DEBUG: pid: 5187, tid: 5423, name: APP-AsyncTa  >>> com.pecana.app <<<
2020-04-18 08:38:13.038 5621-5621/? A/DEBUG: signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
2020-04-18 08:38:13.040 5621-5621/? A/DEBUG: Abort message: 'FORTIFY: vsprintf: prevented 33-byte write into 32-byte buffer'
2020-04-18 08:38:13.040 5621-5621/? A/DEBUG:     x0  0000000000000000  x1  000000000000152f  x2  0000000000000006  x3  0000000000000008
2020-04-18 08:38:13.040 5621-5621/? A/DEBUG:     x4  0000000000000000  x5  0000000000000000  x6  0000000000000000  x7  0000000000000038
2020-04-18 08:38:13.040 5621-5621/? A/DEBUG:     x8  0000000000000083  x9  0000007007fb9878  x10 fffffff87ffffbdf  x11 0000000000000001
2020-04-18 08:38:13.041 5621-5621/? A/DEBUG:     x12 0000000000000030  x13 000000005e9aa050  x14 001fb5a729ce1580  x15 000040d9dceb878c
2020-04-18 08:38:13.042 5621-5621/? A/DEBUG:     x16 0000007007ff02a0  x17 0000007007f2f920  x18 0000000000000000  x19 0000000000001443
2020-04-18 08:38:13.042 5621-5621/? A/DEBUG:     x20 000000000000152f  x21 0000000000000083  x22 000000000000000f  x23 0000006f6a48dcc2
2020-04-18 08:38:13.043 5621-5621/? A/DEBUG:     x24 0000000000000004  x25 0000006f5c0f5588  x26 0000006f6b0a04a0  x27 0000000000000001
2020-04-18 08:38:13.043 5621-5621/? A/DEBUG:     x28 0000006f5c0f30c0  x29 0000006f5c0f2c00
2020-04-18 08:38:13.044 5621-5621/? A/DEBUG:     sp  0000006f5c0f2bc0  lr  0000007007f22d68  pc  0000007007f22d94

Что я могу сделать, чтобы это исправить?

Спасибо!

1 Ответ

1 голос
/ 18 апреля 2020
    static char destination[33] = {0};  // add one more byte for null-terminator
    char* dstptr = destination;         // pointer to first char of the static buffer
    for (i = 0; i < 16; i++) {
        sprintf(dstptr, "%02x", dest[i]&0xFF);  // overwrite two chars in buffer
        dstptr += 2;                    // advance pointer
    }

Таким образом, он будет каждый раз перезаписывать 32 символа, не заботясь о старом контенте.

Имейте в виду, что это похоже на некоторую функцию поддержки для кода Android, что если два потока вызывают его одновременно для получения результата используется один и тот же буфер stati c, поэтому вы можете получить поврежденный ответ в обоих ответах (частичный ответ за один вызов смешивается с частью второго). Так что это не потокобезопасно.

Плюс следующий вызов функции сделает недействительной предыдущую версию (если вы сохраняете только указатель на результат и не скопировали его в Java String).

Я бы, вероятно, предложил вместо этого возвращать только что инстанцированную jstring для непосредственного использования верхним Android кодом (плюс это может быть возможно потокобезопасно, потому что все другие экземпляры в вашем коде являются локальными переменными, только destination is stati c, поэтому, если сами функции MD5 поточно-ориентированы и вы избавитесь от destination, вы сделаете всю функцию поточно-безопасной). Не добавляя исходный пример этого, потому что JNI, как правило, ужасная боль для меня, убивая все хорошее в C ++ и пропагандируя все плохое в нем, очень склонный к ошибкам и потерям типов, et c ... (мой личный токси c предвзятость - игнорируйте, если вы не заинтересованы в разговоре sh, - что он был специально разработан таким образом, чтобы избежать слишком большого использования C / C ++ вместе с Java, но опять же, это было сделано так много лет назад, до C ++ 11, так что, может быть, люди, разрабатывающие Java, были не в курсе ... на самом деле это имеет больше смысла, учитывая весь язык Java)

...