18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * UBSAN error reporting functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Samsung Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitops.h> 108c2ecf20Sopenharmony_ci#include <linux/bug.h> 118c2ecf20Sopenharmony_ci#include <linux/ctype.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "ubsan.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciconst char *type_check_kinds[] = { 218c2ecf20Sopenharmony_ci "load of", 228c2ecf20Sopenharmony_ci "store to", 238c2ecf20Sopenharmony_ci "reference binding to", 248c2ecf20Sopenharmony_ci "member access within", 258c2ecf20Sopenharmony_ci "member call on", 268c2ecf20Sopenharmony_ci "constructor call on", 278c2ecf20Sopenharmony_ci "downcast of", 288c2ecf20Sopenharmony_ci "downcast of" 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define REPORTED_BIT 31 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN) 348c2ecf20Sopenharmony_ci#define COLUMN_MASK (~(1U << REPORTED_BIT)) 358c2ecf20Sopenharmony_ci#define LINE_MASK (~0U) 368c2ecf20Sopenharmony_ci#else 378c2ecf20Sopenharmony_ci#define COLUMN_MASK (~0U) 388c2ecf20Sopenharmony_ci#define LINE_MASK (~(1U << REPORTED_BIT)) 398c2ecf20Sopenharmony_ci#endif 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define VALUE_LENGTH 40 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic bool was_reported(struct source_location *location) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return test_and_set_bit(REPORTED_BIT, &location->reported); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic bool suppress_report(struct source_location *loc) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return current->in_ubsan || was_reported(loc); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic bool type_is_int(struct type_descriptor *type) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci return type->type_kind == type_kind_int; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic bool type_is_signed(struct type_descriptor *type) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci WARN_ON(!type_is_int(type)); 618c2ecf20Sopenharmony_ci return type->type_info & 1; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic unsigned type_bit_width(struct type_descriptor *type) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return 1 << (type->type_info >> 1); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic bool is_inline_int(struct type_descriptor *type) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci unsigned inline_bits = sizeof(unsigned long)*8; 728c2ecf20Sopenharmony_ci unsigned bits = type_bit_width(type); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci WARN_ON(!type_is_int(type)); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return bits <= inline_bits; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic s_max get_signed_val(struct type_descriptor *type, void *val) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci if (is_inline_int(type)) { 828c2ecf20Sopenharmony_ci unsigned extra_bits = sizeof(s_max)*8 - type_bit_width(type); 838c2ecf20Sopenharmony_ci unsigned long ulong_val = (unsigned long)val; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return ((s_max)ulong_val) << extra_bits >> extra_bits; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (type_bit_width(type) == 64) 898c2ecf20Sopenharmony_ci return *(s64 *)val; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return *(s_max *)val; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic bool val_is_negative(struct type_descriptor *type, void *val) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return type_is_signed(type) && get_signed_val(type, val) < 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic u_max get_unsigned_val(struct type_descriptor *type, void *val) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci if (is_inline_int(type)) 1028c2ecf20Sopenharmony_ci return (unsigned long)val; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (type_bit_width(type) == 64) 1058c2ecf20Sopenharmony_ci return *(u64 *)val; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return *(u_max *)val; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void val_to_string(char *str, size_t size, struct type_descriptor *type, 1118c2ecf20Sopenharmony_ci void *value) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci if (type_is_int(type)) { 1148c2ecf20Sopenharmony_ci if (type_bit_width(type) == 128) { 1158c2ecf20Sopenharmony_ci#if defined(CONFIG_ARCH_SUPPORTS_INT128) 1168c2ecf20Sopenharmony_ci u_max val = get_unsigned_val(type, value); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci scnprintf(str, size, "0x%08x%08x%08x%08x", 1198c2ecf20Sopenharmony_ci (u32)(val >> 96), 1208c2ecf20Sopenharmony_ci (u32)(val >> 64), 1218c2ecf20Sopenharmony_ci (u32)(val >> 32), 1228c2ecf20Sopenharmony_ci (u32)(val)); 1238c2ecf20Sopenharmony_ci#else 1248c2ecf20Sopenharmony_ci WARN_ON(1); 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci } else if (type_is_signed(type)) { 1278c2ecf20Sopenharmony_ci scnprintf(str, size, "%lld", 1288c2ecf20Sopenharmony_ci (s64)get_signed_val(type, value)); 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci scnprintf(str, size, "%llu", 1318c2ecf20Sopenharmony_ci (u64)get_unsigned_val(type, value)); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void ubsan_prologue(struct source_location *loc, const char *reason) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci current->in_ubsan++; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci pr_err("========================================" 1418c2ecf20Sopenharmony_ci "========================================\n"); 1428c2ecf20Sopenharmony_ci pr_err("UBSAN: %s in %s:%d:%d\n", reason, loc->file_name, 1438c2ecf20Sopenharmony_ci loc->line & LINE_MASK, loc->column & COLUMN_MASK); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic void ubsan_epilogue(void) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci dump_stack(); 1498c2ecf20Sopenharmony_ci pr_err("========================================" 1508c2ecf20Sopenharmony_ci "========================================\n"); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci current->in_ubsan--; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci check_panic_on_warn("UBSAN"); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void handle_overflow(struct overflow_data *data, void *lhs, 1588c2ecf20Sopenharmony_ci void *rhs, char op) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci struct type_descriptor *type = data->type; 1628c2ecf20Sopenharmony_ci char lhs_val_str[VALUE_LENGTH]; 1638c2ecf20Sopenharmony_ci char rhs_val_str[VALUE_LENGTH]; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (suppress_report(&data->location)) 1668c2ecf20Sopenharmony_ci return; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, type_is_signed(type) ? 1698c2ecf20Sopenharmony_ci "signed-integer-overflow" : 1708c2ecf20Sopenharmony_ci "unsigned-integer-overflow"); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci val_to_string(lhs_val_str, sizeof(lhs_val_str), type, lhs); 1738c2ecf20Sopenharmony_ci val_to_string(rhs_val_str, sizeof(rhs_val_str), type, rhs); 1748c2ecf20Sopenharmony_ci pr_err("%s %c %s cannot be represented in type %s\n", 1758c2ecf20Sopenharmony_ci lhs_val_str, 1768c2ecf20Sopenharmony_ci op, 1778c2ecf20Sopenharmony_ci rhs_val_str, 1788c2ecf20Sopenharmony_ci type->type_name); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ubsan_epilogue(); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_civoid __ubsan_handle_add_overflow(void *data, 1848c2ecf20Sopenharmony_ci void *lhs, void *rhs) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci handle_overflow(data, lhs, rhs, '+'); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_add_overflow); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_civoid __ubsan_handle_sub_overflow(void *data, 1928c2ecf20Sopenharmony_ci void *lhs, void *rhs) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci handle_overflow(data, lhs, rhs, '-'); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_sub_overflow); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_civoid __ubsan_handle_mul_overflow(void *data, 1998c2ecf20Sopenharmony_ci void *lhs, void *rhs) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci handle_overflow(data, lhs, rhs, '*'); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_mul_overflow); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_civoid __ubsan_handle_negate_overflow(void *_data, void *old_val) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct overflow_data *data = _data; 2088c2ecf20Sopenharmony_ci char old_val_str[VALUE_LENGTH]; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (suppress_report(&data->location)) 2118c2ecf20Sopenharmony_ci return; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, "negation-overflow"); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci val_to_string(old_val_str, sizeof(old_val_str), data->type, old_val); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci pr_err("negation of %s cannot be represented in type %s:\n", 2188c2ecf20Sopenharmony_ci old_val_str, data->type->type_name); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ubsan_epilogue(); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_negate_overflow); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_civoid __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct overflow_data *data = _data; 2288c2ecf20Sopenharmony_ci char rhs_val_str[VALUE_LENGTH]; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (suppress_report(&data->location)) 2318c2ecf20Sopenharmony_ci return; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, "division-overflow"); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (type_is_signed(data->type) && get_signed_val(data->type, rhs) == -1) 2388c2ecf20Sopenharmony_ci pr_err("division of %s by -1 cannot be represented in type %s\n", 2398c2ecf20Sopenharmony_ci rhs_val_str, data->type->type_name); 2408c2ecf20Sopenharmony_ci else 2418c2ecf20Sopenharmony_ci pr_err("division by zero\n"); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci ubsan_epilogue(); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_divrem_overflow); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void handle_null_ptr_deref(struct type_mismatch_data_common *data) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci if (suppress_report(data->location)) 2508c2ecf20Sopenharmony_ci return; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ubsan_prologue(data->location, "null-ptr-deref"); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci pr_err("%s null pointer of type %s\n", 2558c2ecf20Sopenharmony_ci type_check_kinds[data->type_check_kind], 2568c2ecf20Sopenharmony_ci data->type->type_name); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ubsan_epilogue(); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void handle_misaligned_access(struct type_mismatch_data_common *data, 2628c2ecf20Sopenharmony_ci unsigned long ptr) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci if (suppress_report(data->location)) 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci ubsan_prologue(data->location, "misaligned-access"); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci pr_err("%s misaligned address %p for type %s\n", 2708c2ecf20Sopenharmony_ci type_check_kinds[data->type_check_kind], 2718c2ecf20Sopenharmony_ci (void *)ptr, data->type->type_name); 2728c2ecf20Sopenharmony_ci pr_err("which requires %ld byte alignment\n", data->alignment); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ubsan_epilogue(); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void handle_object_size_mismatch(struct type_mismatch_data_common *data, 2788c2ecf20Sopenharmony_ci unsigned long ptr) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci if (suppress_report(data->location)) 2818c2ecf20Sopenharmony_ci return; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci ubsan_prologue(data->location, "object-size-mismatch"); 2848c2ecf20Sopenharmony_ci pr_err("%s address %p with insufficient space\n", 2858c2ecf20Sopenharmony_ci type_check_kinds[data->type_check_kind], 2868c2ecf20Sopenharmony_ci (void *) ptr); 2878c2ecf20Sopenharmony_ci pr_err("for an object of type %s\n", data->type->type_name); 2888c2ecf20Sopenharmony_ci ubsan_epilogue(); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void ubsan_type_mismatch_common(struct type_mismatch_data_common *data, 2928c2ecf20Sopenharmony_ci unsigned long ptr) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci unsigned long flags = user_access_save(); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!ptr) 2978c2ecf20Sopenharmony_ci handle_null_ptr_deref(data); 2988c2ecf20Sopenharmony_ci else if (data->alignment && !IS_ALIGNED(ptr, data->alignment)) 2998c2ecf20Sopenharmony_ci handle_misaligned_access(data, ptr); 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci handle_object_size_mismatch(data, ptr); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci user_access_restore(flags); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_civoid __ubsan_handle_type_mismatch(struct type_mismatch_data *data, 3078c2ecf20Sopenharmony_ci void *ptr) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct type_mismatch_data_common common_data = { 3108c2ecf20Sopenharmony_ci .location = &data->location, 3118c2ecf20Sopenharmony_ci .type = data->type, 3128c2ecf20Sopenharmony_ci .alignment = data->alignment, 3138c2ecf20Sopenharmony_ci .type_check_kind = data->type_check_kind 3148c2ecf20Sopenharmony_ci }; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci ubsan_type_mismatch_common(&common_data, (unsigned long)ptr); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_type_mismatch); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_civoid __ubsan_handle_type_mismatch_v1(void *_data, void *ptr) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct type_mismatch_data_v1 *data = _data; 3238c2ecf20Sopenharmony_ci struct type_mismatch_data_common common_data = { 3248c2ecf20Sopenharmony_ci .location = &data->location, 3258c2ecf20Sopenharmony_ci .type = data->type, 3268c2ecf20Sopenharmony_ci .alignment = 1UL << data->log_alignment, 3278c2ecf20Sopenharmony_ci .type_check_kind = data->type_check_kind 3288c2ecf20Sopenharmony_ci }; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ubsan_type_mismatch_common(&common_data, (unsigned long)ptr); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_civoid __ubsan_handle_out_of_bounds(void *_data, void *index) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct out_of_bounds_data *data = _data; 3378c2ecf20Sopenharmony_ci char index_str[VALUE_LENGTH]; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (suppress_report(&data->location)) 3408c2ecf20Sopenharmony_ci return; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, "array-index-out-of-bounds"); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci val_to_string(index_str, sizeof(index_str), data->index_type, index); 3458c2ecf20Sopenharmony_ci pr_err("index %s is out of range for type %s\n", index_str, 3468c2ecf20Sopenharmony_ci data->array_type->type_name); 3478c2ecf20Sopenharmony_ci ubsan_epilogue(); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_out_of_bounds); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_civoid __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct shift_out_of_bounds_data *data = _data; 3548c2ecf20Sopenharmony_ci struct type_descriptor *rhs_type = data->rhs_type; 3558c2ecf20Sopenharmony_ci struct type_descriptor *lhs_type = data->lhs_type; 3568c2ecf20Sopenharmony_ci char rhs_str[VALUE_LENGTH]; 3578c2ecf20Sopenharmony_ci char lhs_str[VALUE_LENGTH]; 3588c2ecf20Sopenharmony_ci unsigned long ua_flags = user_access_save(); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (suppress_report(&data->location)) 3618c2ecf20Sopenharmony_ci goto out; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, "shift-out-of-bounds"); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci val_to_string(rhs_str, sizeof(rhs_str), rhs_type, rhs); 3668c2ecf20Sopenharmony_ci val_to_string(lhs_str, sizeof(lhs_str), lhs_type, lhs); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (val_is_negative(rhs_type, rhs)) 3698c2ecf20Sopenharmony_ci pr_err("shift exponent %s is negative\n", rhs_str); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci else if (get_unsigned_val(rhs_type, rhs) >= 3728c2ecf20Sopenharmony_ci type_bit_width(lhs_type)) 3738c2ecf20Sopenharmony_ci pr_err("shift exponent %s is too large for %u-bit type %s\n", 3748c2ecf20Sopenharmony_ci rhs_str, 3758c2ecf20Sopenharmony_ci type_bit_width(lhs_type), 3768c2ecf20Sopenharmony_ci lhs_type->type_name); 3778c2ecf20Sopenharmony_ci else if (val_is_negative(lhs_type, lhs)) 3788c2ecf20Sopenharmony_ci pr_err("left shift of negative value %s\n", 3798c2ecf20Sopenharmony_ci lhs_str); 3808c2ecf20Sopenharmony_ci else 3818c2ecf20Sopenharmony_ci pr_err("left shift of %s by %s places cannot be" 3828c2ecf20Sopenharmony_ci " represented in type %s\n", 3838c2ecf20Sopenharmony_ci lhs_str, rhs_str, 3848c2ecf20Sopenharmony_ci lhs_type->type_name); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ubsan_epilogue(); 3878c2ecf20Sopenharmony_ciout: 3888c2ecf20Sopenharmony_ci user_access_restore(ua_flags); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_shift_out_of_bounds); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_civoid __ubsan_handle_builtin_unreachable(void *_data) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct unreachable_data *data = _data; 3968c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, "unreachable"); 3978c2ecf20Sopenharmony_ci pr_err("calling __builtin_unreachable()\n"); 3988c2ecf20Sopenharmony_ci ubsan_epilogue(); 3998c2ecf20Sopenharmony_ci panic("can't return from __builtin_unreachable()"); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_builtin_unreachable); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_civoid __ubsan_handle_load_invalid_value(void *_data, void *val) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct invalid_value_data *data = _data; 4068c2ecf20Sopenharmony_ci char val_str[VALUE_LENGTH]; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (suppress_report(&data->location)) 4098c2ecf20Sopenharmony_ci return; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, "invalid-load"); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci val_to_string(val_str, sizeof(val_str), data->type, val); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci pr_err("load of value %s is not a valid value for type %s\n", 4168c2ecf20Sopenharmony_ci val_str, data->type->type_name); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ubsan_epilogue(); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_load_invalid_value); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_civoid __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, 4238c2ecf20Sopenharmony_ci unsigned long align, 4248c2ecf20Sopenharmony_ci unsigned long offset); 4258c2ecf20Sopenharmony_civoid __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr, 4268c2ecf20Sopenharmony_ci unsigned long align, 4278c2ecf20Sopenharmony_ci unsigned long offset) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct alignment_assumption_data *data = _data; 4308c2ecf20Sopenharmony_ci unsigned long real_ptr; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (suppress_report(&data->location)) 4338c2ecf20Sopenharmony_ci return; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ubsan_prologue(&data->location, "alignment-assumption"); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (offset) 4388c2ecf20Sopenharmony_ci pr_err("assumption of %lu byte alignment (with offset of %lu byte) for pointer of type %s failed", 4398c2ecf20Sopenharmony_ci align, offset, data->type->type_name); 4408c2ecf20Sopenharmony_ci else 4418c2ecf20Sopenharmony_ci pr_err("assumption of %lu byte alignment for pointer of type %s failed", 4428c2ecf20Sopenharmony_ci align, data->type->type_name); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci real_ptr = ptr - offset; 4458c2ecf20Sopenharmony_ci pr_err("%saddress is %lu aligned, misalignment offset is %lu bytes", 4468c2ecf20Sopenharmony_ci offset ? "offset " : "", BIT(real_ptr ? __ffs(real_ptr) : 0), 4478c2ecf20Sopenharmony_ci real_ptr & (align - 1)); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ubsan_epilogue(); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ubsan_handle_alignment_assumption); 452