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