LWN:通用的地址空间隔离方案!

操作系统(四)--进程的地址空间 前一章和大家介绍了进程的基本概念与创建进程的系统调用,本篇文章就来研究一下进程中的地址空间 阅读详情

关注了就能看到更多这么棒的文章哦~

Generalized address-space isolation

By Jonathan Corbet
March 3, 2022
DeepL assisted translation
https://lwn.net/Articles/886494/

Meltdown 和 Spectre 漏洞的披露,让人们看到了太广泛地地址空间共享会带来的风险。尽管硬件提供的保护机制应该阻止对敏感数据的不应该有的访问,但这些漏洞往往可以被利用来泄露这些数据。因此,从一开始,人们制定的缓解策略(mitigation strategies)就包括减少共享地址空间,但还可以更进一步,而且人们对这个方向也一直很感兴趣。现在,Junaid Shahid 发布的这组 patch set(包含了 Ofir Weisse 的成果,并且受到 Alexandre Chartre 早期 patch 的启发)就展示了为内核创建一个通用的地址空间隔离(ASI)机制所需要做什么。

Protecting data with ASI

当 CPU 在预测执行模式下被欺骗去访问不该访问的内存区域,从而绕过代码中现存的防止这种访问的检查时,这就是推测性执行(speculative-execution)漏洞了。每当发现 CPU 预测错误时,预测执行的影响就应该被消除,但在各种硬件 cache 中还是留下了痕迹。恶意代码可以找到这些痕迹,并利用它们来窃取出数据,如果没有这些痕迹的话攻击者就无法获得这些数据。

然而,这些攻击无法对攻击时完全不能访问的内存起作用。这就是为什么内核页表隔离(kernel page-table isolation)对 Meltdown 可以有效果的原因;如果内核的内存在攻击者的代码可以运行时完全没有被 map (映射),那么它就不可能在预测执行时被泄露出去。只要保持内核的地址空间不被 map,就足以防止在用户空间运行时受到 Meltdown 漏洞影响。

相反,Spectre 攻击通常在系统运行于内核模式时来攻击系统,并且此时所有的内核内存都被 map 了,所以我们当前的 kernel page-table isolation 的实现方式并没有能够保护这种情况。但是,内核几乎不会需要访问它所拥有的所有地址空间,而且不访问才是常态。因此,只要能够更多地使用地址空间隔离,就能带来这些好处:ASI 可以将内核与它不需要使用的内存区域隔离开来,从而消除许多可能的攻击手段。

还有其他一些阻止 Spectre 攻击的方法,其中一些现在已经在内核中实现了,但是目前的 Spectre 缓解措施中大多都开销很大,而且并不完整。例如,在每次返回用户空间时把内存对应的 cache 内容 flush 掉就可以阻止许多种类的攻击,但这会导致运行时间增长非常多。管理员还必须禁用同步多线程(SMT, simultaneous multi-threading),这可能会严重损害性能,要么就需要承担可能来自兄弟 CPU 的攻击风险。如果 ASI 能够足够有效地阻止攻击,就可能可以去除掉目前的缓解措施,从而增加 CPU 性能表现。

更好的地址空间隔离,可以在虚拟化领域带来更好的优势。在 KVM 下运行的虚拟机经常需要返回到 host 内核来执行各种任务,但这些请求通常可以在不访问内核的大部分地址空间的情况下就处理完毕。由于虚拟机很可能在运行恶意代码,而且它们可能配置成了 mixed-tenant 系统(简单来说就是多个互不知晓的用户存在于同一个系统)运行方式,因此长期以来,人们一直非常关注如何防止来自这种场景的 Spectre 攻击。因此,不出意外,目前的 ASI patch 就是来源于云计算供应商(最初是甲骨文,现在是谷歌),并特别针对 KVM,尽管该机制的整体设计上更加通用,可以支持其他场景。

Sensitive and non-sensitive memory

这套 patch 的核心思想是一个新增的 "address-space-isolation classes"的概念,每个 class 都描述了一种特定的安全环境。unrestricted class 是针对可以完全访问整个地址空间的内核的。换句话说,也就是当前版本代码中内核的工作方式。restricted class 定义为 unrestricted class 的一个子集。存在于 restricted class 中的任何一个 page-table mapping 都跟 unrestricted class 中的同一个 mapping 是完全相同的,但 restricted class 中不包含非受限类中所 map 的许多敏感数据的 mapping。

采用了 ASI 运行的系统,在用户空间代码运行的时候,都是在一个 restricted class 中运行。例如,在把控制权交给在 guest 系统中运行的内核之前,都会进入 KVM 特有的 ASI class 里。kernel page-table isolation class(如果它存在的话,这个 patch set 描述了这种可能性,但没有包含相关代码实现)则是在返回到 host 系统的用户空间之前进入的。但 ASI 的一个重要功能是,如果不需要访问敏感数据,那么在内核中运行时也可以使用 restricted class。因此,内核也就可以不用离开 KVM ASI class 就能够处理许多与 KVM 有关的任务了。

对于存储在内存中的数据,在此 patch set 中定义了三个敏感级别:

  • "sensitive" 内存,永远不应该被泄露出内核。

  • "globally non-sensitive" 内存,如果泄露给当前运行的进程是无害的,但不能允许进一步泄露。

当使用了地址空间隔离时,敏感内存只会在内核运行时才被 map 上来,甚至只有在内核真正需要它时才被 map。globally non-sensitive memory 可以一直保持 mapped 状态。与其他两类不同,locally non-sensitive memory 对每个进程来说都是不一样的;它可以在当前进程运行时被映射,但不会被映射到其他任何一个进程的地址空间。

这几种内存分类适用于所有 restricted ASI class。如果有许多这种 class,它们都会以同样的方式来限制内核的地址空间。换句话说,在一个 restricted ASI class 中判定为敏感信息(sensitive)的内存,在所有的 ASI class 中都是敏感信息。ASI class 之间的区别在于有多少用户空间被 map,以及当内核进入或退出其中一个 class 时,会运行一组钩子函数。例如,进入 KVM class 时,需要 flush 内存 cache,以避免可能在虚拟机中运行的任何一个 Spectre 攻击。如果当前的 kernel page-table isolation 机制在这个方案中被实现,那么在进入这个 class 时就不需要进行 cache flush 了,因为只要从内核中删除相关地址空间映射就足够了。

这组 patch 中有一个有趣的决定:如果内核在 restricted ASI class 下运行时试图访问 sensitive 数据,就会触发处理器的 trap。这时,一个可能的选择就是让 kernel oops,当然这肯定会阻止对该数据的预测执行攻击了。不过 ASI patch set 的做法是在这种情况下退出当前的 ASI class,进入 unrestricted 模式,允许继续访问。这种做法应该足以阻止对该数据的预测执行访问了(因为预测执行会直接停止,而不是处罚 trap),同时,也不会妨碍合法的内核访问。

采取这种方法的一个原因应该是相当清楚的:内核的地址空间是巨大的,没有人指望可以正确地确定内核使用的每一个数据结构的敏感性,并对其进行正确的标记。除此之外,必须有人找到内核里面在处理敏感数据之前必须需要退出 restricted class 的所有代码。哪怕有人真做到了,也没人指望能永远保持下去。因此,这个架构体现了一种承认现实的态度,现实就是永远不可能正确标记所有的数据以及所有必须使用敏感数据的位置,所以无论如何,总是需要让工作能正常进行下去的。

Classifying memory

然而,至少必须要把最敏感和最频繁访问的数据都正确标记出来。这个 patch set 有 47 个 patch 组成,其中大部分内容都集中在这项任务上。对于动态分配的内存来说,有一组新增的 GFP 标志(__GFP_GLOBAL_NONSENSITIVE 和__GFP_LOCAL_NONSENSITIVE)用于标记不包含敏感内容的那些内存分配动作。调用 page 或 slab allocator 进行分配时可以使用这些 flag,就能将得到的内存归入所需的 class;用 vmalloc() 分配的内存也可以用这种方式归到正确的 class 里。

在 kernel 内部,内核为自己的地址空间维护了两套 page-table。其中 unrestricted table 跟当前内核中使用的 page-table 是相同的,其中包括了 "direct map",也就是使所有的物理内存在内核的地址空间中都可用。restricted page table 在最开始时几乎不包含任何 mapping。每次进行 globally non-sensitive 内存分配时,就会把分配出来的 page 相关的 mapping 复制到第二套 page table 中的相同地址上。当在 restricted 模式下运行时,第二套 page table 就会被激活来取代第一套 page table,提供对 non-sensitive 数据的访问权限,但不会可以访问任何 sensitive 数据。

处理 locally non-sensitive 的内存分配则比较棘手。当内核在 restricted 模式下运行时,direct map 中只有全局 non-sensitive 这部分分实际存在于当前 page table 中。因为这些数据是 globally non-sensitive 的,所以有唯一一个 restricted table 会用来给所有进程。但是,locally non-sensitive mapping 对每个进程来说必须是唯一的,所以它们不能存放在这个个唯一的、global page table 里面。这就产生了一个问题,即在地址空间中,这些 mapping 应该放在哪里。

我们选择的解决方案是把 direct map 重新复制一份,所以现在内核对所有的物理内存会有两个完整映射。在 restricted 模式下,第一个映射中包含了 globally non-sensitiive 的数据,就像以前一样。在分配 locally sensitive 数据空间时,则使用第二个 mapping 来设置。再次提醒,只有那些被特地指定了是作为 locally non-sensitiive 来分配的 page 才在这个 restricted 版本的 mapping 中进行映射,并且每个进程都有自己专有的一套 mapping。因此,正在运行的进程的 locally non-sensitiive 数据哪怕在 restricted 模式下也是能访问的,但它不能被其他任何进程访问。

这就解决了这个问题,但代价是内核可以管理的物理内存数量就减少了一半,因为每个物理 page 现在都必须被映射两次。

对于静态变量会有一组单独的 flag,名称就类似于 __asi_not_sensitive 和__asi_not_sensitive_readmostly,可以把这些 flag 添加到变量声明中。人们很容易可以理解,不能将静态变量声明为 locally non-sensitiive。static per-cpu 变量又带来了一些麻烦,需要在用来声明的 macro 里面添加上一些简洁明了的描述,比如 DEFINE_PER_CPU_SHARED_ALIGNED_ASI_NOT_SENSITIVE()。

开发者并没有试图去把每一个分配和声明都标记准确。如上所述,这不是一个正常人会去尝试的做法,哪怕是内核开发者也不会。但是内核开发者们已经花了一些时间来尝试这组 patch set,并记录了有哪些访问触发了 trap 并迫使系统退回到 unrestricted 模式中。通过确认并标记出那些最繁忙的、nonsensitive 数据结构,从而能够减少这个新增机制对整体性能的影响。

Isolating KVM

有了所有这些基础设施之后,再添加一个机制来允许把用户空间的内存可空地映射到 restricted 环境,就有可能专门为 KVM 设置 address-space isolation,从而可以关闭一些开销巨大的 Spectre 的保护措施。每当内核将控制权交给 guest 系统时,它就会确保 KVM ASI 模式被启用;在返回内核时,可能会退出到 unrestricted 模式,也可能不会,这取决于内核打算要做什么。如果这次可以避免退出到 unrestricted 模式的话(因为不需要访问 sensitive 数据),那么就可以避免 cache flush 带来的开销了。同时一般来说,即使是恶意的 guest 系统也无法利用 host 内核的 Spectre 漏洞了。

不过,为了把这种保护做完整,内核必须保护好自己,不仅要防备 guest,还要防备运行在 SMT 兄弟 CPU 之上的系统中的恶意进程。在完整实现中,如果要避免简单地禁用 SMT 所引入的代价,那就意味着当内核在不受限制的地址空间中运行时,需要 "stunning (击晕)" 兄弟 CPU,也就是暂停其执行。当 kernel 返回到 KVM 时,兄弟 CPU 必须要被恢复("unstunned")出来。内核还必须要 flush memory cache 来避免数据泄漏。这里提到的把兄弟 CPU 打晕的这种精彩做法并没有包含在当前 patch set 中。跟现实世界中的同胞相残的事件一样,必须要先考虑清楚这会带来的后果。目前还没有完成这个 stunning 动作以及调度器之间的互动的 review,所以这项工作还没有被发布。

上面这些内容仅是对一种新形式的 ASI 的初步了解,它可以提高使用 KVM 的 guest 系统的安全性和性能,而且还可以扩展到其他任何可能需要 ASI 的情况。截至目前,这组 patch set 还没有收到任何 review,这可能是由于整个工作的规模很大、很复杂造成的。它确实实现了很有意思的权衡:它可以提高性能和安全性,但代价是大量的代码改动,以及今后需要持续维护这些 sensitivity annotation 标注。人们可能希望在不久之后,硬件将不再包含 Spectre 漏洞,那时这些新带来的成本就可能不太必要了。相反,如果我们相信 Spectre 可能会在很长一段时间内继续困扰我们,那么这个做法的优势就很明显了。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

46f0456e606b99eaf39c01455542a2bc.png

【STM32】433MHz OOK信号软解码实战:从EV1527协议到嵌入式实现 本文详细介绍了基于STM32微控制器实现433MHz OOK信号软解码的完整实战过程。文章从EV1527协议解析入手,重点阐述了利用STM32的GPIO和定时器进行信号采样、脉宽还原、同步头识别以及数据位判决的核心算法,并提供了对抗无线干扰的容错优化策略,帮助开发者深入理解并掌握低成本无线通信的嵌入式实现方案。 阅读详情

相关推荐

WOFOST模型参数调优实战:从‘跑不通’到‘预测准’的避坑指南

本文详细介绍了WOFOST模型参数调优的实战技巧,帮助用户从模型报错诊断到参数敏感性分析,再到土壤-作物参数联调策略,逐步解决‘跑不通’到‘预测准’的问题。通过Python和PCSE工具,提供参数扰动测试模板和关键参数优先级矩阵,助力作物模型的高效校准与预测。

weixin_32597009的博客 621

LWN: 通用的地址空间隔离

Generalizing address-space isolationByJonathan CorbetNovember 5, 2019OSS EU原文来自:http...

Linux News搬运工 672

5分钟快速搭建:使用ros1_bridge实现ROS2容器与ROS1主机的无缝通信

本文详细介绍了如何在5分钟内快速搭建基于ros1_bridge的通信方案,实现运行在Docker容器中的ROS2节点与宿主机ROS1系统的无缝数据交换。通过环境隔离、Docker容器化部署及选择性桥接配置,该方案能有效整合新旧系统,避免大规模代码重构,是机器人项目渐进式升级的实用策略。

weixin_29268637的博客 178

【Linux】进程控制深度了解(1)

90%的情况下是不会的,但这并不代表代码不能进行写时拷贝,例如在进行进程替换的时候,则需要进行代码的写时拷贝。所有程序都直接访问物理内存,程序使用的物理空间不是相互隔离的。万一进程越界进行非法操作,这样是非常不安全的。没有有效的内存管理机制,通常执行一个程序时,监控程序需要将其整个程序装入内存然后开始执行。因为每次需要装入运行时,我们都需要给他分配一块足够大的物理空间,而这个物理空间是不确定的。

时间与思念 829

Multisim 14.0元件库下载权威指南:官方与社区资源

详解Multisim元件库下载的官方途径与可靠社区资源,帮助用户快速获取Multisim 14.0所需元件模型,提升电路仿真效率。

weixin_32925455的博客 747

FPGA时序约束--实战篇(读懂Vivado时序报告)

本文将详细介绍如何读懂Vivado时序报告,包括报告的基本结构和如何分析报告。

mengzaishenqiu的博客 1万+

LWN:呼吁再次考虑地址空间隔离!

关注了就能看到更多这么棒的文章哦~A call to reconsider address-space isolationBy Jonathan CorbetSeptember 29, 2022LPCDeepL assisted translationhttps://lwn.net/Articles/909469/内核运行时可以访问到地址空间中的全部内容,通常就包括了所有的物理内存,尽管其实这个地...

Linux News搬运工 417

mapbox进阶,百度地图、高德地图纠偏,使用在线网络地图加载插件

本文详细介绍如何基于mapbox-gl v3.8.0版本百度地图、高德地图纠偏,使用在线网络地图加载插件,亲测可用。希望能帮助到您。一起学习,加油!加油!

我哎GIS博客 748

Linux内核架构浅谈54-Linux内存访问控制:用户空间与内核空间的地址隔离

Linux通过虚拟地址空间划分、硬件特权级别和页表访问控制实现用户空间与内核空间的严格隔离。32位系统采用"3:1"划分模式,用户进程仅能访问0-3GiB空间,而内核独占3-4GiB区域。隔离机制依赖CPU特权级别(Ring0/Ring3)和页表权限位(_PAGE_USER等),用户态访问内核地址会触发硬件异常。合法交互通过系统调用和copy_from/to_user函数实现数据安全传输。

文石_2009的博客 1066

【软件使用】向日葵网络连接错误

一直报这个错误,尝试了修改版本无果,各种密码都正确,最后得出结轮是时间没有同步,查看代理是否更改了时间,做一下同步即可。

andeyeluguo的博客 7968

ZYNQ通过AXI DMA实现PL发送连续大量数据到PS DDR

方案二是在PS端的MPU配置中,将DMA缓冲区所在的内存区域标记为“不缓存”(Device或Strongly Ordered类型),但这样CPU访问这些内存区的速度会大幅降低,需要根据实时性和数据正确性的需求做权衡。更妙的是,描述符链表可以做成一个环状队列,放在DDR里让DMA循环取走,从而实现持续不断的“流式”传输。用FPGA实现FFT硬件加速的系统中也是如此:PS向PL提交待处理的FFT数据,PL硬件加速计算后,DMA把结果写回DDR,全程CPU几乎只做配置调度,大量数据吞吐留给了硬件通道。

QQ_778132974的博客 173

LWN:地址空间隔离的两个patch!(重发)

关注了就能看到更多这么棒的文章哦~Two address-space-isolation patches get closerBy Jonathan CorbetOctober 27, ...

Linux News搬运工 288

OpenCV-Python实战(11)——OpenCV轮廓检测相关应用

在计算机视觉领域,轮廓通常指图像中对象边界的一系列点。因此,轮廓通常描述了对象边界的关键信息,包含了有关对象形状的主要信息,该信息可用于形状分析与对象检测和识别。在本文中,我们将学习如何利用获取到的轮廓,进行形状分析以及对象检测和识别。

盼小辉丶的博客 1万+

LWN:在另一个进程的地址空间内执行代码!

关注了就能看到更多这么棒的文章哦~Running code within another process's address spaceBy Jonathan CorbetApri...

Linux News搬运工 527

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

LWN:kernel通用的ring buffer!

关注了就能看到更多这么棒的文章哦~A generic ring buffer for the kernelBy Jonathan CorbetJune 6, 2024Gemini-1.5-flash translationhttps://lwn.net/Articles/976836/内核的用户空间 ABI 中不乏环形缓冲区(ring buffer);在例如BPF、io_uring、perf和...

Linux News搬运工 1523

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

LWN:在memfd中附加安全保护功能!

关注了就能看到更多这么棒的文章哦~Keeping secrets in memfd areasByJonathan CorbetFebruary 14, 2020原文来自:https:...

Linux News搬运工 1099

LWN:kernel的沙盒模式!

关注了就能看到更多这么棒的文章哦~A sandbox mode for the kernelBy Jonathan CorbetFebruary 29, 2024ChatGLM translationhttps://lwn.net/Articles/963734/Linux 内核遵循 monolithic 设计,这带来了一个众所周知的问题:内核中的所有代码都能访问内核整个地址空间。因此,内核中的一...

Linux News搬运工 320

LWN:在GNU C库实现内存封印!

关注了就能看到更多这么棒的文章哦~Memory sealing for the GNU C LibraryBy Jonathan CorbetJune 12, 2024Gemini-1.5-flash translationhttps://lwn.net/Articles/978010/mseal()系统调用允许进程阻止其地址空间未来进行任何更改(因此被称为“密封 sealing”);它借鉴了...

Linux News搬运工 1736

LWN:从kernel向user space发送通知的一个通用方案

点击上方蓝色字关注我们~Generalized events notification and security policiesByJonathan CorbetJu...

Linux News搬运工 1146

LWN:跟set_fs()说再见吧!

关注了就能看到更多这么棒的文章哦~Saying goodbye to set_fs()By Jonathan CorbetSeptember 24, 2020https://lwn.ne...

Linux News搬运工 2997

LWN:让kmalloc() 更随机!

关注了就能看到更多这么棒的文章哦~Randomness for kmalloc()By Jonathan CorbetJuly 24, 2023ChatGPT assisted translationhttps://lwn.net/Articles/938637/内核的地址空间布局随机化(ASLR, address-space layout randomization)希望通过在每次启动时更改内核...

Linux News搬运工 1059

LWN:KVM使用Guest-first memory!

关注了就能看到更多这么棒的文章哦~Guest-first memory for KVMBy Jonathan CorbetNovember 2, 2023ChatGPT translationhttps://lwn.net/Articles/949277/保护计算(confidential-computing)实现的核心目标之一是保护客户(guest)系统的内存免受来自客户本身之外的其他使用者的访...

Linux News搬运工 1243

LWN:用DAMON来优化memory-management!

关注了就能看到更多这么棒的文章哦~Memory-management optimization with DAMONByJonathan CorbetFebruary 20, 2020...

Linux News搬运工 1028

LWN:看一下动态链接过程!

关注了就能看到更多这么棒的文章哦~A look at dynamic linkingBy Daroc AldenFebruary 13, 2024Gemini translationhttps://lwn.net/Articles/961117/动态链接程序是现代 Linux 系统的关键组件,负责设置大多数进程的地址空间。虽然随着最初推动动态链接的因素变得越来越没有那么重要了,使得静态链接二进制文...

Linux News搬运工 248

LWN:减少vmap 锁冲突!

关注了就能看到更多这么棒的文章哦~Mitigating vmap lock contentionBy Jonathan CorbetMay 26, 2023LSFMM+BPFDeepL assisted translationhttps://lwn.net/Articles/932396/"vmap area" 是在 kernel 需要映射一段内存到虚拟地址时可以使用的一段 kernel 地址空间...

Linux News搬运工 1134

LWN:从KVM直接进行host系统调用!

关注了就能看到更多这么棒的文章哦~Direct host system calls from KVMBy Jonathan CorbetJuly 29, 2022DeepL assisted translationhttps://lwn.net/Articles/902585/虚拟化机制的设计原则之一就是要在 host 和它所运行的 guest 系统之间提供强大的隔离。guest 是不可以被信任...

Linux News搬运工 504

LWN:细粒度的KASLR(内核地址空间随机变化)!

关注了就能看到更多这么棒的文章哦~Finer-grained kernel address-space layout randomizationByJake EdgeFebruary ...

Linux News搬运工 955
上一篇: LWN:Fedora缺失的Chromium update!
下一篇: LWN: Benenios - 用于不公开投票的系统!
LinuxNews搬运工
博客等级 码龄7年 438粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值