簡體   English   中英

使用 Frama-C 檢查 C 代碼的無效內存訪問

[英]Checking C code for invalid memory access with Frama-C

我得到了這個 C 代碼(代碼的細節,包括可能的錯誤,不是很相關):

int read_leb128(char **ptr, char *end) {
  int r = 0;
  int s = 0;
  char b;
  do {
    if ((intptr_t)*ptr >= (intptr_t)end) (exit(1));
    b = *(*ptr)++;
    r += (b & (char)0x7f) << s;
    s += 7;
  } while (b & (char)0x80);
  return r;
}

我想用一些正式的方法來排除危險的錯誤。

特別是,我想保證這個函數不會修改除*ptr之外的任何值,並且只從*ptr讀取內存到end (不包括)。

看起來Frama-C是一個很好的驗證框架,所以我開始添加注釋:

/*@
  requires \valid(ptr);
  requires \valid_read((*ptr) + (0 .. (end-*ptr)));
  assigns *ptr;
 */

似乎檢查無效內存訪問的 Frama-C 插件是Eva ,但在這些文件上運行它仍然打印:

[eva:alarm] foo.c:33: Warning: 
  out of bounds read. assert \valid_read(tmp);
                      (tmp from *ptr++)

我只是對這個工具期待太多,還是有辦法讓 Frama-C 驗證這一點?

這是 Frama-C 19.0(鉀)。

您的工作進展順利,但是 ACSL 合同通常不是向 Eva 解釋分析的初始狀態應該是什么的最佳方式。 通常,您為此使用包裝函數(請參閱Eva 手冊的第 6.3 節。在您的情況下,您可以使用以下代碼:

#include <stdint.h>
#include <stdlib.h>

/*@
  requires \valid(ptr);
  requires \valid_read((*ptr) + (0 .. (end-*ptr)));
  assigns *ptr;
 */
int read_leb128(char **ptr, char *end) {
  int r = 0;
  int s = 0;
  char b;
  do {
    if ((intptr_t)*ptr >= (intptr_t)end) (exit(1));
    b = *(*ptr)++;
    r += (b & (char)0x7f) << s;
    s += 7;
  } while (b & (char)0x80);
  return r;
}

#define N 4

char test[N];

int main() {
char* beg = &test[0];
char* end = &test[0] + (N-1);
read_leb128(&beg, end);
}

現在,由於您似乎對輸出(分配的位置)和輸入(讀取初始值的位置)感興趣,您需要激活 Inout 插件中的某些選項(請參閱Eva 手冊的第 7 章):

frama-c -eva -eva-slevel 20 res.c -lib-entry -out-external -input

會給你:

...
[inout] Out (external) for function read_leb128:
    beg
[inout] Inputs for function read_leb128:
    test[0..2]; beg

這確實表明只有beg (其地址被傳遞給read_leb128 )被修改,並且它從test[0 .. 2] 、數組的內容和本身獲取它的值(因為你增加了它,它的最終值顯然是取決於它的初始值)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM