* Memory error check routine: * - loc = static instruction address. * - base = memory operand base pointer. * - access = actual address that is accessed. * - sz = the size of the memory access. * - _asm = the ASM string of the instruction. */
| 144 | * - _asm = the ASM string of the instruction. |
| 145 | */ |
| 146 | void check(const void *loc, const void *base, const void *access, size_t sz, |
| 147 | const char *_asm) |
| 148 | { |
| 149 | /* |
| 150 | * Step (1): Find the base of the allocation, which has the following |
| 151 | * layout (as guaranteed by libredfat.so): |
| 152 | * |
| 153 | * +----+--------------+ |
| 154 | * | Sz | Object | |
| 155 | * +----+--------------+ |
| 156 | * Allocation |
| 157 | * |
| 158 | * The allocation base stores the object size metadata (Sz) |
| 159 | * which is prepended to the start of the object. The meta |
| 160 | * region also serves as an inaccessible redzone between |
| 161 | * objects. |
| 162 | */ |
| 163 | const size_t *meta = (size_t *)redfat_base(base, access); |
| 164 | if (meta == NULL) |
| 165 | return; // Not a RedFat pointer |
| 166 | |
| 167 | /* |
| 168 | * Step (2): Do the bounds check. Note that "free" objects will have a |
| 169 | * size==0, so will always fail the bounds check. |
| 170 | */ |
| 171 | size_t size = *meta; |
| 172 | const uint8_t *lb = (uint8_t *)meta + REDZONE; |
| 173 | const uint8_t *ub = lb + size; |
| 174 | const uint8_t *access8 = (uint8_t *)access; |
| 175 | if (access8 >= lb && access8 + sz <= ub && size < redfat_size(access)) |
| 176 | return; // Valid memory access |
| 177 | |
| 178 | /* |
| 179 | * Step (3): A memory error has been detected. Gather useful information |
| 180 | * and print the error to stderr, then abort. |
| 181 | */ |
| 182 | const uint8_t *access_base = (uint8_t *)redfat_base(access, access); |
| 183 | size_t access_size = *(size_t *)access_base; |
| 184 | bool access_free = (access_size == 0x0); |
| 185 | access_size = (access_free? redfat_size(access): access_size); |
| 186 | const uint8_t *access_lb = access_base + REDZONE; |
| 187 | const uint8_t *access_ub = access_lb + access_size; |
| 188 | |
| 189 | const uint8_t *base_base = (uint8_t *)redfat_base(base, access); |
| 190 | size_t base_size = *(size_t *)base_base; |
| 191 | bool base_free = (base_size == 0x0); |
| 192 | base_size = (base_free? redfat_size(base): base_size); |
| 193 | const uint8_t *base_lb = base_base + REDZONE; |
| 194 | const uint8_t *base_ub = base_lb + base_size; |
| 195 | |
| 196 | const char *kind = "out-of-bounds"; |
| 197 | if (access_free && base_free) |
| 198 | kind = "use-after-free"; |
| 199 | else if (size > redfat_size(access)) |
| 200 | kind = "size-metadata-corruption"; |
| 201 | |
| 202 | const uint8_t *base8 = (uint8_t *)base; |
| 203 | fprintf(stderr, "%sMEMORY ERROR%s: %s error detected!\n" |
nothing calls this directly
no test coverage detected