使用 eBPF Linux 安全模块实时修补 Linux 内核中的安全漏洞
2022-06-29
使用 LSM BPF,开发人员能够在无需配置或加载内核模块的情况下编写精细策略。LSM BPF 程序会在加载时进行验证,然后在调用路径中到达 LSM hook 时执行...
继续阅读 »
\n \n
Linux 5.7 引入了第三种方式:LSM 扩充 Berkeley Packet Filter (eBPF)(简称 LSM BPF)。使用 LSM BPF,开发人员能够在无需配置或加载内核模块的情况下编写精细策略。LSM BPF 程序会在加载时进行验证,然后在调用路径中到达 LSM hook 时执行。
\n现代操作系统提供了允许“分割”内核资源的设施。例如,FreeBSD 有“jail”,Solaris 有“区域”。Linux 有所不同,它提供一组看起来独立的设施,每个设施允许隔离特定资源。这些称为“命名空间”,多年来一直在内核中增长。它们是 Docker、lxc 或 firejail 等流行工具的基础。许多命名空间都是无争议的,例如 UTS 命名空间,它允许主机系统隐藏其主机名和时间。其他一些命名空间则比较复杂,但直接明了,例如,NET 和 NS (mount) 命名空间就令人难以理解。最后,还有一个非常特殊且稀奇的 USER 命名空间。
USER 命名空间的特殊之处在于,它允许所有者以其中的“根”用户身份操作。具体机制超出了本博客文章的讨论范围,但简单地说,在它的基础上,Docker 等工具才能不以真正的根用户身份操作,并且它还是无根容器等事项的基础。
鉴于其性质,允许无特权的用户访问 USER 命名空间始终会带来极大的安全风险。其中一种风险就是特权提升。
特权提升是操作系统的常见攻击面。用户可以获取特权的一种方式是通过 unshare syscall 将其命名空间映射到根命名空间,并指定 CLONE_NEWUSER 标志。这会指示 unshare 创建有完整权限的新用户命名空间,并将新用户和组 ID 映射到之前的命名空间。您可以使用 unshare(1) 程序将根映射到我们的原始命名空间:
在大部分情况下,使用 unshare 没有损害,而且预定以较低特权运行。但是,此 syscall 已被发现用于提升特权。
\n$ id\nuid=1000(fred) gid=1000(fred) groups=1000(fred) …\n$ unshare -rU\n# id\nuid=0(root) gid=0(root) groups=0(root),65534(nogroup)\n# cat /proc/self/uid_map\n 0 1000 1
\n Syscall clone 和 clone3 值得仔细考虑,因为它们还能够 CLONE_NEWUSER。但就本文而言,我们将专注于 unshare。
Debian 使用这个“add sysctl to disallow unprivileged CLONE_NEWUSER by default”(添加 sysctl 以在默认情况下不允许无特权的 CLONE_NEWUSER)补丁解决了该问题,但这不是主流做法。另一个类似补丁“sysctl: allow CLONE_NEWUSER to be disabled”(sysctl:允许禁用 CLONE_NEWUSER)试图成为主流,但遭到了排挤。一种批评意见是针对特定应用程序无法切换此功能。在文章《控制对用户命名空间的访问》中,作者写道:“...现行补丁似乎很难成为主流。”显然,这些补丁最终并未包含在 vanilla 内核中。
\n由于限制 USER 命名空间的上游代码似乎行不通,我们决定使用 LSM BPF 来规避这些问题。这样做并不需要修改内核,而且我们可以制定守护访问权限的复杂规则。
\n首先,让我们找到所需的 syscall。我们可以在 include/linux/syscalls.h 文件中找到原型。这在其中并不太容易查找到,但以下这行:
提供了线索,这样我们就知道接下来要在 kernel/fork.c 中的什么地方查找。其中发出了对 ksys_unshare() 的调用。在该函数中深入探查,我们找到对 unshare_userns() 的调用。此操作有望成功。
\n/* kernel/fork.c */
\n 到目前为止,我们确定了 syscall 实现,但接下来要弄清楚的是,哪些 hook 可供我们使用?因为我们通过手册页可以知道,unshare 用于改变任务,所以我们来看一下 include/linux/lsm_hooks.h 中基于任务的 hook。早在函数 unshare_userns() 中,我们就看到对 prepare_creds() 的调用。这非常类似于 cred_prepare hook。为了验证我们是否通过 prepare_creds() 获得匹配,我们观察对安全性 hook security_prepare_creds() 的调用,后者最终会调用该 hook:
不必进一步详细探究细节,我们知道这个 hook 很适合使用,因为 prepare_creds() 刚好就在 create_user_ns()(位于 unshare_userns() 中)之前调用,后者是我们试图阻止的操作。
\n…\nrc = call_int_hook(cred_prepare, 0, new, old, gfp);\n…
\n \n 我们打算使用 eBPF compile once-run everywhere (CO-RE) 方法进行编译。这样一来,我们就可以在一个架构上编译,而在另一个架构上加载。但我们打算专门以 x86_64 为目标。适用于 ARM64 的 LSM BPF 仍在开发中,以下代码将无法在该架构上运行。敬请留意 BPF 邮寄列表以关注进展。
测试该解决方案时采用的内核版本不低于 5.15,且配置了以下内容:
启动选项 lsm=bpf
在 CONFIG_LSM
未在列表中包含“bpf”时可能是必要的。
BPF_EVENTS\nBPF_JIT\nBPF_JIT_ALWAYS_ON\nBPF_LSM\nBPF_SYSCALL\nBPF_UNPRIV_DEFAULT_OFF\nDEBUG_INFO_BTF\nDEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT\nDYNAMIC_FTRACE\nFUNCTION_TRACER\nHAVE_DYNAMIC_FTRACE
\n 让我们从序言开始:
deny_unshare.bpf.c:
接下来,我们通过以下方式为 CO-RE 调整设置我们的必要结构:
\n#include <linux/bpf.h>\n#include <linux/capability.h>\n#include <linux/errno.h>\n#include <linux/sched.h>\n#include <linux/types.h>\n\n#include <bpf/bpf_tracing.h>\n#include <bpf/bpf_helpers.h>\n#include <bpf/bpf_core_read.h>\n\n#define X86_64_UNSHARE_SYSCALL 272\n#define UNSHARE_SYSCALL X86_64_UNSHARE_SYSCALL
\n deny_unshare.bpf.c:
我们不需要完全充实 struct 的细节,只需提供程序正常运行所需信息的绝对下限。CO-RE 将执行为内核执行调整所需的任何操作。这样就可以很轻松地编写 LSM BPF 程序!
\n…\n\ntypedef unsigned int gfp_t;\n\nstruct pt_regs {\n\tlong unsigned int di;\n\tlong unsigned int orig_ax;\n} __attribute__((preserve_access_index));\n\ntypedef struct kernel_cap_struct {\n\t__u32 cap[_LINUX_CAPABILITY_U32S_3];\n} __attribute__((preserve_access_index)) kernel_cap_t;\n\nstruct cred {\n\tkernel_cap_t cap_effective;\n} __attribute__((preserve_access_index));\n\nstruct task_struct {\n unsigned int flags;\n const struct cred *cred;\n} __attribute__((preserve_access_index));\n\nchar LICENSE[] SEC("license") = "GPL";\n\n…
\n deny_unshare.bpf.c:
第一步是创建程序,第二步是加载程序并附加到我们所需的 hook。有几种方式可实现这一目的:Cilium ebpf 项目,Rust 绑定,以及 ebpf.io 项目环境页面上的其他几项。我们打算使用原生 libbpf。
\nSEC("lsm/cred_prepare")\nint BPF_PROG(handle_cred_prepare, struct cred *new, const struct cred *old,\n gfp_t gfp, int ret)\n{\n struct pt_regs *regs;\n struct task_struct *task;\n kernel_cap_t caps;\n int syscall;\n unsigned long flags;\n\n // If previous hooks already denied, go ahead and deny this one\n if (ret) {\n return ret;\n }\n\n task = bpf_get_current_task_btf();\n regs = (struct pt_regs *) bpf_task_pt_regs(task);\n // In x86_64 orig_ax has the syscall interrupt stored here\n syscall = regs->orig_ax;\n caps = task->cred->cap_effective;\n\n // Only process UNSHARE syscall, ignore all others\n if (syscall != UNSHARE_SYSCALL) {\n return 0;\n }\n\n // PT_REGS_PARM1_CORE pulls the first parameter passed into the unshare syscall\n flags = PT_REGS_PARM1_CORE(regs);\n\n // Ignore any unshare that does not have CLONE_NEWUSER\n if (!(flags & CLONE_NEWUSER)) {\n return 0;\n }\n\n // Allow tasks with CAP_SYS_ADMIN to unshare (already root)\n if (caps.cap[CAP_TO_INDEX(CAP_SYS_ADMIN)] & CAP_TO_MASK(CAP_SYS_ADMIN)) {\n return 0;\n }\n\n return -EPERM;\n}
\n deny_unshare.c:
最后,我们使用以下 Makefile 来编译:
\n#include <bpf/libbpf.h>\n#include <unistd.h>\n#include "deny_unshare.skel.h"\n\nstatic int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)\n{\n return vfprintf(stderr, format, args);\n}\n\nint main(int argc, char *argv[])\n{\n struct deny_unshare_bpf *skel;\n int err;\n\n libbpf_set_strict_mode(LIBBPF_STRICT_ALL);\n libbpf_set_print(libbpf_print_fn);\n\n // Loads and verifies the BPF program\n skel = deny_unshare_bpf__open_and_load();\n if (!skel) {\n fprintf(stderr, "failed to load and verify BPF skeleton\\n");\n goto cleanup;\n }\n\n // Attaches the loaded BPF program to the LSM hook\n err = deny_unshare_bpf__attach(skel);\n if (err) {\n fprintf(stderr, "failed to attach BPF skeleton\\n");\n goto cleanup;\n }\n\n printf("LSM loaded! ctrl+c to exit.\\n");\n\n // The BPF link is not pinned, therefore exiting will remove program\n for (;;) {\n fprintf(stderr, ".");\n sleep(1);\n }\n\ncleanup:\n deny_unshare_bpf__destroy(skel);\n return err;\n}
\n Makefile:
\nCLANG ?= clang-13\nLLVM_STRIP ?= llvm-strip-13\nARCH := x86\nINCLUDES := -I/usr/include -I/usr/include/x86_64-linux-gnu\nLIBS_DIR := -L/usr/lib/lib64 -L/usr/lib/x86_64-linux-gnu\nLIBS := -lbpf -lelf\n\n.PHONY: all clean run\n\nall: deny_unshare.skel.h deny_unshare.bpf.o deny_unshare\n\nrun: all\n\tsudo ./deny_unshare\n\nclean:\n\trm -f *.o\n\trm -f deny_unshare.skel.h\n\n#\n# BPF is kernel code. We need to pass -D__KERNEL__ to refer to fields present\n# in the kernel version of pt_regs struct. uAPI version of pt_regs (from ptrace)\n# has different field naming.\n# See: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fd56e0058412fb542db0e9556f425747cf3f8366\n#\ndeny_unshare.bpf.o: deny_unshare.bpf.c\n\t$(CLANG) -g -O2 -Wall -target bpf -D__KERNEL__ -D__TARGET_ARCH_$(ARCH) $(INCLUDES) -c $< -o $@\n\t$(LLVM_STRIP) -g $@ # Removes debug information\n\ndeny_unshare.skel.h: deny_unshare.bpf.o\n\tsudo bpftool gen skeleton $< > $@\n\ndeny_unshare: deny_unshare.c deny_unshare.skel.h\n\t$(CC) -g -Wall -c $< -o $@.o\n\t$(CC) -g -o $@ $(LIBS_DIR) $@.o $(LIBS)\n\n.DELETE_ON_ERROR:
\n 在新的终端窗口中,运行:
在另一个终端窗口中,我们成功被阻止!
\n$ make run\n…\nLSM loaded! ctrl+c to exit.
\n 策略还有一项始终允许特权通过的功能:
\n$ unshare -rU\nunshare: unshare failed: Cannot allocate memory\n$ id\nuid=1000(fred) gid=1000(fred) groups=1000(fred) …
\n 在无特权的情况下,syscall 会及早中止。在有特权的情况下,对性能有何影响?
\n$ sudo unshare -rU\n# id\nuid=0(root) gid=0(root) groups=0(root)
\n \n 我们打算使用单行 unshare 来映射用户命名空间,并在其中执行测量的命令:
通过 syscall unshare enter/exit 的 CPU 周期分辨率,我们将以根用户身份测量以下内容:
\n$ unshare -frU --kill-child -- bash -c "exit 0"
\n 不带策略运行的命令
带策略运行的命令
我们将使用 ftrace 记录测量:
目前,我们专门为 unshare 的 syscall enter 和 exit 启用了跟踪。现在,我们设置 enter/exit 调用的时间分辨率,计算 CPU 周期数量:
\n$ sudo su\n# cd /sys/kernel/debug/tracing\n# echo 1 > events/syscalls/sys_enter_unshare/enable ; echo 1 > events/syscalls/sys_exit_unshare/enable
\n 接下来,我们开始测量:
\n# echo 'x86-tsc' > trace_clock
\n 在新的终端窗口中运行策略,然后运行下一个 syscall:
\n# unshare -frU --kill-child -- bash -c "exit 0" &\n[1] 92014
\n 现在,我们来比较两个调用:
\n# unshare -frU --kill-child -- bash -c "exit 0" &\n[2] 92019
\n unshare-92014 使用了 63294 个周期。
\n# cat trace\n# tracer: nop\n#\n# entries-in-buffer/entries-written: 4/4 #P:8\n#\n# _-----=> irqs-off\n# / _----=> need-resched\n# | / _---=> hardirq/softirq\n# || / _--=> preempt-depth\n# ||| / _-=> migrate-disable\n# |||| / delay\n# TASK-PID CPU# ||||| TIMESTAMP FUNCTION\n# | | | ||||| | |\n unshare-92014 [002] ..... 762950852559027: sys_unshare(unshare_flags: 10000000)\n unshare-92014 [002] ..... 762950852622321: sys_unshare -> 0x0\n unshare-92019 [007] ..... 762975980681895: sys_unshare(unshare_flags: 10000000)\n unshare-92019 [007] ..... 762975980752033: sys_unshare -> 0x0\n
\n unshare-92019 使用了 70138 个周期。
这两个测量之间有 6,844 个(大约 10%)周期的差值。结果还不赖!
这些数字是针对单个 syscall 的情况,调用代码越频繁,这些数字也会相应累加。Unshare 通常在创建任务时调用,而在程序正常执行期间不会重复调用。需要对您的用例进行仔细考虑和测量。
\n我们大致了解了 LSM BPF 的基本概念,如何使用 unshare 将用户映射到根,以及如何通过在 eBPF 中实现解决方案来解决现实问题。找到合适的 hook 并不容易,需要开展一些试验,还要编写大量内核代码。幸运的是,其他部分都比较简单。由于策略是采用 C 语言编写的,我们可以通过精细调整策略来解决我们的问题。这意味着,可以使用允许列表扩展该策略,允许特定程序或用户继续使用无特权的 unshare。最后,我们考察了该程序的性能影响,并发现阻止攻击手段所需的开销是值得的。
“Cannot allocate memory”(无法分配内存)并不是拒绝权限的明确错误消息。我们提议了一个补丁,用于在调用堆栈中从 cred_prepare hook 向上传播错误代码。最终,我们得出结论,新的 hook 更适合解决该问题。敬请关注!
"],"published_at":[0,"2022-06-29T12:45:00.000+01:00"],"updated_at":[0,"2024-10-09T23:19:25.801Z"],"feature_image":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1AScqEBDJJJSB1rEYb3VYV/23bb407471fa3e38579f90fbbf9430f9/live-patch-security-vulnerabilities-with-ebpf-lsm.png"],"tags":[1,[[0,{"id":[0,"383iv0UQ6Lp0GZwOAxGq2p"],"name":[0,"Linux"],"slug":[0,"linux"]}],[0,{"id":[0,"6Mp7ouACN2rT3YjL1xaXJx"],"name":[0,"安全"],"slug":[0,"security"]}],[0,{"id":[0,"2UVIYusJwlvsmPYl2AvSuR"],"name":[0,"深入剖析"],"slug":[0,"deep-dive"]}],[0,{"id":[0,"6lhzEBz2B56RKa4nUEAGYJ"],"name":[0,"Programming"],"slug":[0,"programming"]}]]],"relatedTags":[0],"authors":[1,[[0,{"name":[0,"Frederick Lawler"],"slug":[0,"frederick"],"bio":[0,null],"profile_image":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/69T4vzED8P3z82sjq20ktB/3602d21ed4cd710e4d34e5e99a61245d/frederick.jpg"],"location":[0,null],"website":[0,null],"twitter":[0,null],"facebook":[0,null]}]]],"meta_description":[0,"Learn how to patch Linux security vulnerabilities without rebooting the hardware and how to tighten the security of your Linux operating system with eBPF Linux Security Module."],"primary_author":[0,{}],"localeList":[0,{"name":[0,"Live-patching security vulnerabilities inside the Linux kernel with eBPF Linux Security Module Config"],"enUS":[0,"English for Locale"],"zhCN":[0,"Translated for Locale"],"zhHansCN":[0,"No Page for Locale"],"zhTW":[0,"Translated for Locale"],"frFR":[0,"No Page for Locale"],"deDE":[0,"No Page for Locale"],"itIT":[0,"No Page for Locale"],"jaJP":[0,"No Page for Locale"],"koKR":[0,"No Page for Locale"],"ptBR":[0,"No Page for Locale"],"esLA":[0,"No Page for Locale"],"esES":[0,"No Page for Locale"],"enAU":[0,"No Page for Locale"],"enCA":[0,"No Page for Locale"],"enIN":[0,"No Page for Locale"],"enGB":[0,"No Page for Locale"],"idID":[0,"No Page for Locale"],"ruRU":[0,"No Page for Locale"],"svSE":[0,"No Page for Locale"],"viVN":[0,"No Page for Locale"],"plPL":[0,"No Page for Locale"],"arAR":[0,"No Page for Locale"],"nlNL":[0,"No Page for Locale"],"thTH":[0,"No Page for Locale"],"trTR":[0,"No Page for Locale"],"heIL":[0,"No Page for Locale"],"lvLV":[0,"No Page for Locale"],"etEE":[0,"No Page for Locale"],"ltLT":[0,"No Page for Locale"]}],"url":[0,"https://blog.cloudflare.com/live-patch-security-vulnerabilities-with-ebpf-lsm"],"metadata":[0,{"title":[0,"使用 eBPF Linux 安全模块实时修补 Linux 内核中的安全漏洞"],"description":[0,"Learn how to patch Linux security vulnerabilities without rebooting the hardware and how to tighten the security of your Linux operating system with eBPF Linux Security Module."],"imgPreview":[0,"https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1T1WbFDlQxnohg7e9qiK4s/727f5c10f363e77cbbb6c4c29ba495c8/live-patch-security-vulnerabilities-with-ebpf-lsm-0JAtqD.png"]}]}],"locale":[0,"zh-cn"],"translations":[0,{"posts.by":[0,"作者"],"footer.gdpr":[0,"GDPR"],"lang_blurb1":[0,"这篇博文也有 {lang1} 版本。"],"lang_blurb2":[0,"这篇博文也有 {lang1} 和{lang2}版本。"],"lang_blurb3":[0,"这篇博文也有 {lang1}、{lang2} 和{lang3}版本。"],"footer.press":[0,"新闻"],"header.title":[0,"Cloudflare 博客"],"search.clear":[0,"清除"],"search.filter":[0,"过滤"],"search.source":[0,"来源"],"footer.careers":[0,"招聘"],"footer.company":[0,"公司"],"footer.support":[0,"支持"],"footer.the_net":[0,"theNet"],"search.filters":[0,"过滤器"],"footer.our_team":[0,"我们的团队"],"footer.webinars":[0,"网络研讨会"],"page.more_posts":[0,"更多帖子"],"posts.time_read":[0,"{time} 分钟阅读时间"],"search.language":[0,"语言"],"footer.community":[0,"社区"],"footer.resources":[0,"资源"],"footer.solutions":[0,"解决方案"],"footer.trademark":[0,"商标"],"header.subscribe":[0,"订阅"],"footer.compliance":[0,"合规性"],"footer.free_plans":[0,"Free 计划"],"footer.impact_ESG":[0,"影响/ESG"],"posts.follow_on_X":[0,"在 X 上关注"],"footer.help_center":[0,"帮助中心"],"footer.network_map":[0,"网络地图"],"header.please_wait":[0,"请稍候"],"page.related_posts":[0,"相关帖子"],"search.result_stat":[0,"针对 {search_keyword} 的第 {search_range} 个搜索结果(共 {search_total} 个结果)"],"footer.case_studies":[0,"案例研究"],"footer.connect_2024":[0,"Connect 2024"],"footer.terms_of_use":[0,"服务条款"],"footer.white_papers":[0,"白皮书"],"footer.cloudflare_tv":[0,"Cloudflare TV"],"footer.community_hub":[0,"社区中心"],"footer.compare_plans":[0,"比较各项计划"],"footer.contact_sales":[0,"联系销售"],"header.contact_sales":[0,"联系销售团队"],"header.email_address":[0,"电子邮件地址"],"page.error.not_found":[0,"未找到页面"],"footer.developer_docs":[0,"开发人员文档"],"footer.privacy_policy":[0,"隐私政策"],"footer.request_a_demo":[0,"请求演示"],"page.continue_reading":[0,"继续阅读"],"footer.analysts_report":[0,"分析报告"],"footer.for_enterprises":[0,"企业级服务"],"footer.getting_started":[0,"开始使用"],"footer.learning_center":[0,"学习中心"],"footer.project_galileo":[0,"Project Galileo"],"pagination.newer_posts":[0,"较新的帖子"],"pagination.older_posts":[0,"较旧的帖子"],"posts.social_buttons.x":[0,"在 X 上讨论"],"search.icon_aria_label":[0,"搜索"],"search.source_location":[0,"来源/位置"],"footer.about_cloudflare":[0,"关于 Cloudflare"],"footer.athenian_project":[0,"Athenian Project"],"footer.become_a_partner":[0,"成为合作伙伴"],"footer.cloudflare_radar":[0,"Cloudflare Radar"],"footer.network_services":[0,"网络服务"],"footer.trust_and_safety":[0,"信任与安全"],"header.get_started_free":[0,"免费开始使用"],"page.search.placeholder":[0,"搜索 Cloudflare"],"footer.cloudflare_status":[0,"Cloudflare 状态"],"footer.cookie_preference":[0,"Cookie 首选项"],"header.valid_email_error":[0,"必须是有效的电子邮件地址。"],"search.result_stat_empty":[0,"显示第 {search_range} 个结果(共 {search_total} 个结果)"],"footer.connectivity_cloud":[0,"全球连通云"],"footer.developer_services":[0,"开发人员服务"],"footer.investor_relations":[0,"投资者关系"],"page.not_found.error_code":[0,"错误代码:404"],"search.autocomplete_title":[0,"请输入查询内容。按回车键发送"],"footer.logos_and_press_kit":[0,"标识与媒体资料包"],"footer.application_services":[0,"应用程序服务"],"footer.get_a_recommendation":[0,"获得推荐"],"posts.social_buttons.reddit":[0,"在 Reddit 上讨论"],"footer.sse_and_sase_services":[0,"SSE 和 SASE 服务"],"page.not_found.outdated_link":[0,"您可能使用了过期的链接,或者输入了错误的地址。"],"footer.report_security_issues":[0,"报告安全问题"],"page.error.error_message_page":[0,"抱歉,我们找不到您要打开的页面。"],"header.subscribe_notifications":[0,"订阅以接收新文章的通知:"],"footer.cloudflare_for_campaigns":[0,"Cloudflare for Campaigns"],"header.subscription_confimation":[0,"订阅已确认。感谢订阅!"],"posts.social_buttons.hackernews":[0,"在 Hacker News 上讨论"],"footer.diversity_equity_inclusion":[0,"多元、公平与包容"],"footer.critical_infrastructure_defense_project":[0,"关键基础设施防护项目"]}]}" ssr="" client="load" opts="{"name":"PostCard","value":true}" await-children="">2022-06-29
使用 LSM BPF,开发人员能够在无需配置或加载内核模块的情况下编写精细策略。LSM BPF 程序会在加载时进行验证,然后在调用路径中到达 LSM hook 时执行...
继续阅读 »2019-05-18
最近,在布拉格Linux网络会议Netdev 0x13上,我做了一个简短的演讲,题目是“Cloudflare上的Linux”。演讲最后主要是关于BPF(柏克莱封包过滤器)的。似乎,不管问题是什么——BPF都是答案。...
2019-02-19
我们正在努力让您在没有Cloudflare域的情况下部署Worker。您很快就可以将Cloudflare Workers部署到subdomain-of-your-choice.workers.dev (subdomain-of-your-choice为自定义子域),您现在可以在workers.dev上申请!...
2018-12-24
站点的第一个字节的时间(TTFB)是从用户开始导航到他们请求的页面的HTML开始到达的时间。在我运行WebPageTest的十多年里,缓慢的TTFB一直是我的痛苦之源。...
2018年11月23日 15:49
最近,在访问山景城的计算机历史博物馆的时,我深深地被过去的一些磁芯内存所吸引。我发现我完全不知道这些东西曾经是如何运作的。我想知道环是否旋转(它们没有),以及为什么每个环都有三根电线穿过(我仍然不明白它们是如何工作的)。更重要的是,我意识到我对现代计算机内存——动态RAM的工作方式知之甚少!...
2018年11月09日 14:57
Cloudflare有一个名为Workers的云计算平台。与我所知的其他所有云计算平台不同,它不使用容器或虚拟机。我们认为这是无服务器和云计算的未来,接下来我会告诉你为什么。...
2018年7月31日 15:00
目前已经有1000万个网站,应用程序和API使用Cloudflare加快其用户的上网速度。我们曾经最多通过151个数据中心每秒上传一千多万个请求。多年来,随着请求的增加,我们对我们的NGINX版本进行了许多修改。这篇文章讲述了其中一项修改内容。...
2018年1月31日 12:11
除其他有趣的功能外,Rust还具有强大的宏系统。不幸的是,即使在阅读了《The Book》和各种教程之后,当涉及到尝试实现一个涉及处理不同元素的复杂列表的宏时,我仍然很难理解应该如何做,并且在花了一些时间后,我才突然灵光一闪,开始对所有内容使用宏 :) (好吧,...
2018年1月15日 13:49
在Cloudflare,我们有很多在“野外”互联网上操作服务器的经验。但我们一直在提高我们对这种“妖术”的掌握。在这篇博客中,我们触及了互联网协议的多个黑暗角落:比如理解FIN-WAIT-2或接收缓冲区调优。...