New pointer (by malloc) is same as one of the free

2019-06-21 06:15发布

I am trying to track use-after-free errors in C. And my question is that, if I have the code like this:

A * ptrA = malloc(sizeof(A));
A * aliasA = ptrA;
// do something ' 
free(ptrA) 
// some other code
B * ptrB = malloc(sizeof(B)); // assume this return same pointer as ptrA
//trying to use aliasA here

Just wondering if the use of aliasA is a UAF error? If it is, what is going wrong here?

To clear the question, I think it is better to add a small example:

int main(){
    int *ptr = (int *)malloc(4);
    *ptr = 5;
    int *ptr2 = ptr;
    printf("%d\n", *ptr);
    free(ptr);

    int *new_ptr = malloc(4);
    *new_ptr = 66;
    printf("%d\n", *ptr2);

    return 0;
}  

And the output is:

5
66

(I checked ptr and new_ptr in S2E: http://s2e.systems/ and these two pointers actually point to the same address. After freeing ptr, the same address is allocated to new_ptr.)

From the output above, it seems like the use of ptr2 gives the same output as new_ptr.

When I wrote my solution to detect UAF error, I record the information of pointers. The pointers' values are stored as uint64_t and a boolean type flag is to declare whether the pointer is alive.

Therefore, I guess a problem occurs when the new_ptr and ptr point to same address because once malloc() is called the flag for new_ptr will turn true. After that, when I use ptr, I can not detect this UAF error because this address is marked alive.

Thanks in advance!

3条回答
乱世女痞
2楼-- · 2019-06-21 06:18

The aliasA is UAF error, it may hold the same value as ptrA but it's not guaranteed and it's recommended to re-assign the freed pointer (both aliasA and ptrA) to NULL to avoid dangling pointer.

In your case, it's better to assign NULL after you free:

free(ptrA);
free(aliasA);
ptrA = NULL;
aliasA = NULL;
查看更多
够拽才男人
3楼-- · 2019-06-21 06:27

If you don't dereference the pointer aliasA, it depends on the definition of "use after free" whether this constitutes "use after free". For example CWE-416 doesn't talk about just using the pointer value, but about dereferencing it, i.e. using the object that was freed.

However, the C standard says that even using the pointer value has undefined behaviour (Appendix J.2):

  1. The behavior is undefined in the following circumstances:

    [...]

    • The value of a pointer that refers to space deallocated by a call to the free or realloc function is used (7.22.3).

This is because the value of the pointer becomes indeterminate:

The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

Therefore the following code has undefined behaviour:

A *ptrA = malloc(sizeof(A));
A *aliasA = ptrA;
free(ptrA);
A *ptrB = malloc(sizeof(A));

if (aliasA == ptrB) { // undefined behaviour, as it might be a trap
    printf("We were given the same pointer");
}

The comparison there is meaningless and the compiler is given the freedom to do whatever it pleases with its optimization, as aliasA doesn't need to contain a valid value any more. It is totally OK for a compiler to even to set a trap into aliasA which would cause your program to abort at the if statement with a diagnostics message. Or it can be that these could seem to point to the same address even though they were given distinct addresses of memory, or vice versa.

查看更多
一纸荒年 Trace。
4楼-- · 2019-06-21 06:45

This is a UAF error.

In practice, it is very unlikely that the second malloc() call returns the same address as aliasA, as the behavior is not guaranteed. You should not rely on it.

You may ask: Can I compare them to make sure they have the same address? Well, no. Comparing may make some sense to you, but it is undefined behavior, because pointer equality comparison is valid only if the two pointers point to different elements in the same array. In this case the two allocated blocks surely aren't the same array, so comparison between those pointers isn't well-defined.

At last, you shouldn't rely on the address returned by malloc(). All you can do is use it within the amount of memory requested when calling.

In practice, Thiru Shetty's answer is a good way to pursue.

查看更多
登录 后发表回答