Checking C code for invalid memory access with Frama-C

戏子无情 提交于 2019-12-11 01:38:06

问题


I am given this C code (the details of the code, including possible bugs, are not very relevant):

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

and I want to throw some formal methods at it to rule out dangerous bugs.

In particular, I would like a assurance that this function does not modify any value besides *ptr and only reads memory from *ptr to end (not inclusive).

It looked like Frama-C is a good framework for such verification, so I started to add annotations:

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

It seems that the Frama-C plugin that checks for invalid memory access is Eva, but running it on these files still prints:

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

Am I just expecting too much of the tool, or is there a way for Frama-C to verify this?

This is Frama-C 19.0 (Potassium).


回答1:


You're on the good track, but an ACSL contract is often not the best way to explain to Eva what the initial state of the analysis should be. Usually, you use a wrapper function for that (see section 6.3 of the Eva manual. In your case, you could for instance go with the following code:

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

Now, as you seem to be interested by the outputs (locations that are assigned) and the inputs (locations whose initial value is read), you need to activate some option from the Inout plugin (see chapter 7 of the Eva manual):

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

will give you:

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

which indeed indicates that only beg (whose address is passed to read_leb128) is modified, and that it gets its values from test[0 .. 2], the content of the array, and itself (since you increment it, its final value obviously depend on its initial value).



来源:https://stackoverflow.com/questions/57114424/checking-c-code-for-invalid-memory-access-with-frama-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!