linux kernel 内存踩踏之KASAN_SW_TAGS(二)

news2024/11/24 9:33:29

一、背景

linux kernel 内存踩踏之KASAN(一)_kasan版本跟hasan版本区别-CSDN博客

上一篇简单介绍了标准版本的KASAN使用方法和实现,这里将介绍KASAN_SW_TAGS和KASAN_HW_TAGS

的使用和背后基本原理,下图是三种方式的对比:

Overhead typeMTEKASAN_SW_TAG(kernel)/HWASan(userspace)KASAN(kernel)/ASan(userspace)
RAM3%-5%10%-35%~2x
CPU0%-5%~2x~2x
Code size2%-4%40%-50%50%-2x

上表数据来源google的 userspace下MTE、HWASAN和ASAN的测试数据,内核的部分没有找到准确的对比数据,应该也差不多,套用上表。

二、KASAN_SW_TAGS使能相关配置

关键差异:CONFIG_KASAN_SW_TAGS=y

/sys/kernel/debug # zcat /proc/config.gz | grep -i kasan
CONFIG_KASAN_SHADOW_OFFSET=0xefff800000000000 //这个offset和普通版本kasan有差异
CONFIG_DRIVER_KASAN_TEST=m
CONFIG_HAVE_ARCH_KASAN=y
CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
CONFIG_HAVE_ARCH_KASAN_HW_TAGS=y
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
CONFIG_CC_HAS_KASAN_GENERIC=y
CONFIG_CC_HAS_KASAN_SW_TAGS=y
CONFIG_KASAN=y
CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y
# CONFIG_KASAN_GENERIC is not set
CONFIG_KASAN_SW_TAGS=y     //SW_TAGS 版本kasan
# CONFIG_KASAN_HW_TAGS is not set
CONFIG_KASAN_OUTLINE=y
# CONFIG_KASAN_INLINE is not set
CONFIG_KASAN_STACK=y      //stack kasan检测,如局部变量,局部数组等操作引起的内存踩踏
CONFIG_KASAN_VMALLOC=y    //vmalloc kasan检测,使用vmalloc申请内存的内存踩踏

三、KASAN_SW_TAGS基本原理

SW_TAG shadow的原理就是利用ARM64的TBI(Top Byte Ignore)特性,在最高byte存储指针存储能访问内存区域的shadow标记,利用指针操作地址时就会检查指针的shadow和操作地址的的shadow是否一致,不一致则触发内存异常并报告原因。

sw_tag 信息

#define KASAN_PAGE_FREE		KASAN_TAG_INVALID
#define KASAN_PAGE_REDZONE	KASAN_TAG_INVALID
#define KASAN_SLAB_REDZONE	KASAN_TAG_INVALID
#define KASAN_SLAB_FREE		KASAN_TAG_INVALID
#define KASAN_VMALLOC_INVALID	KASAN_TAG_INVALID /* only used for SW_TAGS */

#define KASAN_TAG_KERNEL	0xFF /* native kernel pointers tag */
#define KASAN_TAG_INVALID	0xFE /* inaccessible memory tag */
#define KASAN_TAG_MAX		0xFD /* maximum value for random tags */

#ifdef CONFIG_KASAN_HW_TAGS
#define KASAN_TAG_MIN		0xF0 /* minimum value for random tags */
#else
#define KASAN_TAG_MIN		0x00 /* minimum value for random tags */
#endif

SW_TAG的在指针内存分配时指定,内存有效时随机生成的有效值范围:0x00 ~ 0xFD, 0xFE用来表示free或者redzone等标记;

下图是arm64 48位 pagesize 4K的内存映射图,shadow的16TB映射整个内核空间:

CONFIG_KASAN_SHADOW_OFFSET=0xefff800000000000

计算方法:

CONFIG_KASAN_SHADOW_OFFSET= KASAN_SHADOW_START - KERNEL_ADDR_START >>4

= 0xffff700000000000 - ( 0xffff000000000000 >> 4) = 0xefff800000000000

有了这个kasan_shadow_offset, 后面我们需要获取一个内核地址对应的shadow 位置,只需要通过公式:

kernel_addr >> 4 + CONFIG_KASAN_SHADOW_OFFSET = kernel_addr对应的shadow_addr

四、sw_tag生成和验证流程分析

4.1 设置sw_tag

还是用kmalloc为例:

kmalloc
-->kmalloc_trace
     -->__kmem_cache_alloc_node
         -->slab_alloc_node
              -->slab_post_alloc_hook
                   -->kasan_slab_alloc

void * __must_check __kasan_slab_alloc(struct kmem_cache *cache,
					void *object, gfp_t flags, bool init)
{
	....

	/*
	 * Generate and assign random tag for tag-based modes.
	 * Tag is ignored in set_tag() for the generic mode.
	 */
	tag = assign_tag(cache, object, false);    // 1、随机数分配tag
	tagged_object = set_tag(object, tag);      // 2、设置tag 到指针 

	/*
	 * Unpoison the whole object.
	 * For kmalloc() allocations, kasan_kmalloc() will do precise poisoning.
	 */
	kasan_unpoison(tagged_object, cache->object_size, init); 
        //3、从分配地址和size确认tag是否需要更新,如果和上面新分配的tag值不同,则更新tag

	/* Save alloc info (if possible) for non-kmalloc() allocations. */
	if (kasan_stack_collection_enabled() && !is_kmalloc_cache(cache))
		kasan_save_alloc_info(cache, tagged_object, flags);
        //4、存储分配stack

	return tagged_object;
}

#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS)
#define __tag_shifted(tag)  ((u64)(tag) << 56)
#define __tag_reset(addr)   __untagged_addr(addr)
#define __tag_get(addr)     (__u8)((u64)(addr) >> 56)

流程如下:

1、分配tag随机数(0x00~0xFD)

2、给指针最高byte存储新 tag

3、根据指针tag和分配的长度,检查 ptr>>4 + shadow_offset处存储的tag值是否一致,不一致则更新

4、返回指针(高byte为tag)

4.2 检查指针

检查指针即使是在kasan_check_range中进行的,

(gdb) disassemble __hwasan_store1_noabort
Dump of assembler code for function __hwasan_store1_noabort:
   0xffff8000803d6f08 <+0>:	paciasp
   0xffff8000803d6f0c <+4>:	stp	x29, x30, [sp, #-16]!
   0xffff8000803d6f10 <+8>:	xpaclri
   0xffff8000803d6f14 <+12>:	mov	w2, #0x1                   	// #1
   0xffff8000803d6f18 <+16>:	mov	x29, sp
   0xffff8000803d6f1c <+20>:	mov	x3, x30
   0xffff8000803d6f20 <+24>:	mov	x1, #0x1                   	// #1
   0xffff8000803d6f24 <+28>:	bl	0xffff8000803d6e38 <kasan_check_range>
   0xffff8000803d6f28 <+32>:	ldp	x29, x30, [sp], #16
   0xffff8000803d6f2c <+36>:	autiasp
   0xffff8000803d6f30 <+40>:	ret

bool kasan_check_range(const void *addr, size_t size, bool write,
			unsigned long ret_ip)
{
	u8 tag;
	u8 *shadow_first, *shadow_last, *shadow;
	void *untagged_addr;

	if (unlikely(size == 0))
		return true;

	if (unlikely(addr + size < addr))
		return !kasan_report(addr, size, write, ret_ip);

	tag = get_tag((const void *)addr);  //1、获取指针tag

	/*
	 * Ignore accesses for pointers tagged with 0xff (native kernel
	 * pointer tag) to suppress false positives caused by kmap.
	 *
	 * Some kernel code was written to account for archs that don't keep
	 * high memory mapped all the time, but rather map and unmap particular
	 * pages when needed. Instead of storing a pointer to the kernel memory,
	 * this code saves the address of the page structure and offset within
	 * that page for later use. Those pages are then mapped and unmapped
	 * with kmap/kunmap when necessary and virt_to_page is used to get the
	 * virtual address of the page. For arm64 (that keeps the high memory
	 * mapped all the time), kmap is turned into a page_address call.

	 * The issue is that with use of the page_address + virt_to_page
	 * sequence the top byte value of the original pointer gets lost (gets
	 * set to KASAN_TAG_KERNEL (0xFF)).
	 */
	if (tag == KASAN_TAG_KERNEL)
		return true;

	untagged_addr = kasan_reset_tag((const void *)addr); //2、将带tag指针转换成指针
	if (unlikely(!addr_has_metadata(untagged_addr)))
		return !kasan_report(addr, size, write, ret_ip);
	shadow_first = kasan_mem_to_shadow(untagged_addr);  //3、提取对应地址的sw_tag shadow值
	shadow_last = kasan_mem_to_shadow(untagged_addr + size - 1); //4、提取访问地址尾部的sw_tag shadow值
	for (shadow = shadow_first; shadow <= shadow_last; shadow++) {
		if (*shadow != tag) {                              //5、遍历检查shadow tag和指针tag是否匹配
			return !kasan_report(addr, size, write, ret_ip);
		}
	}

	return true;
}

如上面代码逻辑,检查tag的流程如下:

1、传入指针和内存操作的长度

2、获取指针tag

3、将带tag指针转换成指针

4、提取对应地址的sw_tag shadow值

5、提取访问地址尾部的sw_tag shadow值

6、遍历检查shadow tag和指针tag是否匹配

五、利用 test driver程序验证

还是上一篇的例子(linux kernel 内存踩踏之KASAN(一)_kasan版本跟hasan版本区别-CSDN博客):

例子日志:

/test # echo 0 > /dev/kasan_test 
[  150.681333] kmalloc_oob_right d2ff000003de9c00
[  150.691414] ==================================================================
[  150.693254] BUG: KASAN: invalid-access in kmalloc_oob_right.constprop.0+0x4c/0x6c [kasan_driver]
[  150.695503] Write of size 1 at addr d2ff000003de9c81 by task sh/181
[  150.696332] Pointer tag: [d2], memory tag: [fe]
[  150.696848] 
[  150.697599] CPU: 1 PID: 181 Comm: sh Tainted: G    B            N 6.6.1-g00ad0b878692 #18
[  150.698596] Hardware name: linux,dummy-virt (DT)
[  150.699352] Call trace:
[  150.699744]  dump_backtrace+0x90/0xe8
[  150.700697]  show_stack+0x18/0x24
[  150.701221]  dump_stack_lvl+0x48/0x60
[  150.701716]  print_report+0x15c/0x54c
[  150.702204]  kasan_report+0xc4/0x108
[  150.702678]  kasan_check_range+0x80/0xa4
[  150.703198]  __hwasan_store1_noabort+0x20/0x2c
[  150.703749]  kmalloc_oob_right.constprop.0+0x4c/0x6c [kasan_driver]
[  150.704593]  kasan_test_case+0x40/0xc0 [kasan_driver]
[  150.705354]  kasan_testcase_write+0x88/0x130 [kasan_driver]
[  150.706170]  vfs_write+0x144/0x4d8
[  150.706667]  ksys_write+0xe0/0x1b0
[  150.707166]  __arm64_sys_write+0x44/0x58
[  150.707729]  invoke_syscall+0x60/0x17c
[  150.708246]  el0_svc_common.constprop.0+0x78/0x13c
[  150.708842]  do_el0_svc+0x30/0x40
[  150.709462]  el0_svc+0x40/0x100
[  150.709973]  el0t_64_sync_handler+0x120/0x12c
[  150.710410]  el0t_64_sync+0x190/0x194
[  150.710946] 
[  150.711219] The buggy address belongs to the object at ffff000003de9c80
[  150.711219]  which belongs to the cache kmalloc-128 of size 128
[  150.712055] The buggy address is located 1 bytes inside of
[  150.712055]  128-byte region [ffff000003de9c80, ffff000003de9d00)
[  150.712749] 
[  150.713093] The buggy address belongs to the physical page:
[  150.713741] page:(____ptrval____) refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x43de9
[  150.714943] flags: 0x3fffc0000000800(slab|node=0|zone=0|lastcpupid=0xffff|kasantag=0x0)
[  150.715955] page_type: 0xffffffff()
[  150.716752] raw: 03fffc0000000800 82ff000003402600 dead000000000122 0000000000000000
[  150.717349] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000
[  150.717938] page dumped because: kasan: bad access detected
[  150.718358] 
[  150.718602] Memory state around the buggy address:
[  150.719208]  ffff000003de9a00: 2c 2c 2c 2c 2c 2c 2c fe 28 28 28 28 28 28 28 28
[  150.719744]  ffff000003de9b00: 66 66 66 66 66 66 66 66 f8 f8 f8 f8 f8 f8 f8 f8
[  150.720267] >ffff000003de9c00: d2 d2 d2 d2 d2 d2 d2 d2 fe fe fe fe fe fe fe fe
[  150.720886]                                            ^
[  150.721635]  ffff000003de9d00: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
[  150.722291]  ffff000003de9e00: fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
[  150.722978] ==================================================================
[  150.724556] kasan_test_case type 0

调试:

(gdb) disassemble 
Dump of assembler code for function kmalloc_oob_right:
0xffff80007b160300 <+0>:	paciasp
   0xffff80007b160304 <+4>:	adrp	x0, 0xffff8000822ce000 <cpu_ops+432>
   0xffff80007b160308 <+8>:	stp	x29, x30, [sp, #-32]!
   0xffff80007b16030c <+12>:	mov	x2, #0x80                  	// #128
   0xffff80007b160310 <+16>:	mov	w1, #0xcc0                 	// #3264
   0xffff80007b160314 <+20>:	mov	x29, sp
   0xffff80007b160318 <+24>:	ldr	x0, [x0, #3648]
   0xffff80007b16031c <+28>:	str	x19, [sp, #16]
   0xffff80007b160320 <+32>:	bl	0xffff80008033c920 <kmalloc_trace>  //1.指针设置sw tag 
=> 0xffff80007b160324 <+36>:	mov	x2, x0         //断点
   0xffff80007b160328 <+40>:	adrp	x1, 0xffff80007b164000
   0xffff80007b16032c <+44>:	add	x1, x1, #0x110
   0xffff80007b160330 <+48>:	add	x1, x1, #0x48
   0xffff80007b160334 <+52>:	mov	x19, x0
   0xffff80007b160338 <+56>:	adrp	x0, 0xffff80007b164000
   0xffff80007b16033c <+60>:	add	x0, x0, #0x50
   0xffff80007b160340 <+64>:	bl	0xffff80008015d280 <_printk>
   0xffff80007b160344 <+68>:	add	x0, x19, #0x81
   0xffff80007b160348 <+72>:	bl	0xffff8000803d6f08 <__hwasan_store1_noabort> 

                                                             //2.检查指针访问的内存是否合法
   0xffff80007b16034c <+76>:	mov	w1, #0x79                  	// #121
   0xffff80007b160350 <+80>:	strb	w1, [x19, #129]
   0xffff80007b160354 <+84>:	mov	x0, x19
   0xffff80007b160358 <+88>:	bl	0xffff80008033da7c <kfree>
   0xffff80007b16035c <+92>:	ldr	x19, [sp, #16]
   0xffff80007b160360 <+96>:	ldp	x29, x30, [sp], #32
   0xffff80007b160364 <+100>:	autiasp
   0xffff80007b160368 <+104>:	ret


1、在上图断点处检查kmalloc_trace分配的指针值
(gdb) p /x $x0
$7 = 0xd2ff000003de9c00

2、利用计算公式,寻找对应指针地址存储的sw_tag shadow值:
ptr >> 4 + kasan_offset = kasan sw shadow

计算时记得将指针头替换成0xff
即:0xffff000003de9c00 >> 4 + 0xefff800000000000 = 0xFFFF7000003DE9C0
(gdb) x /30b 0xFFFF7000003DE9C0
0xffff7000003de9c0: 0xd2 0xd2 0xd2 0xd2 0xd2 0xd2 0xd2 0xd2
0xffff7000003de9c8: 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe
0xffff7000003de9d0: 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe
0xffff7000003de9d8: 0xfe 0xfe 0xfe 0xfe 0xfe 0xfe

上面的0xd2代表指针指向有效空间的范围,8 个0xd2, 由于sw_tag是每16个byte对应一个byte, 这里表示这个指针有效的范围是8*16 =128字节,正好和测试用例 kmalloc(128) 对应;

3、kasan report原因是我们访问的指针对应地址长度为0x81, 访问到了129字节处,这里对应的tag为0xfe,最后上报异常如下:

[ 150.695503] Write of size 1 at addr d2ff000003de9c81 by task sh/181
[ 150.696332] Pointer tag: [d2], memory tag: [fe]

六、总结

从KASAN 和 KASAN_SW_TAGS的对比来看

类型shadow内存占用cpu占用优缺点
KASAN1/8复杂,每次内存访问,需要计算对比shadow值定位准确,8byte内的踩踏也能检测;32位/64位均能使用
KASAN_SW_TAGS1/16每次内存访问,需要计算对比shadow值16 byte内的踩踏无法区分, 仅64才能使用(因为依赖arm64 TBI feature)

缺点1:16byte内的踩踏无法检测

KASAN_SW_TAGS的tag标记范围是16byte, 打一个比方:

ptr = kmalloc(129);

ptr[129] = 0; // 此时不会报错,无法检测到越界,实际上 pt[129] ~ ptr[128 + 16 -1] 内存越界操作都无法检测出来,因为这16字节的tag都是一样的,tag本身没有16byte內分配大小的记录;

缺点2:tag虽然是随机值,但是连续内存存在随机tag值一致导致漏检测可能

比如,

ptr1= kmalloc(128);

ptr2= kmalloc(128);

假如ptr1的tag是0x12, ptr1的tag也是0x12, 同时它们的内存连续,那么ptr1[128] = 0的操作就不会报错;

漏检测概率:由于0xfe和0xff两个值不会作为tag随机数, 连续内存生成重复tag的概率为1/254 * 1/254。

参考:

Android Native | 内存问题的终极武器--MTE

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1452717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++11---(1)

目录 一、C11简介 二、列表初始化 2.1、{ } 初始化 三、变量类型推导 3.1、auto 3.2、decltype 为什么需要decltype 四、final和override 4.1、final 4.2、override 五、默认成员函数控制 5.1、default修饰函数 5.2、delete修饰函数 六、nullptr 一、C11简介 C11是…

JavaScript_00001_00000

contents 简介变量与数据类型自动类型转换强制类型转换 简介 变量与数据类型 根据变量定义的范围不同&#xff0c;变量有全局变量和局部变量之分。直接定义的变量是全局变量&#xff0c;全局变量可以被所有的脚本访问&#xff1b;在函数里定义的变量称为局部变量&#xff0c;…

17-k8s控制器资源-job控制

job控制器&#xff1a;就是一次性任务的pod控制器&#xff0c;pod完成作业后不会重启&#xff0c;其重启策略是&#xff1a;Never 1&#xff0c;job控制器案例描述 启动一个pod&#xff0c;执行完成一个事件&#xff0c;然后pod关闭&#xff1b; 事件&#xff1a;计算π的值&a…

【初始RabbitMQ】工作队列的实现

工作队列 工作队列&#xff08;又称为任务队列&#xff09;的主要思想是避免立即执行资源密集型任务&#xff0c;而不得不等待它完成。 相反我们安排任务在之后执行。我们把任务封装为消息并将其发送到队列。在后台运行的工作进 程将弹出任务并最终执行作业。当有多个工作线程…

.NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库

一、效果 记录日志为文档 记录日志到数据库 二、添加NuGet包 三、代码配置 <?xml version"1.0" encoding"utf-8" ?> <log4net><!-- Debug日志 --><appender name"RollingFileDebug" type"log4net.Appender.Roll…

【RL】Value Iteration and Policy Iteration(利用迭代算法求解贝尔曼最优等式)

Lecture 4: Value Iteration and Policy Iteration Value Iteration Algorithm 对于Bellman最优公式&#xff1a; v f ( v ) m a x π ( r γ P π v ) \mathbf{v} f(\mathbf{v}) max_{\pi}(\mathbf{r} \gamma \mathbf{P}_{\pi} \mathbf{v}) vf(v)maxπ​(rγPπ​v) …

Midjourney绘图欣赏系列(一)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子,它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同,Midjourney 是自筹资金且闭源的,因此确切了解其幕后内容尚不清楚。我们知道它严重依赖机器学…

Python教程(26)——Python迭代器和生成器详解

迭代器 Python中的迭代器是一种对象&#xff0c;它可以迭代&#xff08;遍历&#xff09;一个可迭代对象&#xff08;比如列表、元组或字符串&#xff09;的元素。迭代器用于实现迭代器协议&#xff0c;即包含 __iter__() 方法和 __next__() 方法。 迭代器的工作原理是每次调…

2.11题目

#include <stdio.h> int main() { char a; while((a getchar()) ! -1) { if(a > A && a < Z) a32; putchar(ch); } return 0;} ———————————————— 版权声明&#xff1a;本文为博主原创文章…

2024年危险化学品经营单位主要负责人证模拟考试题库及危险化学品经营单位主要负责人理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年危险化学品经营单位主要负责人证模拟考试题库及危险化学品经营单位主要负责人理论考试试题是由安全生产模拟考试一点通提供&#xff0c;危险化学品经营单位主要负责人证模拟考试题库是根据危险化学品经营单位主…

【大模型 数据增强】LLMAAA:使用 LLMs 作为数据标注器

【大模型 数据增强】LLMAAA&#xff1a;使用 LLMs 作为数据标注器 提出背景算法步骤1. LLM作为活跃标注者&#xff08;LLMAAA&#xff09;2. k-NN示例检索与标签表述化3. 活跃学习策略4. 自动重权技术 LLMAAA 框架1. LLM Annotator2. Active Acquisition3. Robust Training 总结…

数据结构对链表的初步认识(一)

已经两天没有更新了&#xff0c;今天就写一篇数据结构的链表吧&#xff0c;巩固自己也传授知识&#xff0c;不知道各位是否感兴趣看看这一篇有关联表的文章。 目录 链表的概念与结构 单向链表的实现 链表各个功能函数 首先我在一周前发布了一篇有关顺序表的文章&#xff0c;…

【Linux系统化学习】缓冲区

目录 缓冲区 一个样例 现象解释 缓冲区存在的位置 缓冲区 在刚开始学习C语言的时候我们就听过缓冲区这个名词&#xff0c;很是晦涩难懂&#xff1b;在Linux下进程退出时也包含缓冲区&#xff0c;因此缓冲区到底是什么&#xff1f;有什么作用&#xff1f; 让我们先从一个小…

斯坦福大学全能家政服务机器人Mobile ALOHA以及“小群体大智慧”Zooids集群机器人

斯坦福大学成功研发出低成本自主进化克隆人类行为和任务的能力全能型家政服务机器人。 原文标题: 【Mobile ALOHA-Learning Bimanual Mobile Manipulation with Low-Cost Whole-Body Teleoperation】 论文链接:【Mobile ALOHA (mobile-aloha.github.io)】。 以及由斯坦福大学…

51单片机项目(32)——基于51单片机的温度检测及控制装置的proteus仿真

1.功能设定 使用DS18B20测定当前温度并实时显示在LCD1602屏幕&#xff0c;使用四个按键设定温度的上限、下限。当温度低于下限时&#xff0c;蜂鸣器报警同时开启升温装置&#xff1b;当温度大于上限时&#xff0c;蜂鸣器报警同时启动降温装置。 仿真图如下&#xff1a; 2.软件设…

【无标题】管理kvm 虚拟机

管理kvm 虚拟机 点击虚拟机 创建新的虚拟机 安装操作系统 设置root密码

中小学信息学奥赛CSP-J认证 CCF非专业级别软件能力认证-入门组初赛模拟题第三套(选择题)

CSP-J入门组初赛模拟练习题第三套 1、以下不是属于国家顶级域名的是 A、.au B、.cn C、.com D、.jp 答案&#xff1a;C 考点分析&#xff1a;主要考查域名相关知识&#xff0c;au是澳大利亚、cn是中国&#xff0c;jp是日本&#xff0c;答案C 2、2个10进制数1111和1010的异…

蓝桥杯 星期计算

思路1 由于2022太大&#xff0c;用double来存储&#xff0c;即(52022 % 7) % 7即可 int num 5;int t (int)(Math.pow(20,22)%7);num t;num%7;System.out.println(num1);思路2 你需要知道 (a * b ) % p a % p * b % p Scanner scan new Scanner(System.in);int num 1;for…

计算机设计大赛 深度学习YOLO抽烟行为检测 - python opencv

文章目录 1 前言1 课题背景2 实现效果3 Yolov5算法3.1 简介3.2 相关技术 4 数据集处理及实验5 部分核心代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习YOLO抽烟行为检测 该项目较为新颖&#xff0c;适合作为竞赛课…

【感知机】感知机(perceptron)学习策略

感知机( perceptron )是二类分类的线性分类模型&#xff0c;其输入为实例的特征向量&#xff0c;输出为实例的类别&#xff0c;取1 和-1二值。感知机对应输入空间(特征空间)中将实例划分为正负两类的分离超平面&#xff0c;是一种判别模型。感知机是神经网络与支持向量机的基础…