cfi.c 20.9 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 37 38 39 40 41 42 43 44 45 46 47 48 49
 * 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:
 *      sv = (AlignUp(__cfi_check, LIBRARY_ALIGNMENT) - cfi_check_addr + N * LIBRARY_ALIGNMENT) / 4096 + 2;
 *
 *      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
    LD_LOGI("[CFI] [%{public}s] the cfi_check_func_addr is %{public}p!\n", __FUNCTION__, cfi_check_func_addr);
D
dhy308 已提交
180 181 182 183

    return cfi_check_func_addr;
}

184
static inline void cfi_slowpath_common(uint64_t call_site_type_id, void *func_ptr, void *diag_data)
D
dhy308 已提交
185
{
D
dhy308 已提交
186
    LD_LOGI("[CFI] [%{public}s] func_ptr[%{public}p] !\n", __FUNCTION__, func_ptr);
D
dhy308 已提交
187 188 189

    uint16_t value = sv_invalid;

190
    if (func_ptr == NULL) {
D
dhy308 已提交
191
        LD_LOGE("[CFI] [%{public}s] func_ptr is NULL!\n", __FUNCTION__);
192 193 194
        return;
    }

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

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

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

D
dhy308 已提交
211 212 213 214 215
    if (offset > shadow_size) {
        value = sv_invalid;
    } else {
        value = *((uint16_t*)(cfi_shadow_start + offset));
    }
D
dhy308 已提交
216
    LD_LOGI("[CFI] [%{public}s] the value is 0x%{public}x!\n", __FUNCTION__, value);
D
dhy308 已提交
217 218 219 220 221

    struct dso *dso = NULL;
    switch (value)
    {
    case sv_invalid:
D
dhy308 已提交
222 223 224 225 226 227 228
        /* 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 已提交
229 230
        dso = (struct dso *)addr2dso((size_t)__builtin_return_address(0));
        if (dso == NULL) {
D
dhy308 已提交
231
            LD_LOGE("[CFI] [%{public}s] can not find the dso!\n", __FUNCTION__);
D
dhy308 已提交
232 233
            __builtin_trap();
        }
D
dhy308 已提交
234
        LD_LOGI("[CFI] [%{public}s] dso name[%{public}s]!\n", __FUNCTION__, dso->name);
235

D
dhy308 已提交
236 237
        struct symdef cfi_check_sym = find_cfi_check_sym(dso);
        if (!cfi_check_sym.sym) {
D
dhy308 已提交
238
            LD_LOGE("[CFI] [%{public}s] can not find the __cfi_check in the dso!\n", __FUNCTION__);
D
dhy308 已提交
239 240
            __builtin_trap();
        }
D
dhy308 已提交
241
        LD_LOGD("[CFI] [%{public}s] cfi_check addr[%{public}p]!\n", __FUNCTION__,
242
                LADDR(cfi_check_sym.dso, cfi_check_sym.sym->st_value));
D
dhy308 已提交
243 244 245 246 247 248 249 250 251 252 253 254
        ((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 已提交
255
int init_cfi_shadow(struct dso *dso_list, struct dso *ldso)
D
dhy308 已提交
256
{
D
dhy308 已提交
257
    LD_LOGI("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
258 259

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

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

    return map_dso_to_cfi_shadow(dso_list);
}

D
dhy308 已提交
271
int map_dso_to_cfi_shadow(struct dso *dso)
D
dhy308 已提交
272
{
D
dhy308 已提交
273
    LD_LOGI("[CFI] [%{public}s] start!\n", __FUNCTION__);
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 287 288 289 290 291 292
        /* Find __cfi_check symbol in dso list */
        for (struct dso *p = dso; p; p = p->next) {
            if (find_cfi_check_sym(p).sym) {
                LD_LOGI("[CFI] [%{public}s] find __cfi_check function in dso %{public}s!\n", __FUNCTION__, p->name);
                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
            }
D
dhy308 已提交
298
            LD_LOGD("[CFI] [%{public}s] add_dso_to_cfi_shadow with dso_list_head!\n", __FUNCTION__);
D
dhy308 已提交
299
            add_dso_to_cfi_shadow(dso_list_head);
D
dhy308 已提交
300
            prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, cfi_shadow_start, shadow_size, "cfi_shadow:musl");
D
dhy308 已提交
301 302 303
        }
    /* If the cfi shadow exists, map the current dso and its dependents to it. */
    } else {
D
dhy308 已提交
304
        LD_LOGD("[CFI] [%{public}s] add_dso_to_cfi_shadow with dso!\n", __FUNCTION__);
D
dhy308 已提交
305
        add_dso_to_cfi_shadow(dso);
D
dhy308 已提交
306
        prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, cfi_shadow_start, shadow_size, "cfi_shadow:musl");
D
dhy308 已提交
307 308
    }

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

void unmap_dso_from_cfi_shadow(struct dso *dso)
{
D
dhy308 已提交
314
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
315 316

    if (dso == NULL) {
D
dhy308 已提交
317
        LD_LOGE("[CFI] [%{public}s] has null param!\n", __FUNCTION__);
D
dhy308 已提交
318 319 320
        return;
    }

D
dhy308 已提交
321
    LD_LOGI("[CFI] [%{public}s] unmap dso %{public}s from shadow!\n", __FUNCTION__, dso->name);
D
dhy308 已提交
322 323 324 325 326 327 328

    if (cfi_shadow_start == NULL)
        return;

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

D
dhy308 已提交
329 330 331
    if (dso->is_mapped_to_shadow == false)
        return;

D
dhy308 已提交
332 333
    /* 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 已提交
334 335
    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 已提交
336 337 338 339

    return;
}

D
dhy308 已提交
340
static int create_cfi_shadow(void)
D
dhy308 已提交
341
{
D
dhy308 已提交
342
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
343 344

    /* Each process can load up to (max_target_addr >> shadow_granularity) dsos. Shift left 1 bit because the shadow 
D
dhy308 已提交
345
     * value is uint16_t. The size passed to mmap() should be aligned with 4096, so shadow_size should be aligned. */
D
dhy308 已提交
346 347 348 349 350
    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 已提交
351
        LD_LOGE("[CFI] [%{public}s] mmap failed!\n", __FUNCTION__);
D
dhy308 已提交
352
        return CFI_FAILED;
D
dhy308 已提交
353 354 355
    }

    cfi_shadow_start = (char*)mmap_addr;
D
dhy308 已提交
356
    LD_LOGI("[CFI] [%{public}s] the cfi_shadow_start addr is %{public}p!\n", __FUNCTION__, cfi_shadow_start);
D
dhy308 已提交
357

D
dhy308 已提交
358
    return CFI_SUCCESS;
D
dhy308 已提交
359 360
}

D
dhy308 已提交
361
static int add_dso_to_cfi_shadow(struct dso *dso)
D
dhy308 已提交
362
{
D
dhy308 已提交
363
    LD_LOGI("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
364 365

    for (struct dso *p = dso; p; p = p->next) {
D
dhy308 已提交
366
        LD_LOGI("[CFI] [%{public}s] start to deal with dso %{public}s!\n", __FUNCTION__, p->name);
D
dhy308 已提交
367
        if (p->map == 0 || p->map_len == 0) {
D
dhy308 已提交
368
            LD_LOGW("[CFI] [%{public}s] the dso has no data! map[%{public}p] map_len[0x%{public}x]\n",
369
                    __FUNCTION__, p->map, p->map_len);
D
dhy308 已提交
370 371 372 373
            continue;
        }

        if (p->is_mapped_to_shadow == true) {
D
dhy308 已提交
374
            LD_LOGW("[CFI] [%{public}s] the dso is already in shadow!\n", __FUNCTION__);
D
dhy308 已提交
375 376 377 378 379 380
            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) {
D
dhy308 已提交
381
            LD_LOGI("[CFI] [%{public}s] the dso has no __cfi_check()!\n", __FUNCTION__);
D
dhy308 已提交
382
            if (fill_shadow_value_to_shadow(p->map, p->map + p->map_len, 0, sv_uncheck) == CFI_FAILED) {
D
dhy308 已提交
383
                LD_LOGE("[CFI] [%{public}s] add dso to cfi shadow failed!\n", __FUNCTION__);
D
dhy308 已提交
384
                return CFI_FAILED;
D
dhy308 已提交
385 386 387
            }
        /* If the dso has __cfi_check(), set it's shadow value valid. */
        } else {
D
dhy308 已提交
388
            LD_LOGI("[CFI] [%{public}s] the dso has __cfi_check()!\n", __FUNCTION__);
D
dhy308 已提交
389 390 391 392
            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) {
D
dhy308 已提交
393
                LD_LOGE("[CFI] [%{public}s] the dso has null cfi_check func!\n", __FUNCTION__);
D
dhy308 已提交
394
                return CFI_FAILED;
D
dhy308 已提交
395
            }
D
dhy308 已提交
396
            if (fill_shadow_value_to_shadow(p->map, end, cfi_check, sv_valid_min) == CFI_FAILED) {
D
dhy308 已提交
397
                LD_LOGE("[CFI] [%{public}s] add dso to cfi shadow failed!\n", __FUNCTION__);
D
dhy308 已提交
398
                return CFI_FAILED;
D
dhy308 已提交
399 400
            }
        }
D
dhy308 已提交
401
        p->is_mapped_to_shadow = true;
D
dhy308 已提交
402
        LD_LOGI("[CFI] [%{public}s] finish to deal with dso %{public}s!\n", __FUNCTION__, p->name);
D
dhy308 已提交
403 404
    }

D
dhy308 已提交
405
    return CFI_SUCCESS;
D
dhy308 已提交
406 407
}

D
dhy308 已提交
408
static int fill_shadow_value_to_shadow(uintptr_t begin, uintptr_t end, uintptr_t cfi_check, uint16_t type)
D
dhy308 已提交
409
{
D
dhy308 已提交
410
    LD_LOGI("[CFI] [%{public}s] begin[%{public}x] end[%{public}x] cfi_check[%{public}x] type[%{public}x]!\n",
411
            __FUNCTION__, begin, end, cfi_check, type);
D
dhy308 已提交
412 413

    /* To ensure the atomicity of the CFI shadow operation, we create a temp_shadow, write the shadow value to 
D
dhy308 已提交
414
     * the temp_shadow, and then write it back to the CFI shadow by mremap(). */
D
dhy308 已提交
415 416 417 418 419 420 421 422 423 424 425 426 427 428
    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 已提交
429
        LD_LOGE("[CFI] [%{public}s] mmap failed!\n", __FUNCTION__);
D
dhy308 已提交
430
        return CFI_FAILED;
D
dhy308 已提交
431 432
    }

D
dhy308 已提交
433
    LD_LOGD("[CFI] [%{public}s] tmp_shadow_start is %{public}p\t tmp_shadow_size is 0x%{public}x!\n",
D
dhy308 已提交
434 435 436 437 438 439 440 441 442 443 444 445 446
        __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
D
dhy308 已提交
447
        LD_LOGI("[CFI] [%{public}s] shadow_value_begin is 0x%{public}x!\n", __FUNCTION__, shadow_value_begin);
D
dhy308 已提交
448 449 450 451 452 453
        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 已提交
454
            /* If a dso is larger than 16G( = max_shadow_value * shadow_alignment / 1G),
D
dhy308 已提交
455
             * the excess is not checked. */
D
dhy308 已提交
456 457 458 459
            if (shadow_value < shadow_value_begin) {
                *shadow_addr = sv_uncheck;
                continue;
            }
D
dhy308 已提交
460
            *shadow_addr = (*shadow_addr == sv_invalid) ? shadow_value : sv_uncheck;
D
dhy308 已提交
461 462 463 464 465 466 467 468 469 470
            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 已提交
471
        LD_LOGE("[CFI] [%{public}s] has error param!\n", __FUNCTION__);
D
dhy308 已提交
472 473
        munmap(tmp_shadow_start, tmp_shadow_size);
        return CFI_FAILED;
D
dhy308 已提交
474 475 476 477 478 479 480
    }

    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 已提交
481
    if (mremap_addr == MAP_FAILED) {
D
dhy308 已提交
482
        LD_LOGE("[CFI] [%{public}s] mremap failed!\n", __FUNCTION__);
D
dhy308 已提交
483 484
        munmap(tmp_shadow_start, tmp_shadow_size);
        return CFI_FAILED;
D
dhy308 已提交
485 486
    }

D
dhy308 已提交
487
    LD_LOGD("[CFI] [%{public}s] fill completed!\n", __FUNCTION__);
D
dhy308 已提交
488
    return CFI_SUCCESS;
D
dhy308 已提交
489 490 491 492
}

void __cfi_slowpath(uint64_t call_site_type_id, void *func_ptr)
{
D
dhy308 已提交
493
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
494 495 496 497 498 499 500 501

    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)
{
D
dhy308 已提交
502
    LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__);
D
dhy308 已提交
503 504 505 506 507

    cfi_slowpath_common(call_site_type_id, func_ptr, diag_data);

    return;
}