非法检测之UBSAN

一 概念

UBSAN:全称Undefined Behavior Sanitizer,用于运行时检测一些未定义行为。未定义,是一个统称,并非是代码中的变量等没有定义,如果是此类错误,编译就会进行拦截。此含义就可以理解为一个非法行为的检测,比如定义的变量超过范围,数组使用不正确的下标,左右移不符合规范,或者超过变量的范围,对齐不匹配等等。

二 内核版本区分

2.1 kernel-4.19

userdebug版本默认使能,user版本未开启,使能方法:

junfang1@buildsrv-n43:~/work/0_code/s0-trank-user/tran_projects$ git diff x6820/x6820_h773_a1/x6820/kernel-4.19/arch/arm64/configs/x6820_h773_defconfig
diff --git a/x6820/x6820_h773_a1/x6820/kernel-4.19/arch/arm64/configs/x6820_h773_defconfig b/x6820/x6820_h773_a1/x6820/kernel-4.19/arch/arm64/configs/x6820_h773_defconfig
index a0781309f..a285bcd64 100644
--- a/x6820/x6820_h773_a1/x6820/kernel-4.19/arch/arm64/configs/x6820_h773_defconfig
+++ b/x6820/x6820_h773_a1/x6820/kernel-4.19/arch/arm64/configs/x6820_h773_defconfig
@@ -4,6 +4,11 @@ CONFIG_IKHEADERS=m
 CONFIG_LOG_BUF_SHIFT=19
 CONFIG_UCLAMP_TASK=y
 CONFIG_BLK_CGROUP=y
+#add for ubsan start
+CONFIG_UBSAN=y
+CONFIG_UBSAN_SANITIZE_ALL=y
+#add for ubsan end
 CONFIG_UCLAMP_TASK_GROUP=y
 CONFIG_CPUSETS=y
 CONFIG_SCHED_TUNE=y

2.2 kernel-5.10

默认所有版本开启,可通过命令查看:

:/ # zcat /proc/config.gz | grep UBSAN
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
CONFIG_UBSAN=y
CONFIG_UBSAN_TRAP=y
CONFIG_CC_HAS_UBSAN_BOUNDS=y
CONFIG_CC_HAS_UBSAN_ARRAY_BOUNDS=y
CONFIG_UBSAN_BOUNDS=y
CONFIG_UBSAN_ARRAY_BOUNDS=y
CONFIG_UBSAN_LOCAL_BOUNDS=y
# CONFIG_UBSAN_SHIFT is not set
# CONFIG_UBSAN_DIV_ZERO is not set
# CONFIG_UBSAN_UNREACHABLE is not set
# CONFIG_UBSAN_OBJECT_SIZE is not set
# CONFIG_UBSAN_BOOL is not set
# CONFIG_UBSAN_ENUM is not set
CONFIG_UBSAN_SANITIZE_ALL=y
# CONFIG_TEST_UBSAN is not set

三 案例

对应的code如下:

=》除数为0
static void test_ubsan_divrem_overflow(void)
{
        volatile int val = 16;
        volatile int val2 = 0;

        val /= val2;
}

=》数组下标非法
static void test_ubsan_vla_bound_not_positive(void)
{
        volatile int size = -1;
        char buf[size];

        (void)buf;
}

=》右移不合理
static void test_ubsan_shift_out_of_bounds(void)
{
        volatile int val = -1;
        int val2 = 10;

        val2 <<= val;
}

=》数组index越界
static void test_ubsan_out_of_bounds(void)
{
        volatile int i = 4, j = 5;
        volatile int arr[i];

        arr[j] = i;
}

UBASAN检测出来的异常打印如下:

<3>[ 1056.356966]-(7)[7270:insmod]================================================================================
<3>[ 1056.358247]-(7)[7270:insmod]UBSAN: Undefined behaviour in /work/junfang1/work/0_code/s0-trank-user/kernel-4.19/lib/test_ubsan.c:42:6
<3>[ 1056.359784]-(7)[7270:insmod]division by zero
<4>[ 1056.360371]-(7)[7270:insmod]CPU: 7 PID: 7270 Comm: insmod Tainted: G S      W         4.19.191+ #13
<4>[ 1056.361551]-(7)[7270:insmod]Hardware name: MT6877V/TZA (DT)
<4>[ 1056.362295]-(7)[7270:insmod]Call trace:
<4>[ 1056.362836]-(7)[7270:insmod] dump_backtrace.cfi_jt+0x0/0x4
<4>[ 1056.363578]-(7)[7270:insmod] dump_stack+0xb8/0xf0
<4>[ 1056.364220]-(7)[7270:insmod] ubsan_epilogue+0x14/0xb8
<4>[ 1056.364900]-(7)[7270:insmod] __ubsan_handle_divrem_overflow+0x1c8/0x1f0
<4>[ 1056.365777]-(7)[7270:insmod] test_ubsan_divrem_overflow+0x70/0x78 [test_ubsan]
<4>[ 1056.366731]-(7)[7270:insmod] init_module+0x20/0xff0 [test_ubsan]
<4>[ 1056.367535]-(7)[7270:insmod] do_one_initcall+0x184/0x360
<4>[ 1056.368251]-(7)[7270:insmod] do_init_module+0x5c/0x27c
<4>[ 1056.368940]-(7)[7270:insmod] load_module+0x3190/0x3860
<4>[ 1056.369631]-(7)[7270:insmod] __arm64_sys_finit_module+0xb0/0xe0
<4>[ 1056.370422]-(7)[7270:insmod] el0_svc_common+0xb0/0x194
<4>[ 1056.371113]-(7)[7270:insmod] el0_svc_handler+0x60/0x78
<4>[ 1056.371806]-(7)[7270:insmod] el0_svc+0x8/0x300
<3>[ 1056.372409]-(7)[7270:insmod]================================================================================
<4>[ 1056.373776]-(7)[7270:insmod]ubsan_epilogue: 3 callbacks suppressed
<3>[ 1056.373784]-(7)[7270:insmod]================================================================================
<3>[ 1056.375878]-(7)[7270:insmod]UBSAN: Undefined behaviour in /work/junfang1/work/0_code/s0-trank-user/kernel-4.19/lib/test_ubsan.c:48:11
<3>[ 1056.377425]-(7)[7270:insmod]variable length array bound value -1 <= 0
<4>[ 1056.378278]-(7)[7270:insmod]CPU: 7 PID: 7270 Comm: insmod Tainted: G S      W         4.19.191+ #13
<4>[ 1056.379456]-(7)[7270:insmod]Hardware name: MT6877V/TZA (DT)
<4>[ 1056.380199]-(7)[7270:insmod]Call trace:
<4>[ 1056.380732]-(7)[7270:insmod] dump_backtrace.cfi_jt+0x0/0x4
<4>[ 1056.381466]-(7)[7270:insmod] dump_stack+0xb8/0xf0
<4>[ 1056.382104]-(7)[7270:insmod] ubsan_epilogue+0x14/0xb8
<4>[ 1056.382782]-(7)[7270:insmod] __ubsan_handle_vla_bound_not_positive+0xc4/0xc8
<4>[ 1056.383713]-(7)[7270:insmod] test_ubsan_vla_bound_not_positive+0x38/0x3c [test_ubsan]
<4>[ 1056.384742]-(7)[7270:insmod] init_module+0x20/0xff0 [test_ubsan]
<4>[ 1056.385543]-(7)[7270:insmod] do_one_initcall+0x184/0x360
<4>[ 1056.386254]-(7)[7270:insmod] do_init_module+0x5c/0x27c
<4>[ 1056.386944]-(7)[7270:insmod] load_module+0x3190/0x3860
<4>[ 1056.387633]-(7)[7270:insmod] __arm64_sys_finit_module+0xb0/0xe0
<4>[ 1056.388422]-(7)[7270:insmod] el0_svc_common+0xb0/0x194
<4>[ 1056.389112]-(7)[7270:insmod] el0_svc_handler+0x60/0x78
<4>[ 1056.389801]-(7)[7270:insmod] el0_svc+0x8/0x300
<3>[ 1056.390403]-(7)[7270:insmod]================================================================================
<3>[ 1056.391705]-(7)[7270:insmod]================================================================================
<3>[ 1056.392980]-(7)[7270:insmod]UBSAN: Undefined behaviour in /work/junfang1/work/0_code/s0-trank-user/kernel-4.19/lib/test_ubsan.c:58:7
<3>[ 1056.394516]-(7)[7270:insmod]shift exponent -1 is negative
<4>[ 1056.395237]-(7)[7270:insmod]CPU: 7 PID: 7270 Comm: insmod Tainted: G S      W         4.19.191+ #13
<4>[ 1056.396414]-(7)[7270:insmod]Hardware name: MT6877V/TZA (DT)
<4>[ 1056.397157]-(7)[7270:insmod]Call trace:
<4>[ 1056.397685]-(7)[7270:insmod] dump_backtrace.cfi_jt+0x0/0x4
<4>[ 1056.398418]-(7)[7270:insmod] dump_stack+0xb8/0xf0
<4>[ 1056.399054]-(7)[7270:insmod] ubsan_epilogue+0x14/0xb8
<4>[ 1056.399732]-(7)[7270:insmod] __ubsan_handle_shift_out_of_bounds+0x30c/0x328
<4>[ 1056.400651]-(7)[7270:insmod] test_ubsan_shift_out_of_bounds+0x3c/0x40 [test_ubsan]
<4>[ 1056.401645]-(7)[7270:insmod] init_module+0x20/0xff0 [test_ubsan]
<4>[ 1056.402444]-(7)[7270:insmod] do_one_initcall+0x184/0x360
<4>[ 1056.403154]-(7)[7270:insmod] do_init_module+0x5c/0x27c
<4>[ 1056.403843]-(7)[7270:insmod] load_module+0x3190/0x3860
<4>[ 1056.404532]-(7)[7270:insmod] __arm64_sys_finit_module+0xb0/0xe0
<4>[ 1056.405319]-(7)[7270:insmod] el0_svc_common+0xb0/0x194
<4>[ 1056.406008]-(7)[7270:insmod] el0_svc_handler+0x60/0x78
<4>[ 1056.406697]-(7)[7270:insmod] el0_svc+0x8/0x300
<3>[ 1056.407298]-(7)[7270:insmod]================================================================================
<3>[ 1056.408605]-(7)[7270:insmod]================================================================================
<3>[ 1056.409880]-(7)[7270:insmod]UBSAN: Undefined behaviour in /work/junfang1/work/0_code/s0-trank-user/kernel-4.19/lib/test_ubsan.c:66:2
<3>[ 1056.411416]-(7)[7270:insmod]index 5 is out of range for type 'volatile int [i]'
<4>[ 1056.412375]-(7)[7270:insmod]CPU: 7 PID: 7270 Comm: insmod Tainted: G S      W         4.19.191+ #13
<4>[ 1056.413552]-(7)[7270:insmod]Hardware name: MT6877V/TZA (DT)
<4>[ 1056.414295]-(7)[7270:insmod]Call trace:
<4>[ 1056.414823]-(7)[7270:insmod] dump_backtrace.cfi_jt+0x0/0x4
<4>[ 1056.415555]-(7)[7270:insmod] dump_stack+0xb8/0xf0
<4>[ 1056.416189]-(7)[7270:insmod] ubsan_epilogue+0x14/0xb8
<4>[ 1056.416868]-(7)[7270:insmod] __ubsan_handle_out_of_bounds+0xcc/0xd0
<4>[ 1056.417699]-(7)[7270:insmod] test_ubsan_out_of_bounds+0xb8/0xbc [test_ubsan]
<4>[ 1056.418627]-(7)[7270:insmod] init_module+0x20/0xff0 [test_ubsan]
<4>[ 1056.419424]-(7)[7270:insmod] do_one_initcall+0x184/0x360
<4>[ 1056.420135]-(7)[7270:insmod] do_init_module+0x5c/0x27c
<4>[ 1056.420824]-(7)[7270:insmod] load_module+0x3190/0x3860
<4>[ 1056.421513]-(7)[7270:insmod] __arm64_sys_finit_module+0xb0/0xe0
<4>[ 1056.422300]-(7)[7270:insmod] el0_svc_common+0xb0/0x194
<4>[ 1056.422989]-(7)[7270:insmod] el0_svc_handler+0x60/0x78
<4>[ 1056.423679]-(7)[7270:insmod] el0_svc+0x8/0x300

四 代码

UBSAN主要利用  就是代码插桩的方式,在关键的地方插入 代码跳转进行检测,以4.19为例:

反汇编一个函数:
0000000000000134 <test_ubsan_divrem_overflow$ac29f208fd07f28460a5dd7ae18fd394>:
 134:        d100c3ff         sub        sp, sp, #0x30
 138:        a9027bfd         stp        x29, x30, [sp,#32]
 13c:        910083fd         add        x29, sp, #0x20
 140:        52800208         mov        w8, #0x10                          // #16
 144:        b81fc3a8         stur        w8, [x29,#-4]
 148:        b81f83bf         stur        wzr, [x29,#-8]
 14c:        b85f83a8         ldur        w8, [x29,#-8]
 150:        b85fc3a9         ldur        w9, [x29,#-4]
 154:        1280000a         mov        w10, #0xffffffff                    // #-1
 158:        52b0000b         mov        w11, #0x80000000                    // #-2147483648
 15c:        eb0a011f         cmp        x8, x10
 160:        1a9f07ea         cset        w10, ne
 164:        eb0b013f         cmp        x9, x11
 168:        1a9f07eb         cset        w11, ne
 16c:        34000108         cbz        w8, 18c <test_ubsan_divrem_overflow$ac29f208fd07f28460a5dd7ae18fd394+0x58>
 170:        2a0b014a         orr        w10, w10, w11
 174:        360000ca         tbz        w10, #0, 18c <test_ubsan_divrem_overflow$ac29f208fd07f28460a5dd7ae18fd394+0x58>
 178:        1ac80d28         sdiv        w8, w9, w8
 17c:        b81fc3a8         stur        w8, [x29,#-4]
 180:        a9427bfd         ldp        x29, x30, [sp,#32]
 184:        9100c3ff         add        sp, sp, #0x30
 188:        d65f03c0         ret =》正常情况,直接就return了
 18c:        90000000         adrp        x0, 0 <__cfi_check>
 190:        91000000         add        x0, x0, #0x0
 194:        aa0903e1         mov        x1, x9
 198:        aa0803e2         mov        x2, x8
 19c:        a900a7e8         stp        x8, x9, [sp,#8]
 1a0:        94000000         bl        0 <__ubsan_handle_divrem_overflow> =》如果走入异常插桩code
 1a4:        a940a7e8         ldp        x8, x9, [sp,#8]
 1a8:        17fffff4         b        178 <test_ubsan_divrem_overflow$ac29f208fd07f28460a5dd7ae18fd394+0x44>

__ubsan_handle_divrem_overflow函数实现在:
lib/ubsan.c里面:

void __ubsan_handle_divrem_overflow(struct overflow_data *data,
                                void *lhs, void *rhs)
{
        unsigned long flags;
        char rhs_val_str[VALUE_LENGTH];

        if (suppress_report(&data->location))
                return;

        ubsan_prologue(&data->location, &flags); =》这里面会打印相关log

        val_to_string(rhs_val_str, sizeof(rhs_val_str), data->type, rhs);

        if (type_is_signed(data->type) && get_signed_val(data->type, rhs) == -1)
                pr_err("division of %s by -1 cannot be represented in type %s\n",
                        rhs_val_str, data->type->type_name);
        else
                pr_err("division by zero\n");

        ubsan_epilogue(&flags);
}
EXPORT_SYMBOL(__ubsan_handle_divrem_overflow);

static void ubsan_prologue(struct source_location *location,
                        unsigned long *flags)
{
        current->in_ubsan++;
        spin_lock_irqsave(&report_lock, *flags);

        pr_err("========================================"
                "========================================\n");
        print_source_location("UBSAN: Undefined behaviour in", location);
}

static void ubsan_epilogue(unsigned long *flags)
{
        int cpu;
        struct rq *rq;

        dump_stack();
        pr_err("========================================"
                "========================================\n");
        spin_unlock_irqrestore(&report_lock, *flags);
        current->in_ubsan--;

        cpu = raw_smp_processor_id();
        rq = cpu_rq(cpu);
        if (!raw_spin_is_locked(&rq->lock)) { =》最后基本上都会走到这边,所以大多场景都是warning log呈现
                /* AEE Kernel API Dump for UBSan */
                aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_DEFAULT,
                        "UBSan error",
                        "[UBSan report]");
        } else {
                BUG(); =》可以强制走这边,这样遇到一些不合法行为就可以出发bug
        }

}

5.10默认也不会触发bug,需要添加code
146 static void ubsan_epilogue(void)
147 {
148   dump_stack();
149   pr_err("========================================"
150     "========================================\n");
151
152   current->in_ubsan--;
153  + panic_on_warn = 1; =》新增触发panic添加的
154   if (panic_on_warn) { =》如果希望触发panic,需要dts里面传入panic_on_warn
155     /*
156      * This thread may hit another WARN() in the panic path.
157      * Resetting this prevents additional WARN() from panicking the
158      * system on this thread.  Other threads are blocked by the
159      * panic_mutex in panic().
160      */
161     panic_on_warn = 0;
162     panic("panic_on_warn set ...\n");
163   }
164 }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值