linux/lib/ubsan.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * UBSAN error reporting functions
 *
 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
 * Author: Andrey Ryabinin <[email protected]>
 */

#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/ubsan.h>
#include <kunit/test-bug.h>

#include "ubsan.h"

#ifdef CONFIG_UBSAN_TRAP
/*
 * Only include matches for UBSAN checks that are actually compiled in.
 * The mappings of struct SanitizerKind (the -fsanitize=xxx args) to
 * enum SanitizerHandler (the traps) in Clang is in clang/lib/CodeGen/.
 */
const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type)
{
	switch (check_type) {
#ifdef CONFIG_UBSAN_BOUNDS
	/*
	 * SanitizerKind::ArrayBounds and SanitizerKind::LocalBounds
	 * emit SanitizerHandler::OutOfBounds.
	 */
	case ubsan_out_of_bounds:
		return "UBSAN: array index out of bounds";
#endif
#ifdef CONFIG_UBSAN_SHIFT
	/*
	 * SanitizerKind::ShiftBase and SanitizerKind::ShiftExponent
	 * emit SanitizerHandler::ShiftOutOfBounds.
	 */
	case ubsan_shift_out_of_bounds:
		return "UBSAN: shift out of bounds";
#endif
#if defined(CONFIG_UBSAN_DIV_ZERO) || defined(CONFIG_UBSAN_SIGNED_WRAP)
	/*
	 * SanitizerKind::IntegerDivideByZero and
	 * SanitizerKind::SignedIntegerOverflow emit
	 * SanitizerHandler::DivremOverflow.
	 */
	case ubsan_divrem_overflow:
		return "UBSAN: divide/remainder overflow";
#endif
#ifdef CONFIG_UBSAN_UNREACHABLE
	/*
	 * SanitizerKind::Unreachable emits
	 * SanitizerHandler::BuiltinUnreachable.
	 */
	case ubsan_builtin_unreachable:
		return "UBSAN: unreachable code";
#endif
#if defined(CONFIG_UBSAN_BOOL) || defined(CONFIG_UBSAN_ENUM)
	/*
	 * SanitizerKind::Bool and SanitizerKind::Enum emit
	 * SanitizerHandler::LoadInvalidValue.
	 */
	case ubsan_load_invalid_value:
		return "UBSAN: loading invalid value";
#endif
#ifdef CONFIG_UBSAN_ALIGNMENT
	/*
	 * SanitizerKind::Alignment emits SanitizerHandler::TypeMismatch
	 * or SanitizerHandler::AlignmentAssumption.
	 */
	case ubsan_alignment_assumption:
		return "UBSAN: alignment assumption";
	case ubsan_type_mismatch:
		return "UBSAN: type mismatch";
#endif
#ifdef CONFIG_UBSAN_SIGNED_WRAP
	/*
	 * SanitizerKind::SignedIntegerOverflow emits
	 * SanitizerHandler::AddOverflow, SanitizerHandler::SubOverflow,
	 * or SanitizerHandler::MulOverflow.
	 */
	case ubsan_add_overflow:
		return "UBSAN: integer addition overflow";
	case ubsan_sub_overflow:
		return "UBSAN: integer subtraction overflow";
	case ubsan_mul_overflow:
		return "UBSAN: integer multiplication overflow";
#endif
	default:
		return "UBSAN: unrecognized failure code";
	}
}

#else
static const char * const type_check_kinds[] =;

#define REPORTED_BIT

#if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN)
#define COLUMN_MASK
#define LINE_MASK
#else
#define COLUMN_MASK
#define LINE_MASK
#endif

#define VALUE_LENGTH

static bool was_reported(struct source_location *location)
{}

static bool suppress_report(struct source_location *loc)
{}

static bool type_is_int(struct type_descriptor *type)
{}

static bool type_is_signed(struct type_descriptor *type)
{}

static unsigned type_bit_width(struct type_descriptor *type)
{}

static bool is_inline_int(struct type_descriptor *type)
{}

static s_max get_signed_val(struct type_descriptor *type, void *val)
{}

static bool val_is_negative(struct type_descriptor *type, void *val)
{}

static u_max get_unsigned_val(struct type_descriptor *type, void *val)
{}

static void val_to_string(char *str, size_t size, struct type_descriptor *type,
			void *value)
{}

static void ubsan_prologue(struct source_location *loc, const char *reason)
{}

static void ubsan_epilogue(void)
{}

static void handle_overflow(struct overflow_data *data, void *lhs,
			void *rhs, char op)
{}

void __ubsan_handle_add_overflow(void *data,
				void *lhs, void *rhs)
{}
EXPORT_SYMBOL();

void __ubsan_handle_sub_overflow(void *data,
				void *lhs, void *rhs)
{}
EXPORT_SYMBOL();

void __ubsan_handle_mul_overflow(void *data,
				void *lhs, void *rhs)
{}
EXPORT_SYMBOL();

void __ubsan_handle_negate_overflow(void *_data, void *old_val)
{}
EXPORT_SYMBOL();


void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs)
{}
EXPORT_SYMBOL();

static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
{}

static void handle_misaligned_access(struct type_mismatch_data_common *data,
				unsigned long ptr)
{}

static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
					unsigned long ptr)
{}

static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
				unsigned long ptr)
{}

void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
				void *ptr)
{}
EXPORT_SYMBOL();

void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr)
{}
EXPORT_SYMBOL();

void __ubsan_handle_out_of_bounds(void *_data, void *index)
{}
EXPORT_SYMBOL();

void __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs)
{}
EXPORT_SYMBOL();


void __ubsan_handle_builtin_unreachable(void *_data)
{}
EXPORT_SYMBOL();

void __ubsan_handle_load_invalid_value(void *_data, void *val)
{}
EXPORT_SYMBOL();

void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
					 unsigned long align,
					 unsigned long offset)
{}
EXPORT_SYMBOL();

#endif /* !CONFIG_UBSAN_TRAP */