{"id":1441,"date":"2020-09-21T16:32:16","date_gmt":"2020-09-21T23:32:16","guid":{"rendered":"https:\/\/outflux.net\/blog\/?p=1441"},"modified":"2022-04-04T16:32:36","modified_gmt":"2022-04-04T23:32:36","slug":"security-things-in-linux-v5-7","status":"publish","type":"post","link":"https:\/\/outflux.net\/blog\/archives\/2020\/09\/21\/security-things-in-linux-v5-7\/","title":{"rendered":"security things in Linux v5.7"},"content":{"rendered":"<p>Previously: <a href=\"\/blog\/archives\/2020\/09\/02\/security-things-in-linux-v5-6\/\">v5.6<\/a><\/p>\n<p>Linux <a href=\"https:\/\/lore.kernel.org\/lkml\/CAHk-=wiZGrCkiBB1V7bxp8NZH6yWi9mPM4ptMW16OzOiNprBFA@mail.gmail.com\">v5.7 was released at the end of May<\/a>. Here\u2019s my summary of various security things that caught my attention:<\/p>\n<p><strong id=\"v5.7-pac\">arm64 kernel pointer authentication<\/strong><br \/>\nWhile the ARMv8.3 CPU &#8220;Pointer Authentication&#8221; (PAC) feature <a href=\"\/blog\/archives\/2019\/03\/12\/security-things-in-linux-v5-0\/\">landed for userspace already<\/a>, Kristina Martsenko has now <a href=\"https:\/\/git.kernel.org\/linus\/74afda4016a7437e6e425c3370e4b93b47be8ddf\">landed PAC support in kernel mode<\/a>. The current implementation uses <code>PACIASP<\/code> which protects the saved stack pointer, similar to the existing <code>CONFIG_STACKPROTECTOR<\/code> feature, only faster. This also paves the way to sign and check pointers stored in the heap, as a way to defeat function pointer overwrites in those memory regions too. Since the behavior is different from the traditional stack protector, Amit Daniel Kachhap added an <a href=\"https:\/\/git.kernel.org\/linus\/6cb6982f42cbfaf5e50af1069451a8828231ffb9\">LKDTM test for PAC<\/a> as well.<\/p>\n<p><strong>BPF LSM<\/strong><br \/>\nThe kernel&#8217;s Linux Security Module (LSM) API provide a way to write security modules that have traditionally implemented various Mandatory Access Control (MAC) systems like SELinux, AppArmor, etc. The LSM hooks are numerous and no one LSM uses them all, as some hooks are much more specialized (like those used by IMA, Yama, LoadPin, etc). There was not, however, any way to externally attach to these hooks (not even through a regular loadable kernel module) nor build fully dynamic security policy, until KP Singh landed the API for <a href=\"https:\/\/git.kernel.org\/linus\/4dece7f3b9258e812795443b4bf64ff9454a0411\">building LSM policy using BPF<\/a>. With <code>CONFIG_BPF_LSM=y<\/code>, it is possible (for a privileged process) to write kernel LSM hooks in BPF, allowing for totally custom security policy (and reporting).<\/p>\n<p><strong><code>execve()<\/code> deadlock refactoring<\/strong><br \/>\nThere have been a number of long-standing races in the kernel&#8217;s process launching code where ptrace could deadlock. Fixing these has been attempted several times over the last many years, but Eric W. Biederman and Ernd Edlinger decided to dive in, and successfully landed the a series of refactorings, <a href=\"https:\/\/git.kernel.org\/linus\/eea9673250db4e854e9998ef9da6d4584857f0ea\">splitting up the problematic locking<\/a> and refactoring their uses to <a href=\"https:\/\/git.kernel.org\/linus\/3e74fabd39710ee29fa25618d2c2b40cfa7d76c7\">remove the deadlocks<\/a>. While he was at it, Eric also <a href=\"https:\/\/git.kernel.org\/linus\/d1e7fd6462ca9fc76650fbe6ca800e35b24267da\">extended the <code>exec_id<\/code> counter to 64 bits<\/a> to avoid the possibility of the counter wrapping and allowing an attacker to send arbitrary signals to processes they normally shouldn&#8217;t be able to.<\/p>\n<p><strong id=\"v5.7-slub\">slub freelist obfuscation improvements<\/strong><br \/>\nAfter Silvio Cesare observed some weaknesses in the implementation of <code>CONFIG_SLAB_FREELIST_HARDENED<\/code>&#8216;s freelist pointer content obfuscation, I <a href=\"https:\/\/git.kernel.org\/linus\/1ad53d9fa3f6168ebcf48a50e08b170432da2257\">improved their bit diffusion<\/a>, which makes attacks require significantly more memory content exposures to defeat the obfuscation. As part of the conversation, Vitaly Nikolenko pointed out that the freelist pointer&#8217;s <i>location<\/i> made it relatively easy to target too (for either disclosures or overwrites), so I <a href=\"https:\/\/git.kernel.org\/linus\/3202fa62fb43087387c65bfa9c100feffac74aa6\">moved it away from the edge of the slab<\/a>, making it harder to reach through small-sized overflows (which usually target the freelist pointer). As it turns out, there were a few assumptions in the kernel about the location of the freelist pointer, which had to also get <a href=\"https:\/\/git.kernel.org\/linus\/cbfc35a48609ceac978791e3ab9dde0c01f8cb20\">cleaned<\/a> <a href=\"https:\/\/git.kernel.org\/linus\/89b83f282d8ba380cf2124f88106c57df49c538c\">up<\/a>.<\/p>\n<p><strong id=\"v5.7-wx-riscv\">RISCV strict kernel memory protections<\/strong><br \/>\nZong Li <a href=\"https:\/\/git.kernel.org\/linus\/d27c3c90817e4c5ea655714065a725b4abd576f9\">implemented <code>STRICT_KERNEL_RWX<\/code> support for RISCV<\/a>. And to validate the results, following v5.6&#8217;s <a href=\"\/blog\/archives\/2020\/09\/02\/security-things-in-linux-v5-6\/\">generic page table dumping work<\/a>, he landed the <a href=\"https:\/\/git.kernel.org\/linus\/59c4da8640ccf4721d54d36835706f3eefb521a4\">RISCV page dumping code<\/a>. This means it&#8217;s much easier to examine the kernel&#8217;s page table layout when running a debug kernel (built with <code>PTDUMP_DEBUGFS<\/code>), visible in <code>\/sys\/kernel\/debug\/kernel_page_tables<\/code>.<\/p>\n<p><strong id=\"v5.7-array-bounds\">array index bounds checking<\/strong><br \/>\nThis is a pretty large area of work that touches a lot of overlapping elements (and history) in the Linux kernel. The short version is: C is bad at noticing when it uses an array index beyond the bounds of the declared array, and we need to fix that. For example, don&#8217;t do this:<\/p>\n<pre class=\"brush:c\">\r\nint foo[5];\r\n...\r\nfoo[8] = bar;\r\n<\/pre>\n<p>The long version gets complicated by the evolution of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Flexible_array_member\">&#8220;flexible array&#8221; structure members<\/a>, so we&#8217;ll pause for a moment and skim the surface of this topic. While things like <code>CONFIG_FORTIFY_SOURCE<\/code> try to catch these kinds of cases in the <code>memcpy()<\/code> and <code>strcpy()<\/code> family of functions, it doesn&#8217;t catch it in open-coded array indexing, as seen in the code above. GCC has a warning (<code>-Warray-bounds<\/code>) for these cases, but it was <a href=\"https:\/\/git.kernel.org\/linus\/44720996e2d79e47d508b0abe99b931a726a3197\">disabled by Linus<\/a> because of all the false positives seen due to &#8220;fake&#8221; flexible array members. Before flexible arrays were standardized, GNU C supported &#8220;zero sized&#8221; array members. And before that, C code would use a 1-element array. These were all designed so that some structure could be the &#8220;header&#8221; in front of some data blob that could be addressable through the last structure member:<\/p>\n<pre class=\"brush:c\">\r\n\/* 1-element array *\/\r\nstruct foo {\r\n    ...\r\n    char contents[1];\r\n};\r\n\r\n\/* GNU C extension: 0-element array *\/\r\nstruct foo {\r\n    ...\r\n    char contents[0];\r\n};\r\n\r\n\/* C standard: flexible array *\/\r\nstruct foo {\r\n    ...\r\n    char contents[];\r\n};\r\n\r\ninstance = kmalloc(sizeof(struct foo) + content_size);\r\n<\/pre>\n<p>Converting all the zero- and one-element array members to flexible arrays is one of Gustavo A. R. Silva&#8217;s goals, and <a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/log\/?h=v5.7&#038;qt=grep&#038;q=flexible+array\">hundreds of these changes started landing<\/a>. Once fixed, <code>-Warray-bounds<\/code> can be re-enabled. Much more detail can be found in the kernel&#8217;s <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/process\/deprecated.html#zero-length-and-one-element-arrays\">deprecation<\/a> docs.<\/p>\n<p>However, that will only catch the &#8220;visible at compile time&#8221; cases. For runtime checking, the Undefined Behavior Sanitizer has an option for adding runtime array bounds checking for catching things like this where the compiler cannot perform a static analysis of the index values:<\/p>\n<pre class=\"brush:c\">\r\nint foo[5];\r\n...\r\nfor (i = 0; i < some_argument; i++) {\r\n    ...\r\n    foo[i] = bar;\r\n    ...\r\n}\r\n<\/pre>\n<p>It was, however, not separate (via kernel Kconfig) until Elena Petrova and I <a href=\"https:\/\/git.kernel.org\/linus\/277a10850f9f4cb3429faf59293e2c89b1a320be\">split it out into <code>CONFIG_UBSAN_BOUNDS<\/code><\/a>, which is fast enough for production kernel use. With this enabled, it's now possible to instrument the kernel to catch these conditions, which seem to come up with some regularity in Wi-Fi and Bluetooth drivers for some reason. Since UBSAN (and the other Sanitizers) only <code>WARN()<\/code> by default, system owners need to set <code>panic_on_warn=1<\/code> too if they want to defend against attacks targeting these kinds of flaws. Because of this, and to avoid bloating the kernel image with all the warning messages, I <a href=\"https:\/\/git.kernel.org\/linus\/0887a7ebc97770c7870abf3075a2e8cd502a7f52\">introduced <code>CONFIG_UBSAN_TRAP<\/code><\/a> which effectively turns these conditions into a <code>BUG()<\/code> without needing additional sysctl settings.<\/p>\n<p><strong id=\"v5.7-scnprintf\">Fixing \"additive\" <code>snprintf()<\/code> usage<\/strong><br \/>\nA common idiom in C for building up strings is to use <code>sprintf()<\/code>'s return value to increment a pointer into a string, and build a string with more <code>sprintf()<\/code> calls:<\/p>\n<pre class=\"brush:c\">\r\n\/* safe if strlen(foo) + 1 < sizeof(string) *\/\r\nwrote  = sprintf(string, \"Foo: %s\\n\", foo);\r\n\/* overflows if strlen(foo) + strlen(bar) > sizeof(string) *\/\r\nwrote += sprintf(string + wrote, \"Bar: %s\\n\", bar);\r\n\/* writing way beyond the end of \"string\" now ... *\/\r\nwrote += sprintf(string + wrote, \"Baz: %s\\n\", baz);\r\n<\/pre>\n<p>The risk is that if these calls eventually walk off the end of the <code>string<\/code> buffer, it will start writing into other memory and create some bad situations. Switching these to <code>snprintf()<\/code> does not, however, make anything safer, since <code>snprintf()<\/code> returns how much it <i>would<\/i> have written:<\/p>\n<pre class=\"brush:c\">\r\n\/* safe, assuming available <= sizeof(string), and for this example\r\n * assume strlen(foo) < sizeof(string) *\/\r\nwrote  = snprintf(string, available, \"Foo: %s\\n\", foo);\r\n\/* if (strlen(bar) > available - wrote), this is still safe since the\r\n * write into \"string\" will be truncated, but now \"wrote\" has been\r\n * incremented by how much snprintf() *would* have written, so \"wrote\"\r\n * is now larger than \"available\". *\/\r\nwrote += snprintf(string + wrote, available - wrote, \"Bar: %s\\n\", bar);\r\n\/* string + wrote is beyond the end of string, and availabe - wrote wraps\r\n * around to a giant positive value, making the write effectively \r\n * unbounded. *\/\r\nwrote += snprintf(string + wrote, available - wrote, \"Baz: %s\\n\", baz);\r\n<\/pre>\n<p>So while the first overflowing call would be safe, the next one would be targeting beyond the end of the array and the size calculation will have wrapped around to a giant limit. Replacing this idiom with <code>scnprintf()<\/code> solves the issue because it only reports what was <i>actually<\/i> written. To this end, Takashi Iwai has been <a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/log\/?h=v5.7&#038;qt=grep&#038;q=Use+scnprintf\">landing a bunch scnprintf() fixes<\/a>.<\/p>\n<p>That's it for now! Let me know if there is anything else you think I should mention here. Next up: Linux <a href=\"\/blog\/archives\/2021\/02\/08\/security-things-in-linux-v5-8\/\">v5.8<\/a>.<\/p>\n<p style='text-align:left'>&copy; 2020 - 2022, <a href=\"https:\/\/outflux.net\/blog\/\">Kees Cook<\/a>. This work is licensed under a <a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/\">Creative Commons Attribution-ShareAlike 4.0 License<\/a>.<br \/><a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/\"><img decoding=\"async\" alt=\"CC BY-SA 4.0\" style=\"border-width:0\" src=\"https:\/\/i.creativecommons.org\/l\/by-sa\/4.0\/88x31.png\" \/><\/a> <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previously: v5.6 Linux v5.7 was released at the end of May. Here\u2019s my summary of various security things that caught my attention: arm64 kernel pointer authentication While the ARMv8.3 CPU &#8220;Pointer Authentication&#8221; (PAC) feature landed for userspace already, Kristina Martsenko has now landed PAC support in kernel mode. The current implementation uses PACIASP which protects [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,20,18,21,6,14,19],"tags":[],"_links":{"self":[{"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/posts\/1441"}],"collection":[{"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/comments?post=1441"}],"version-history":[{"count":31,"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/posts\/1441\/revisions"}],"predecessor-version":[{"id":1574,"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/posts\/1441\/revisions\/1574"}],"wp:attachment":[{"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/media?parent=1441"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/categories?post=1441"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/outflux.net\/blog\/wp-json\/wp\/v2\/tags?post=1441"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}