Linux 6.6内核内存管理深度解析(十八):KASLR 内核地址空间随机化

引言:攻击者要 ROP,得先知道内核在哪

内核漏洞利用(如 ROP 链)第一步往往是拿到内核里某个函数的地址 ------如果内核每次启动都加载在同一个固定地址 ,攻击者就能硬编码这些地址,漏洞利用变成"开卷考试"。KASLR(Kernel Address Space Layout Randomization,内核地址空间布局随机化) 就是让内核的物理位置 和虚拟布局每次启动都随机,让硬编码的地址失效。

KASLR 其实是两段独立的随机化:

  1. 物理随机化 :内核镜像被解压到哪个物理地址 ,启动时随机选(choose_random_location,compressed 阶段)。
  2. 虚拟随机化 :内核的直接映射区 / vmalloc 区 / vmemmap 区 这三个大虚拟区域的基址 随机(kernel_randomize_memory)。

这条链路:boot stub 选随机物理地址 → 解压 → __startup_64 算 load_delta 重定位页表 → setup_arch 里随机化虚拟布局。


全景图

#mermaid-svg-fb7hH1xmWKptjbKt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fb7hH1xmWKptjbKt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fb7hH1xmWKptjbKt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fb7hH1xmWKptjbKt .error-icon{fill:#552222;}#mermaid-svg-fb7hH1xmWKptjbKt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fb7hH1xmWKptjbKt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fb7hH1xmWKptjbKt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fb7hH1xmWKptjbKt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fb7hH1xmWKptjbKt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fb7hH1xmWKptjbKt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fb7hH1xmWKptjbKt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fb7hH1xmWKptjbKt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fb7hH1xmWKptjbKt .marker.cross{stroke:#333333;}#mermaid-svg-fb7hH1xmWKptjbKt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fb7hH1xmWKptjbKt p{margin:0;}#mermaid-svg-fb7hH1xmWKptjbKt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fb7hH1xmWKptjbKt .cluster-label text{fill:#333;}#mermaid-svg-fb7hH1xmWKptjbKt .cluster-label span{color:#333;}#mermaid-svg-fb7hH1xmWKptjbKt .cluster-label span p{background-color:transparent;}#mermaid-svg-fb7hH1xmWKptjbKt .label text,#mermaid-svg-fb7hH1xmWKptjbKt span{fill:#333;color:#333;}#mermaid-svg-fb7hH1xmWKptjbKt .node rect,#mermaid-svg-fb7hH1xmWKptjbKt .node circle,#mermaid-svg-fb7hH1xmWKptjbKt .node ellipse,#mermaid-svg-fb7hH1xmWKptjbKt .node polygon,#mermaid-svg-fb7hH1xmWKptjbKt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fb7hH1xmWKptjbKt .rough-node .label text,#mermaid-svg-fb7hH1xmWKptjbKt .node .label text,#mermaid-svg-fb7hH1xmWKptjbKt .image-shape .label,#mermaid-svg-fb7hH1xmWKptjbKt .icon-shape .label{text-anchor:middle;}#mermaid-svg-fb7hH1xmWKptjbKt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fb7hH1xmWKptjbKt .rough-node .label,#mermaid-svg-fb7hH1xmWKptjbKt .node .label,#mermaid-svg-fb7hH1xmWKptjbKt .image-shape .label,#mermaid-svg-fb7hH1xmWKptjbKt .icon-shape .label{text-align:center;}#mermaid-svg-fb7hH1xmWKptjbKt .node.clickable{cursor:pointer;}#mermaid-svg-fb7hH1xmWKptjbKt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fb7hH1xmWKptjbKt .arrowheadPath{fill:#333333;}#mermaid-svg-fb7hH1xmWKptjbKt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fb7hH1xmWKptjbKt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fb7hH1xmWKptjbKt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fb7hH1xmWKptjbKt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fb7hH1xmWKptjbKt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fb7hH1xmWKptjbKt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fb7hH1xmWKptjbKt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fb7hH1xmWKptjbKt .cluster text{fill:#333;}#mermaid-svg-fb7hH1xmWKptjbKt .cluster span{color:#333;}#mermaid-svg-fb7hH1xmWKptjbKt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fb7hH1xmWKptjbKt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fb7hH1xmWKptjbKt rect.text{fill:none;stroke-width:0;}#mermaid-svg-fb7hH1xmWKptjbKt .icon-shape,#mermaid-svg-fb7hH1xmWKptjbKt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fb7hH1xmWKptjbKt .icon-shape p,#mermaid-svg-fb7hH1xmWKptjbKt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fb7hH1xmWKptjbKt .icon-shape .label rect,#mermaid-svg-fb7hH1xmWKptjbKt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fb7hH1xmWKptjbKt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fb7hH1xmWKptjbKt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fb7hH1xmWKptjbKt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} compressed 阶段

extract_kernel misc.c:377
choose_random_location

kaslr.c:842 选随机物理地址
find_random_phys_addr :792

扫 e820 找不冲突的随机地址
解压内核到随机物理地址

__decompress misc.c:350
__startup_64 head64.c:179

算 load_delta 修页表
load_delta = physaddr - (text - __START_KERNEL_map)

head64.c:203
把 load_delta 加进各页表项

让内核在随机物理地址正确运行
setup_arch setup.c:1082

kernel_randomize_memory kaslr.c:64
随机化 page_offset_base

vmalloc_base / vmemmap_base
每次启动地址布局都不同

硬编码地址失效

一句话:boot stub choose_random_location 选随机物理地址 → 解压 → __startup_64 算 load_delta 修页表让内核在随机物理地址运行 → setup_arch 里 kernel_randomize_memory 随机化直接映射/vmalloc/vmemmap 虚拟基址 → 每次启动布局都不同。


一、KASLR 是什么:两段独立随机化

先看清 x86-64 的内核虚拟地址布局(L4 分页,几个默认基址):

区域 默认基址(不随机时) 存什么 KASLR 随机?
内核 text __START_KERNEL_map = 0xffffffff80000000(page_64_types.h:50) 内核代码/数据 ❌ 虚拟固定(物理随机)
直接映射 __PAGE_OFFSET_BASE_L4 = 0xffff888000000000(:42) 所有物理内存的线性映射 ✅ page_offset_base
vmalloc __VMALLOC_BASE_L4 = 0xffffc90000000000(pgtable_64_types.h:124) vmalloc/vmap/ioremap(#17) ✅ vmalloc_base
vmemmap __VMEMMAP_BASE_L4 = 0xffffea0000000000(:130) struct page 数组(#1) ✅ vmemmap_base

两段随机化各管一边:

  • 物理 KASLR (CONFIG_RANDOMIZE_BASE):随机化内核镜像的物理加载地址 。但内核 text 虚拟地址固定 在 __START_KERNEL_map------所以"虚拟固定、物理随机"。
  • 虚拟 KASLR (CONFIG_RANDOMIZE_MEMORY):随机化直接映射 / vmalloc / vmemmap 的虚拟基址。它们的物理地址由硬件决定,所以"虚拟随机、物理固定"。

这两段是互补的 :内核 text 虚拟地址固定(__START_KERNEL_map),但它的物理页是随机的;直接映射区物理地址固定(硬件决定的),但虚拟基址随机。攻击者无论从哪头突破,另一头仍是随机的。


二、物理随机化:choose_random_location

物理 KASLR 发生在内核还没解压、还在 compressed boot stub 阶段 。extract_kernel(misc.c:377)先调 choose_random_location(kaslr.c:842)选地址,再 __decompress(:350)解压:

c 复制代码
// choose_random_location(arch/x86/boot/compressed/kaslr.c:842)------ 关键片段
void choose_random_location(unsigned long input, ...,
			    unsigned long *output, unsigned long output_size,
			    unsigned long *virt_addr)
{
	if (cmdline_find_option_bool("nokaslr")) {      // ① nokaslr 禁用
		warn("KASLR disabled: 'nokaslr' on cmdline.");
		return;
	}
	...
	mem_avoid_init(input, input_size, *output);      // ② 记录"不能放"的区间(:863)

	min_addr = min(*output, 512UL << 20);            // ③ 随机下限(:870)
	min_addr = ALIGN(min_addr, CONFIG_PHYSICAL_ALIGN);  // 2MB 对齐

	random_addr = find_random_phys_addr(min_addr, output_size);   // ④ 扫 e820 找随机物理地址(:875)
	if (!random_addr)
		warn("Physical KASLR disabled: no suitable memory region!");
	else if (*output != random_addr)
		*output = random_addr;                       // 更新物理加载地址

	if (IS_ENABLED(CONFIG_X86_64))
		random_addr = find_random_virt_addr(LOAD_PHYSICAL_ADDR, output_size);  // ⑤ 随机虚拟地址(:887)
	*virt_addr = random_addr;
}

find_random_phys_addr(:792)→ process_e820_entries(:772)遍历 e820 内存表,用 mem_avoid_overlap(:432)排除掉不能覆盖的区间 ------内核自己、boot_params、cmdline、initrd、固件保留区等(mem_avoid_init :383 记录的)。剩下的可用区间里,slots_fetch_random(:556)随机挑一个 2MB 对齐的槽位(CONFIG_PHYSICAL_ALIGN)放内核镜像。

Why 物理 KASLR 在 compressed 阶段就定 :内核镜像必须在解压前就确定落到哪个物理地址(解压是往物理地址写数据)。而这时真正的内核还没跑起来,只有 boot stub 能用------所以选地址的逻辑放在 compressed 里,选完直接解压过去。这也是为什么 nokaslr 要在这里检查(:850)。


三、虚拟随机化:kernel_randomize_memory

物理 KASLR 只随机了内核镜像本身的位置。真正启动后(setup_arch,setup.c:1082),kernel_randomize_memory(mm/kaslr.c:64)随机化三个大虚拟区域的基址:

c 复制代码
// kaslr_regions[](arch/x86/mm/kaslr.c:51)------ 要随机化的三个虚拟区域
static __initdata struct kaslr_memory_region {
	unsigned long *base;
	unsigned long size_tb;
} kaslr_regions[] = {
	{ &page_offset_base, 0 },   // 直接映射区
	{ &vmalloc_base, 0 },       // vmalloc 区
	{ &vmemmap_base, 0 },       // vmemmap 区
};

// kernel_randomize_memory(arch/x86/mm/kaslr.c:64)------ 关键片段
void __init kernel_randomize_memory(void)
{
	vaddr_start = pgtable_l5_enabled() ? __PAGE_OFFSET_BASE_L5 : __PAGE_OFFSET_BASE_L4;  // :73
	...
	kaslr_regions[0].size_tb = 1 << (MAX_PHYSMEM_BITS - TB_SHIFT);   // 直接映射区大小(:88)
	kaslr_regions[1].size_tb = VMALLOC_SIZE_TB;                      // vmalloc 区 32TB(:89)
	... // vmemmap 大小 = struct page 数组大小(:107-109)

	/* 三个区之间剩下的空间就是可用的"随机熵" */
	remain_entropy = vaddr_end - vaddr_start;                        // :112
	for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++)
		remain_entropy -= get_padding(&kaslr_regions[i]);

	for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) {                // 逐个随机化
		entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i);
		prandom_bytes_state(&rand_state, &rand, sizeof(rand));
		entropy = (rand % (entropy + 1)) & PUD_MASK;                 // 随机 + PUD 对齐(:127)
		vaddr += entropy;
		*kaslr_regions[i].base = vaddr;                              // 写入随机基址(:129)
		vaddr += get_padding(&kaslr_regions[i]);
		vaddr = round_up(vaddr + 1, PUD_SIZE);                       // 跳过本区 + 对齐
		remain_entropy -= entropy;
	}
}

核心:三个虚拟区域(直接映射/vmalloc/vmemmap)保持原有顺序,但在它们之间和前后随机插入空隙 ,让每个区的基址都落到一个 1GB(PUD_SIZE)对齐的随机位置。结果就是 page_offset_base/vmalloc_base/vmemmap_base 每次启动不同------直接映射区的基址不再固定是 0xffff888000000000。

Why 直接映射区要随机 :直接映射(page_offset)是内核访问所有物理内存 的线性窗口,virt = page_offset_base + phys。如果 page_offset_base 固定,攻击者只要能泄漏任意一个内核数据地址,就能反推物理页、进而算到任意对象地址。随机化 page_offset_base 就断掉了"物理地址 → 虚拟地址"这条固定换算。这也是为什么 kaslr_regions 的注释(kaslr.c:45-46)强调"列表按虚拟地址排序,随机化后顺序保持"------顺序不能乱,只是整体错位。


四、__startup_64:load_delta 重定位

物理 KASLR 选完随机地址后,问题来了:内核编译时假设自己加载在 LOAD_PHYSICAL_ADDR(默认 16MB)物理地址、映射在 __START_KERNEL_map 虚拟地址,但现在被放到随机物理地址了,怎么还能正确跑?

答案在 __startup_64(head64.c:179)------内核最早运行的头代码,它算出偏移量 load_delta,把早期页表里的物理地址全部修正:

c 复制代码
// __startup_64(arch/x86/kernel/head64.c:179)------ 关键片段
unsigned long __head __startup_64(unsigned long physaddr, struct boot_params *bp)
{
	...
	/* 我编译时该在的物理地址 vs 我实际跑的物理地址,差多少 */
	load_delta = physaddr - (unsigned long)(_text - __START_KERNEL_map);   // :203

	if (load_delta & ~PMD_MASK)     // 必须 2MB 对齐(:206)
		for (;;);

	load_delta += sme_get_me_mask(); // 加上 SME 加密掩码

	/* 把 load_delta 加进各级页表项,修正物理地址 */
	pgd = fixup_pointer(&early_top_pgt, physaddr);
	...
	*p += _PAGE_TABLE_NOENC - __START_KERNEL_map + load_delta;   // :220
	...
	pud[510] += load_delta;   // :228
	pud[511] += load_delta;   // :229
	...
	pmd[i] += load_delta;     // :233
	...
}

关键在 load_delta(:203):链接脚本(vmlinux.lds.S:125)用 AT(ADDR(.text) - LOAD_OFFSET) 定义 .text 段的物理地址,其中 LOAD_OFFSET = __START_KERNEL_map(:21)------所以 _text - __START_KERNEL_map 就是内核 text 编译时 的物理地址(LOAD_PHYSICAL_ADDR 附近)。而实际运行物理地址是 physaddr(boot stub 随机选的)。两者之差就是 load_delta。然后 __startup_64 把这个 load_delta 加进早期页表的每个 PGD/PUD/PMD 项 ------这样内核虽然被搬到随机物理地址,页表翻译后虚拟地址仍是 __START_KERNEL_map,代码照常执行。

Why 用 load_delta 而不是重编译 :内核是位置无关的 ------所有内核符号都是"相对 __START_KERNEL_map 的偏移",运行时真实虚拟地址 = __START_KERNEL_map 固定不变。物理 KASLR 只改变"这个固定虚拟地址背后映射到哪个物理页",所以只需要修页表里的物理地址 (加 load_delta),不用动任何代码/数据的虚拟地址。这就是 KASLR 几乎零成本的原因------它搬的是页表项,不是内核代码。


五、用户态 ASLR(对比)

内核 KASLR 的"用户态兄弟"是用户进程的 ASLR,随机化的是用户态 mmap 的基址(#16):

c 复制代码
// arch_pick_mmap_layout(arch/x86/mm/mmap.c:129)------ 用户态 ASLR
void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
{
	if (mmap_is_legacy())                        // 老式布局(栈上往下)
		...
	else
		*base = mmap_base(random_factor, task_size, rlim_stack);  // top-down + 随机
	arch_pick_mmap_base(&mm->mmap_base, &mm->mmap_legacy_base, ...);   // :136
}

arch_mmap_rnd(mm/mmap.c:77)生成随机偏移,mmap_base(:82)算出随机化的 mmap 起点。用户态 ASLR 随机的是用户进程的 mmap 基址 (加载共享库、mmap 匿名区的起点),内核 KASLR 随机的是内核自己的物理位置和虚拟布局------两层独立,共同防御"硬编码地址"。


六、与前面各篇的关系 + 记住三点

6.1 与前面各篇的关系

篇 关系
#17 vmalloc vmalloc_base 就是虚拟 KASLR 随机化的三个基址之一(kaslr_regions[1])
#1 物理内存初始化 vmemmap_base(struct page 数组的基址,kaslr_regions[2])也随机
PTE 篇 / 页表 __startup_64 修早期页表(load_delta)是页表初始化的第一步
CPU #1 compressed 自解压 物理 KASLR 发生在 compressed 阶段(extract_kernel → choose_random_location)
#16 mmap 用户态 ASLR(mmap_base)是内核 KASLR 的用户态对照

6.2 与 AI Infra 的关系

  • 安全基线 :训练/推理集群的宿主机内核被攻破,往往先要绕过 KASLR(泄漏地址 + 算偏移)。理解 KASLR 是理解内核漏洞利用(ret2usr、ret2dir、KASLR bypass)的前提。
  • 调试反直觉 :/proc/kallsyms 在 kptr_restrict=1 时隐藏内核符号地址(因为 KASLR 让地址每次变),排障时看 oops 地址要对上 __START_KERNEL_map 偏移。
  • nokaslr :性能剖析(perf)和内核调试常用 nokaslr 关掉随机化,让地址稳定、符号可解析。

6.3 记住三点

  1. KASLR = 物理随机 + 虚拟随机两段 :物理段 choose_random_location(kaslr.c:842)在 compressed 阶段选随机物理地址放内核镜像(find_random_phys_addr :792 扫 e820 + mem_avoid_overlap :432 避冲突);虚拟段 kernel_randomize_memory(mm/kaslr.c:64)随机化 page_offset_base/vmalloc_base/vmemmap_base(kaslr_regions[] :51)。内核 text 虚拟地址固定 __START_KERNEL_map,物理随机;直接映射区物理固定、虚拟随机------两段互补。

  2. load_delta 重定位零成本搬页表 :__startup_64(head64.c:179)算 load_delta = physaddr - (text - __START_KERNEL_map)(:203),把差值加进早期页表每个 PGD/PUD/PMD 项(:220-233)------内核代码/数据虚拟地址不变,只是背后的物理页变了。KASLR 搬的是页表项不是代码。

  3. 三个虚拟区顺序不变、整体错位 :kernel_randomize_memory 保持直接映射/vmalloc/vmemmap 的顺序,在区间之间随机插 1GB(PUD_SIZE)对齐的空隙,让每个区基址随机。用户态 ASLR(arch_pick_mmap_layout mmap.c:129)随机 mmap 基址,是内核 KASLR 的用户态对照。


附:本篇关键源码索引

符号 位置
extract_kernel(compressed 入口) arch/x86/boot/compressed/misc.c:377
choose_random_location(物理 KASLR 选地址) arch/x86/boot/compressed/kaslr.c:842
find_random_phys_addr(扫 e820 找随机物理地址) arch/x86/boot/compressed/kaslr.c:792
find_random_virt_addr(随机虚拟地址) arch/x86/boot/compressed/kaslr.c:821
process_e820_entries / mem_avoid_overlap(避冲突) arch/x86/boot/compressed/kaslr.c:772 / :432
mem_avoid_init(记录不可覆盖区间) arch/x86/boot/compressed/kaslr.c:383
kernel_randomize_memory(虚拟 KASLR) arch/x86/mm/kaslr.c:64
kaslr_regions[](三个随机化区域) arch/x86/mm/kaslr.c:51
__startup_64(load_delta 重定位) arch/x86/kernel/head64.c:179
kernel_randomize_memory 调用点 arch/x86/kernel/setup.c:1082
__START_KERNEL_map(内核 text 固定虚拟基址) arch/x86/include/asm/page_64_types.h:50
LOAD_OFFSET(= __START_KERNEL_map,链接脚本虚拟基址) arch/x86/kernel/vmlinux.lds.S:21
.text 物理地址定义(AT(ADDR(.text) - LOAD_OFFSET)) arch/x86/kernel/vmlinux.lds.S:125
__PAGE_OFFSET_BASE_L4(直接映射默认基址) arch/x86/include/asm/page_64_types.h:42
__VMALLOC_BASE_L4 / __VMEMMAP_BASE_L4 arch/x86/include/asm/pgtable_64_types.h:124 / :130
arch_pick_mmap_layout / arch_mmap_rnd(用户态 ASLR) arch/x86/mm/mmap.c:129 / :77
相关推荐
todoitbo1 小时前
群晖NAS部署JmalCloud:Docker安装、文件管理、博客与公网访问完整教程
运维·docker·容器
时间售卖铺2 小时前
触发器与函数实战:MySQL高效编程秘诀
运维·数据库·mysql·云原生
qetfw2 小时前
UOS MariaDB 数据库:安装、最小权限与备份验证
linux·数据库·mariadb·uos
前端精髓2 小时前
调用大模型API
运维·服务器·microsoft
跨境小彭2 小时前
Temu 全托管模式下,SKU 利润核算的实践复盘
大数据·运维·人工智能·自动化·temu
李纲明3 小时前
WordPress 定时发布不跑、备份邮件延误:先核 WP-Cron 触发与回环,再改系统 Cron
运维·wordpress·定时任务·devdiy·wp-cron
chushiyunen3 小时前
autoHotKey、windows自动化快捷键工具
运维·windows·自动化
逆风的蚂蚁3 小时前
linux服务器性能调整怎么落地?我把 CPU 调度、I/O 优先级和内核参数这几个旋钮都拧了一遍
linux·运维·服务器
ESDWAN3 小时前
企业网络监控应该监测哪些目标?网关、网络节点还是业务系统?
服务器·网络·php