cfi.c 21.5 KB
Newer Older
D
dhy308 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

D
dhy308 已提交
16 17 18 19 20 21 22 23 24
#define _GNU_SOURCE
#include <sys/mman.h>
#include <sys/prctl.h>
#include "cfi.h"
#include "ld_log.h"
#include "namespace.h"

/* This module provides support for LLVM CFI Cross-DSO by implementing the __cfi_slowpath() and __cfi_slowpath_diag()
 * functions. These two functions will be called before visiting other dso's resources. The responsibility is to
D
dhy308 已提交
25 26 27 28 29 30 31 32 33 34 35 36
 * calculate the __cfi_check() of the target dso, and call it. So use CFI shadow and shadow value to store the
 * relationship between dso and its __cfi_check addr while loading a dso. CFI shadow is an array which stores shadow
 * values. Shadow value is used to store the relationship. A shadow value can map 1 LIBRARY_ALIGNMENT memory range. So
 * each dso will be mapped to one or more shadow values in the CFI shadow, this depends on the address range of the
 * dso.
 * There are 3 types for shadow value:
 * - invalid(0) : the target addr does not belongs to any loaded dso.
 * - uncheck(1) : this LIBRARY_ALIGNMENT memory range belongs to a dso but it is no need to do the CFI check.
 * - valid(2 - 0xFFFF) : this LIBRARY_ALIGNMENT memory range belongs to a dso and need to do the CFI check.
 * The valid shadow value records the distance from the end of a LIBRARY_ALIGNMENT memory range to the __cfi_check addr
 * of the dso (The unit is 4096, because the __cfi_check is aligned with 4096).
 * The valid shadow value is calculated as below:
D
dhy308 已提交
37
 *      sv = (AlignUp(__cfi_check, LIBRARY_ALIGNMENT) - __cfi_check + N * LIBRARY_ALIGNMENT) / 4096 + 2;
D
dhy308 已提交
38 39 40 41 42 43 44 45 46 47 48 49
 *
 *      N   : starts at 0, is the index of LIBRARY_ALIGNMENT memory range that belongs to a dso.
 *      + 2 : to avoid conflict with invalid and uncheck shadow value.
 * 
 * Below is a example for calculating shadow values of a dso.
 *                                               liba.so
 *                                                /\
 *           /''''''''''''''''''''''''''''''''''''  '''''''''''''''''''''''''''''''''''''\
 *           0x40000  __cfi_check addr = 0x42000               0x80000                  0xA0000                0xC0000
 *           +---------^----------------------------------------^-------------------------^-------------------------+
 *  Memory   |         |                                        |                         |                         |
 *           +------------------------------------------------------------------------------------------------------+
50
 *           \........... LIBRARY_ALIGNMENT ..................../\........... LIBRARY_ALIGNMENT ..................../
D
dhy308 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
 *             \                                              /                                               /
 *               \                                          /                                          /
 *                 \                                      /                                     /
 *                   \                                  /                                /
 *                     \                              /                            /
 *            +-----------------------------------------------------------------------------------------------------+
 * CFI shadow |  invalid |           sv1              |           sv2              |            invalid             |
 *            +-----------------------------------------------------------------------------------------------------+
 *                          sv1 = (0x80000 - 0x42000 + 0 * LIBRARY_ALIGNMENT) / 4096 + 2 = 64
 *                          sv2 = (0x80000 - 0x42000 + 1 * LIBRARY_ALIGNMENT) / 4096 + 2 = 126
 * 
 * Calculating the __cfi_check address is a reverse process:
 * - First align up the target addr with LIBRARY_ALIGNMENT to locate the corresponding shadow value.
 * - Then calculate the __cfi_check addr.
 * 
D
dhy308 已提交
66
 * In order for the algorithm to work well, the start addr of each dso should be aligned with LIBRARY_ALIGNMENT. */
D
dhy308 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

#define MAX(a,b)                (((a) > (b)) ? (a) : (b))
#define MIN(a,b)                (((a) < (b)) ? (a) : (b))
#define ALIGN_UP(a, b)          (((a) + (b) - 1) & -(b))
#define ALIGN_DOWN(a, b)        ((a) & -(b))
#if DL_FDPIC
#define LADDR(p, v)             laddr((p), (v))
#else
#define LADDR(p, v)             (void *)((p)->base + (v))
#endif

/* Function ptr for __cfi_check() */
typedef int (*cfi_check_t)(uint64_t, void *, void *);

static const uintptr_t shadow_granularity = LIBRARY_ALIGNMENT_BITS;
static const uintptr_t cfi_check_granularity = 12;
static const uintptr_t shadow_alignment = 1UL << shadow_granularity;
static uintptr_t shadow_size = 0;
/* Start addr of the CFI shadow */
static char *cfi_shadow_start = NULL;
/* List head of all the DSOs loaded by the process */
static struct dso *dso_list_head = NULL;
D
dhy308 已提交
89
static struct dso *pldso = NULL;
D
dhy308 已提交
90 91

/* Shadow value */
D
dhy308 已提交
92 93
/* The related shadow value(s) will be set to `sv_invalid` when:
 * - init CFI shadow.
D
dhy308 已提交
94
 * - removing a dso. */
D
dhy308 已提交
95
static const uint16_t sv_invalid = 0;
D
dhy308 已提交
96 97 98
/* The related shadow value(s) will be set to `sv_uncheck` if:
 * - the DSO does not enable CFI Cross-Dso.
 * - the DSO enabled CFI Cross-Dso, but this DSO is larger than 16G, for the part of the dso that exceeds 16G,
D
dhy308 已提交
99
 *   its shadow value will be set to `sv_uncheck`. */
D
dhy308 已提交
100
static const uint16_t sv_uncheck = 1;
D
dhy308 已提交
101
/* If a DSO enabled CFI Cross-Dso, the DSO's shadow value should be valid. Because of the defination of `sv_invalid`
D
dhy308 已提交
102
 * and `sv_unchecked`, the valid shadow value should be at least 2. */
D
dhy308 已提交
103 104 105 106 107 108 109 110 111
static const uint16_t sv_valid_min = 2;

#if defined(__LP64__)
static const uintptr_t max_target_addr = 0xffffffffffff;
#else
static const uintptr_t max_target_addr = 0xffffffff;
#endif

/* Create a cfi shadow */
D
dhy308 已提交
112
static int create_cfi_shadow(void);
D
dhy308 已提交
113 114

/* Map dsos to CFI shadow */
D
dhy308 已提交
115 116
static int add_dso_to_cfi_shadow(struct dso *dso);
static int fill_shadow_value_to_shadow(uintptr_t begin, uintptr_t end, uintptr_t cfi_check, uint16_t type);
D
dhy308 已提交
117 118 119 120 121 122 123 124

/* Find the __cfi_check() of target dso and call it */
void __cfi_slowpath(uint64_t call_site_type_id, void *func_ptr);
void __cfi_slowpath_diag(uint64_t call_site_type_id, void *func_ptr, void *diag_data);

static inline uintptr_t addr_to_offset(uintptr_t addr, int bits)
{
    /* Convert addr to CFI shadow offset.
D
dhy308 已提交
125
     * Shift left 1 bit because the shadow value is uint16_t. */
D
dhy308 已提交
126 127 128 129 130
    return (addr >> bits) << 1;
}

static struct symdef find_cfi_check_sym(struct dso *p)
{
D
dhy308 已提交
131
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
132

D
dhy308 已提交
133
    struct verinfo verinfo = { .s = "__cfi_check", .v = "", .use_vna_hash = false };
D
dhy308 已提交
134 135
    struct sym_info_pair s_info_p = gnu_hash(verinfo.s);
    return find_sym_impl(p, &verinfo, s_info_p, 0, p->namespace);
D
dhy308 已提交
136 137
}

D
dhy308 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
static int is_addr_in_ldso(size_t a)
{
    size_t i = 0;
    if (DL_FDPIC) {
        i = count_syms(pldso);
        if (a - (size_t)pldso->funcdescs < i * sizeof(*pldso->funcdescs))
            return 1;
    }
    if (DL_FDPIC && pldso->loadmap) {
        for (i = 0; i < pldso->loadmap->nsegs; i++) {
            if (a-pldso->loadmap->segs[i].p_vaddr
                < pldso->loadmap->segs[i].p_memsz)
                return 1;
        }
    } else {
        Phdr *ph = pldso->phdr;
        size_t phcnt = pldso->phnum;
        size_t entsz = pldso->phentsize;
        size_t base = (size_t)pldso->base;
        for (; phcnt--; ph = (void *)((char *)ph + entsz)) {
            if (ph->p_type != PT_LOAD) continue;
            if (a - base - ph->p_vaddr < ph->p_memsz)
                return 1;
        }
        if (a - (size_t)pldso->map < pldso->map_len)
            return 0;
    }
    return 0;
}

D
dhy308 已提交
168 169
static uintptr_t get_cfi_check_addr(uint16_t value, void* func_ptr)
{
D
dhy308 已提交
170
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
171 172 173 174 175

    uintptr_t addr = (uintptr_t)func_ptr;
    uintptr_t aligned_addr = ALIGN_DOWN(addr, shadow_alignment) + shadow_alignment;
    uintptr_t cfi_check_func_addr = aligned_addr - ((uintptr_t)(value - sv_valid_min) << cfi_check_granularity);
#ifdef __arm__
D
dhy308 已提交
176
    LD_LOGD("[CFI] [%{public}s] __arm__ defined!\n", __FUNCTION__);
D
dhy308 已提交
177 178
    cfi_check_func_addr++;
#endif
D
dhy308 已提交
179 180 181
    LD_LOGD("[CFI] [%{public}s] cfi_check_func_addr[%{public}p] in dso[%{public}s]\n",
            __FUNCTION__, cfi_check_func_addr, ((struct dso *)addr2dso((size_t)cfi_check_func_addr))->name);

D
dhy308 已提交
182 183 184
    return cfi_check_func_addr;
}

185
static inline void cfi_slowpath_common(uint64_t call_site_type_id, void *func_ptr, void *diag_data)
D
dhy308 已提交
186 187 188
{
    uint16_t value = sv_invalid;

189 190 191 192
    if (func_ptr == NULL) {
        return;
    }

D
dhy308 已提交
193
#if defined(__aarch64__)
D
dhy308 已提交
194
    LD_LOGD("[CFI] [%{public}s] __aarch64__ defined!\n", __FUNCTION__);
D
dhy308 已提交
195 196
    uintptr_t addr = (uintptr_t)func_ptr & ((1ULL << 56) - 1);
#else
D
dhy308 已提交
197
    LD_LOGD("[CFI] [%{public}s] __aarch64__ not defined!\n", __FUNCTION__);
D
dhy308 已提交
198 199 200 201 202
    uintptr_t addr = func_ptr;
#endif

    /* Get shadow value */
    uintptr_t offset = addr_to_offset(addr, shadow_granularity);
D
dhy308 已提交
203 204

    if (cfi_shadow_start == NULL) {
D
dhy308 已提交
205
        LD_LOGE("[CFI] [%{public}s] the cfi_shadow_start is null!\n", __FUNCTION__);
D
dhy308 已提交
206 207 208
        __builtin_trap();
    }

D
dhy308 已提交
209 210 211 212 213
    if (offset > shadow_size) {
        value = sv_invalid;
    } else {
        value = *((uint16_t*)(cfi_shadow_start + offset));
    }
Y
yinchuang 已提交
214 215 216 217 218
    LD_LOGD("[CFI] [%{public}s] called from %{public}s to %{public}s func_ptr:0x%{public}p shadow value:%{public}d diag_data:0x%{public}p call_site_type_id[%{public}p.\n",
             __FUNCTION__,
             ((struct dso *)addr2dso((size_t)__builtin_return_address(0)))->name,
             ((struct dso *)addr2dso((size_t)func_ptr))->name,
             func_ptr, value, diag_data, call_site_type_id);
D
dhy308 已提交
219 220 221 222 223

    struct dso *dso = NULL;
    switch (value)
    {
    case sv_invalid:
D
dhy308 已提交
224 225 226 227 228 229 230
        /* The ldso is an exception because it is loaded by kernel and is not mapped to the CFI shadow.
         * Do not check it. */
        if (is_addr_in_ldso((size_t)func_ptr)) {
            LD_LOGI("[CFI] [%{public}s] uncheck for ldso\n", __FUNCTION__);
            return;
        }

D
dhy308 已提交
231 232
        dso = (struct dso *)addr2dso((size_t)__builtin_return_address(0));
        if (dso == NULL) {
D
dhy308 已提交
233
            LD_LOGE("[CFI] [%{public}s] can not find the dso!\n", __FUNCTION__);
D
dhy308 已提交
234 235
            __builtin_trap();
        }
Y
yinchuang 已提交
236
        LD_LOGD("[CFI] [%{public}s] dso name[%{public}s]!\n", __FUNCTION__, dso->name);
237

D
dhy308 已提交
238 239
        struct symdef cfi_check_sym = find_cfi_check_sym(dso);
        if (!cfi_check_sym.sym) {
D
dhy308 已提交
240
            LD_LOGE("[CFI] [%{public}s] can not find the __cfi_check in the dso!\n", __FUNCTION__);
D
dhy308 已提交
241 242
            __builtin_trap();
        }
D
dhy308 已提交
243
        LD_LOGD("[CFI] [%{public}s] cfi_check addr[%{public}p]!\n", __FUNCTION__,
244
                LADDR(cfi_check_sym.dso, cfi_check_sym.sym->st_value));
D
dhy308 已提交
245 246 247 248 249 250 251 252 253 254 255 256
        ((cfi_check_t)LADDR(cfi_check_sym.dso, cfi_check_sym.sym->st_value))(call_site_type_id, func_ptr, diag_data);
        break;
    case sv_uncheck:
        break;
    default:
        ((cfi_check_t)get_cfi_check_addr(value, func_ptr))(call_site_type_id, func_ptr, diag_data);
        break;
    }

    return;
}

D
dhy308 已提交
257
int init_cfi_shadow(struct dso *dso_list, struct dso *ldso)
D
dhy308 已提交
258
{
Y
yinchuang 已提交
259
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
260 261

    if (dso_list == NULL) {
D
dhy308 已提交
262
        LD_LOGW("[CFI] [%{public}s] has null param!\n", __FUNCTION__);
D
dhy308 已提交
263
        return CFI_SUCCESS;
D
dhy308 已提交
264 265 266 267
    }

    /* Save the head node of dso list */
    dso_list_head = dso_list;
D
dhy308 已提交
268
    pldso = ldso;
D
dhy308 已提交
269 270 271 272

    return map_dso_to_cfi_shadow(dso_list);
}

D
dhy308 已提交
273
int map_dso_to_cfi_shadow(struct dso *dso)
D
dhy308 已提交
274 275 276 277
{
    bool has_cfi_check = false;

    if (dso == NULL) {
D
dhy308 已提交
278
        LD_LOGW("[CFI] [%{public}s] has null param!\n", __FUNCTION__);
D
dhy308 已提交
279
        return CFI_SUCCESS;
D
dhy308 已提交
280 281 282 283
    }

    /* If the cfi shadow does not exist, create it and map all the dsos and its dependents to it. */
    if (cfi_shadow_start == NULL) {
D
dhy308 已提交
284 285 286
        /* Find __cfi_check symbol in dso list */
        for (struct dso *p = dso; p; p = p->next) {
            if (find_cfi_check_sym(p).sym) {
Y
yinchuang 已提交
287
                LD_LOGD("[CFI] [%{public}s] find __cfi_check function in dso %{public}s!\n", __FUNCTION__, p->name);
D
dhy308 已提交
288 289 290 291 292
                has_cfi_check = true;
                break;
            }
        }

D
dhy308 已提交
293
        if (has_cfi_check) {
D
dhy308 已提交
294
            if (create_cfi_shadow() == CFI_FAILED) {
D
dhy308 已提交
295
                LD_LOGE("[CFI] [%{public}s] create cfi shadow failed!\n", __FUNCTION__);
D
dhy308 已提交
296
                return CFI_FAILED;
D
dhy308 已提交
297 298
            }
            add_dso_to_cfi_shadow(dso_list_head);
D
dhy308 已提交
299
            prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, cfi_shadow_start, shadow_size, "cfi_shadow:musl");
D
dhy308 已提交
300 301 302 303
        }
    /* If the cfi shadow exists, map the current dso and its dependents to it. */
    } else {
        add_dso_to_cfi_shadow(dso);
D
dhy308 已提交
304
        prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, cfi_shadow_start, shadow_size, "cfi_shadow:musl");
D
dhy308 已提交
305 306
    }

D
dhy308 已提交
307
    return CFI_SUCCESS;
D
dhy308 已提交
308 309 310 311 312
}

void unmap_dso_from_cfi_shadow(struct dso *dso)
{
    if (dso == NULL) {
Y
yinchuang 已提交
313
        LD_LOGD("[CFI] [%{public}s] has null param!\n", __FUNCTION__);
D
dhy308 已提交
314 315 316
        return;
    }

Y
yinchuang 已提交
317
    LD_LOGD("[CFI] [%{public}s] unmap dso %{public}s from shadow!\n", __FUNCTION__, dso->name);
D
dhy308 已提交
318 319 320 321 322 323 324

    if (cfi_shadow_start == NULL)
        return;

    if (dso->map == 0 || dso->map_len == 0)
        return;

D
dhy308 已提交
325 326 327
    if (dso->is_mapped_to_shadow == false)
        return;

D
dhy308 已提交
328 329
    /* Set the dso's shadow value as invalid. */
    fill_shadow_value_to_shadow(dso->map, dso->map + dso->map_len, 0, sv_invalid);
D
dhy308 已提交
330 331
    dso->is_mapped_to_shadow = false;
    prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, cfi_shadow_start, shadow_size, "cfi_shadow:musl");
D
dhy308 已提交
332 333 334 335

    return;
}

D
dhy308 已提交
336
static int create_cfi_shadow(void)
D
dhy308 已提交
337
{
D
dhy308 已提交
338
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
339 340

    /* Each process can load up to (max_target_addr >> shadow_granularity) dsos. Shift left 1 bit because the shadow 
D
dhy308 已提交
341
     * value is uint16_t. The size passed to mmap() should be aligned with 4096, so shadow_size should be aligned. */
D
dhy308 已提交
342 343 344 345 346
    shadow_size = ALIGN_UP(((max_target_addr >> shadow_granularity) << 1), PAGE_SIZE);

    uintptr_t *mmap_addr = mmap(NULL, shadow_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);

    if (mmap_addr == MAP_FAILED) {
D
dhy308 已提交
347
        LD_LOGE("[CFI] [%{public}s] mmap failed!\n", __FUNCTION__);
D
dhy308 已提交
348
        return CFI_FAILED;
D
dhy308 已提交
349 350 351
    }

    cfi_shadow_start = (char*)mmap_addr;
Y
yinchuang 已提交
352
    LD_LOGD("[CFI] [%{public}s] the cfi_shadow_start addr is %{public}p!\n", __FUNCTION__, cfi_shadow_start);
D
dhy308 已提交
353

D
dhy308 已提交
354
    return CFI_SUCCESS;
D
dhy308 已提交
355 356
}

D
dhy308 已提交
357
static int add_dso_to_cfi_shadow(struct dso *dso)
D
dhy308 已提交
358
{
Y
yinchuang 已提交
359
    LD_LOGD("[CFI] [%{public}s] start with %{public}s !\n", __FUNCTION__, dso->name);
D
dhy308 已提交
360
    for (struct dso *p = dso; p; p = p->next) {
Y
yinchuang 已提交
361
        LD_LOGD("[CFI] [%{public}s] adding %{public}s to cfi shadow!\n", __FUNCTION__, p->name);
D
dhy308 已提交
362
        if (p->map == 0 || p->map_len == 0) {
D
dhy308 已提交
363
            LD_LOGW("[CFI] [%{public}s] the dso has no data! map[%{public}p] map_len[0x%{public}x]\n",
364
                    __FUNCTION__, p->map, p->map_len);
D
dhy308 已提交
365 366 367 368
            continue;
        }

        if (p->is_mapped_to_shadow == true) {
Y
yinchuang 已提交
369
            LD_LOGW("[CFI] [%{public}s] %{public}s is already in shadow!\n", __FUNCTION__, p->name);
D
dhy308 已提交
370 371 372 373 374 375
            continue;
        }

        struct symdef cfi_check_sym = find_cfi_check_sym(p);
        /* If the dso doesn't have __cfi_check(), set it's shadow value unchecked. */
        if (!cfi_check_sym.sym) {
Y
yinchuang 已提交
376
            LD_LOGD("[CFI] [%{public}s] %{public}s has no __cfi_check()!\n", __FUNCTION__, p->name);
D
dhy308 已提交
377
            if (fill_shadow_value_to_shadow(p->map, p->map + p->map_len, 0, sv_uncheck) == CFI_FAILED) {
D
dhy308 已提交
378
                LD_LOGE("[CFI] [%{public}s] add dso to cfi shadow failed!\n", __FUNCTION__);
D
dhy308 已提交
379
                return CFI_FAILED;
D
dhy308 已提交
380 381 382
            }
        /* If the dso has __cfi_check(), set it's shadow value valid. */
        } else {
Y
yinchuang 已提交
383
            LD_LOGD("[CFI] [%{public}s] %{public}s has __cfi_check()!\n", __FUNCTION__, p->name);
D
dhy308 已提交
384 385 386 387
            uintptr_t end = p->map + p->map_len;
            uintptr_t cfi_check = LADDR(cfi_check_sym.dso, cfi_check_sym.sym->st_value);

            if (cfi_check == 0) {
Y
yinchuang 已提交
388
                LD_LOGE("[CFI] [%{public}s] %{public}s has null cfi_check func!\n", __FUNCTION__, p->name);
D
dhy308 已提交
389
                return CFI_FAILED;
D
dhy308 已提交
390
            }
D
dhy308 已提交
391
            if (fill_shadow_value_to_shadow(p->map, end, cfi_check, sv_valid_min) == CFI_FAILED) {
Y
yinchuang 已提交
392
                LD_LOGE("[CFI] [%{public}s] add %{public}s to cfi shadow failed!\n", __FUNCTION__, p->name);
D
dhy308 已提交
393
                return CFI_FAILED;
D
dhy308 已提交
394 395
            }
        }
D
dhy308 已提交
396
        p->is_mapped_to_shadow = true;
Y
yinchuang 已提交
397
        LD_LOGD("[CFI] [%{public}s] add %{public}s to cfi shadow succeed.\n", __FUNCTION__, p->name);
D
dhy308 已提交
398
    }
Y
yinchuang 已提交
399
    LD_LOGD("[CFI] [%{public}s] %{public}s done.\n", __FUNCTION__, dso->name);
D
dhy308 已提交
400

D
dhy308 已提交
401
    return CFI_SUCCESS;
D
dhy308 已提交
402 403
}

D
dhy308 已提交
404
static int fill_shadow_value_to_shadow(uintptr_t begin, uintptr_t end, uintptr_t cfi_check, uint16_t type)
D
dhy308 已提交
405
{
Y
yinchuang 已提交
406
    LD_LOGD("[CFI] [%{public}s] begin[%{public}x] end[%{public}x] cfi_check[%{public}x] type[%{public}x]!\n",
407
            __FUNCTION__, begin, end, cfi_check, type);
D
dhy308 已提交
408 409

    /* To ensure the atomicity of the CFI shadow operation, we create a temp_shadow, write the shadow value to 
D
dhy308 已提交
410
     * the temp_shadow, and then write it back to the CFI shadow by mremap(). */
D
dhy308 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423 424
    begin = ALIGN_DOWN(MAX(begin, cfi_check), shadow_alignment);
    char* shadow_begin = cfi_shadow_start + addr_to_offset(begin, LIBRARY_ALIGNMENT_BITS);
    char* shadow_end = (char*)(((uint16_t*)(cfi_shadow_start + addr_to_offset(end - 1, LIBRARY_ALIGNMENT_BITS))) + 1);
    char* aligned_shadow_begin = (char*)ALIGN_DOWN((uintptr_t)shadow_begin, PAGE_SIZE);
    char* aligned_shadow_end = (char*)ALIGN_UP((uintptr_t)shadow_end, PAGE_SIZE);

    uint16_t tmp_shadow_size = aligned_shadow_end - aligned_shadow_begin;
    uint16_t offset_begin = shadow_begin - aligned_shadow_begin;
    uint16_t offset_end = shadow_end - aligned_shadow_begin;

    char* tmp_shadow_start = (char*)mmap(NULL, tmp_shadow_size,
        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    if (tmp_shadow_start == MAP_FAILED) {
D
dhy308 已提交
425
        LD_LOGE("[CFI] [%{public}s] mmap failed!\n", __FUNCTION__);
D
dhy308 已提交
426
        return CFI_FAILED;
D
dhy308 已提交
427 428
    }

D
dhy308 已提交
429
    LD_LOGD("[CFI] [%{public}s] tmp_shadow_start is %{public}p\t tmp_shadow_size is 0x%{public}x!\n",
D
dhy308 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442
        __FUNCTION__, tmp_shadow_start, tmp_shadow_size);
    memcpy(tmp_shadow_start, aligned_shadow_begin, offset_begin);
    memcpy(tmp_shadow_start + offset_end, shadow_end, aligned_shadow_end - shadow_end);

    /* If the dso has __cfi_check(), calculate valid shadow value */
    if (type == sv_valid_min) {
#ifdef __arm__
        uint16_t shadow_value_begin = ((begin + shadow_alignment - (cfi_check - 1))
            >> cfi_check_granularity) + sv_valid_min;
#else
        uint16_t shadow_value_begin = ((begin + shadow_alignment - cfi_check)
            >> cfi_check_granularity) + sv_valid_min;
#endif
Y
yinchuang 已提交
443
        LD_LOGD("[CFI] [%{public}s] shadow_value_begin is 0x%{public}x!\n", __FUNCTION__, shadow_value_begin);
D
dhy308 已提交
444 445 446 447 448 449
        uint16_t shadow_value_step = 1 << (shadow_granularity - cfi_check_granularity);
        uint16_t shadow_value = shadow_value_begin;

        /* Set shadow_value */
        for (uint16_t *shadow_addr = tmp_shadow_start + offset_begin;
            shadow_addr != tmp_shadow_start + offset_end; shadow_addr++) {
D
dhy308 已提交
450
            /* If a dso is larger than 16G( = max_shadow_value * shadow_alignment / 1G),
D
dhy308 已提交
451
             * the excess is not checked. */
D
dhy308 已提交
452 453 454 455
            if (shadow_value < shadow_value_begin) {
                *shadow_addr = sv_uncheck;
                continue;
            }
D
dhy308 已提交
456
            *shadow_addr = (*shadow_addr == sv_invalid) ? shadow_value : sv_uncheck;
D
dhy308 已提交
457 458 459 460 461 462 463 464 465 466
            shadow_value += shadow_value_step;
        }
    /* in these cases, shadow_value will always be sv_uncheck or sv_invalid */
    } else if (type == sv_uncheck || type == sv_invalid) {
        /* Set shadow_value */
        for (uint16_t *shadow_addr = tmp_shadow_start + offset_begin;
            shadow_addr != tmp_shadow_start + offset_end; shadow_addr++) {
            *shadow_addr = type;
        }
    } else {
D
dhy308 已提交
467
        LD_LOGE("[CFI] [%{public}s] has error param!\n", __FUNCTION__);
D
dhy308 已提交
468 469
        munmap(tmp_shadow_start, tmp_shadow_size);
        return CFI_FAILED;
D
dhy308 已提交
470 471 472 473 474 475 476
    }

    mprotect(tmp_shadow_start, tmp_shadow_size, PROT_READ);
    /* Remap temp_shadow to CFI shadow. */
    uint16_t* mremap_addr = mremap(tmp_shadow_start, tmp_shadow_size, tmp_shadow_size,
        MREMAP_MAYMOVE | MREMAP_FIXED, aligned_shadow_begin);

D
dhy308 已提交
477
    if (mremap_addr == MAP_FAILED) {
D
dhy308 已提交
478
        LD_LOGE("[CFI] [%{public}s] mremap failed!\n", __FUNCTION__);
D
dhy308 已提交
479 480
        munmap(tmp_shadow_start, tmp_shadow_size);
        return CFI_FAILED;
D
dhy308 已提交
481 482
    }

D
dhy308 已提交
483
    LD_LOGD("[CFI] [%{public}s] fill completed!\n", __FUNCTION__);
D
dhy308 已提交
484
    return CFI_SUCCESS;
D
dhy308 已提交
485 486 487 488
}

void __cfi_slowpath(uint64_t call_site_type_id, void *func_ptr)
{
489 490 491 492 493
    LD_LOGD("[CFI] [%{public}s] called from dso[%{public}s] to dso[%{public}s] func_ptr[%{public}p]\n",
            __FUNCTION__,
            ((struct dso *)addr2dso((size_t)__builtin_return_address(0)))->name,
            ((struct dso *)addr2dso((size_t)func_ptr))->name,
            func_ptr);
D
dhy308 已提交
494 495 496 497 498 499 500

    cfi_slowpath_common(call_site_type_id, func_ptr, NULL);
    return;
}

void __cfi_slowpath_diag(uint64_t call_site_type_id, void *func_ptr, void *diag_data)
{
501 502 503 504 505
    LD_LOGD("[CFI] [%{public}s] called from dso[%{public}s] to dso[%{public}s] func_ptr[%{public}p]\n",
            __FUNCTION__,
            ((struct dso *)addr2dso((size_t)__builtin_return_address(0)))->name,
            ((struct dso *)addr2dso((size_t)func_ptr))->name,
            func_ptr);
D
dhy308 已提交
506 507 508 509

    cfi_slowpath_common(call_site_type_id, func_ptr, diag_data);
    return;
}