<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[&quot;Hahaha, look at how Rust failed here.&quot;]]></title><description><![CDATA[<p class="quote-inline">RE: <a href="https://infosec.exchange/@lcamtuf/116517194178120536" rel="nofollow noopener"><span>https://</span><span>infosec.exchange/@lcamtuf/1165</span><span>17194178120536</span></a></p><p>"Hahaha, look at how Rust failed here."</p><p>Maybe writing a utility like <code>cp</code> without TOCTOU, race conditions, symlink exploits and the like shouldn't be hard. Maybe copying a file shouldn't require more than a single line in userspace.</p><p>Maybe the UNIX file API is incomplete and could do with a number of revisions and updates. Maybe, after 40, 50 years we have learned a few things and should go through it with a fine comb.</p><p>Of course we shouldn't break userspace. We can still provide the old, broken calls.</p><p>But maybe we should discuss how we can come up with something systematic that doesn't suck and invite these kinds of bugs. In any language.</p>]]></description><link>https://board.circlewithadot.net/topic/4acb7ebf-974d-482d-b713-c4c15958a1cf/hahaha-look-at-how-rust-failed-here.</link><generator>RSS for Node</generator><lastBuildDate>Fri, 15 May 2026 01:53:21 GMT</lastBuildDate><atom:link href="https://board.circlewithadot.net/topic/4acb7ebf-974d-482d-b713-c4c15958a1cf.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 05 May 2026 08:31:58 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 10:37:08 GMT]]></title><description><![CDATA[<p><span><a href="/user/barubary%40infosec.exchange">@<span>barubary</span></a></span> You do not read a directory race-free in the snapshot sense.</p><p>A directory fd gives you a stable ref to THAT directory object, not a stable list of its children.</p><p>You CAN do</p><pre><code>dirfd = openat2(parentfd, "subdir", ...);<br />getdents64(dirfd, ...);      // or fdopendir/readdir<br />openat(dirfd, name, ...);    // act relative to the same directory<br /></code></pre><p>That avoids races involving CWD, replaced parent paths, symlinked path components, and “I checked one path but opened another”. </p><p>The entries themselves can still change while you read. Another process can create, delete, rename, or replace name after readdir() returns it and before openat() uses it. Linux does not make readdir() a frozen transaction. A directory fd pins the directory, not its contents.</p><p>So you'd</p><ul><li>open directory by fd</li><li>read entry name as bytes</li><li>openat(dirfd, entry_name, flags that express intent)</li><li>fstat the returned fd</li><li>decide based on the object actually opened</li><li>operate on the fd, not the path</li></ul><p>For recursive traversal, you extend the same rule: open child directories with openat() or openat2(), reject symlinks with flags/resolution constraints, keep dirfds on a stack, and perform later operations relative to those dirfds. </p><p>The oss-sec report’s uutils examples are mostly failures of this kind: path-based second operations, permission changes after creation, missing O_NOFOLLOW, missing O_EXCL, or creating too broadly and tightening later.</p><p>A truly race-free directory listing would mean one of three things:</p><ul><li>A filesystem snapshot.</li><li>Kernel support for transactional directory enumeration plus later object resolution against that transaction.</li><li>Locking/excluding all concurrent mutation, which Unix generally does not provide as a normal directory API.</li></ul><p>None of that is desireable, because it will scale like shit.</p><p>A snapshot is desirable for backups, indexing, forensics, package database consistency, and reproducible tree copies. But then the right answer is usually “use a filesystem snapshot”, not “make readdir() magic”.</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521528778363751</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521528778363751</guid><dc:creator><![CDATA[isotopp@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 10:37:08 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 10:28:32 GMT]]></title><description><![CDATA[<p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span> How do you read the contents of a directory in a race-free way?</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/barubary/statuses/116521494913509386</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/barubary/statuses/116521494913509386</guid><dc:creator><![CDATA[barubary@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 10:28:32 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 10:26:16 GMT]]></title><description><![CDATA[<p>What we do need is a Linux-centric update to W. Richard Stevens of APUE, an APLE book.</p><p>It would be discussing working with the Linux kernel API correctly, maybe implementing a libc or a libc-replacement, or a Python or Rust kernel API interface, correctly, with error handling, using code.</p><p>Stevens had a wonderful writing style, in English and in Code, showcasing the point made in a chapter without compromising on correctness and production-ready error handling.</p><p>But his books and the API he describes are old, and from the Linux Kernel PoV also inferior and outdated.</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521486047902169</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521486047902169</guid><dc:creator><![CDATA[isotopp@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 10:26:16 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 10:22:05 GMT]]></title><description><![CDATA[<p><span><a href="/user/hllizi%40hespere.de" rel="nofollow noopener">@<span>hllizi</span></a></span> See followup post: This has largely alread happened (improving the kernel fd API).</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521469593843468</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521469593843468</guid><dc:creator><![CDATA[isotopp@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 10:22:05 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 10:19:25 GMT]]></title><description><![CDATA[<p>File naming has been decoupled from the API that does things with files through these <code>fd</code>-based calls. So once you have an <code>fd</code> you should be set.</p><p>But:</p><p>Linux at the upper kernel layer does not change POSIX filename requirements. Filenames can be random garbage as long as they do not contain <code>pathsep</code> (the slash) and Nullbytes.</p><p>There is no clean, portable Linux syscall that says: “this directory accepts exactly UTF-8” or “this directory accepts arbitrary bytes.” The safe model is still: treat filenames as byte strings, not text, until you must display or create human-facing names.</p><p>That means your programming language must work with byte-arrays as filenames, even when that seems to be silly.</p><p>Linux pathname rules are byte-oriented: a pathname is a null-terminated byte sequence, interior null bytes are forbidden, and <code>/</code> is the separator, not a filename byte. </p><p>Directory reads likewise return null-terminated <code>d_name</code> entries, not Unicode strings.</p><p>For creating new human-facing filenames, emit valid UTF-8, preferably normalized to NFC at the application layer. But still be prepared for EINVAL, ENAMETOOLONG, EEXIST, or filesystem-specific rejection – some filesystems have magic filenames such as nul, prn or con and you won't be able to use them.</p><p>For accepting existing names, accept arbitrary bytes except <code>/</code> and <code>\0</code>. A UTF-8-only application that refuses to operate on invalid names will break on normal Unix trees, backups, tar extractions, old mounts, removable media, and network filesystems.</p><p>For detecting constraints, the options are weak:</p><p><code>statfs()</code> tells you the filesystem type, so you can special-case ext4, vfat, ntfs3, btrfs, overlayfs, etc., but that is not a semantic contract. You will need to know the rules for each filesystem type, there is no way to query them.</p><p><code>pathconf(path, _PC_NAME_MAX)</code> tells you name length limits, not encoding.</p><p><code>statx()</code> gives richer file metadata, but not a general filename-encoding capability, and surely not lists of reserved names or other fancyness.</p><p>Some filesystems have feature-specific behavior. ext4 casefolding, for example, stores a filesystem-wide encoding model for case-insensitive directories, defaulting to UTF-8 in the kernel documentation. That does not turn Linux pathname handling generally into Unicode.</p><p>So we DO have an API that could be race-free if you used to fully, and in order to do that you'd use Linux specific syscalls.</p><p>We LACK an API that can handle structured filenames, and answer questions about naming restrictions properly.</p><p>There is no</p><p><code>query_name_policy(dirfd)</code> → accepted encoding, normalization rules, case-sensitivity/case-folding, max component length in bytes and characters, reserved names, forbidden code points/bytes, equivalence rules, stable display form, and whether invalid legacy names may already exist.</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521459059608233</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521459059608233</guid><dc:creator><![CDATA[isotopp@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 10:19:25 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 10:11:36 GMT]]></title><description><![CDATA[<p>Part of that work is already done.</p><p>Linux’s syscall surface has a pattern: take a narrow primitive, remove implicit global state, make it composable, and push work into the kernel to avoid copies or races. <code>clone()</code>, <code>openat()</code>, and <code>splice()</code> fit that pattern well. </p><p>There are several other clusters of similar “upgrades”.</p><p>First, the <code>at</code> family generalizes path-based syscalls to operate relative to a directory file descriptor, which eliminates reliance on the process-wide CWD and closes race windows. </p><p>Besides <code>openat()</code>, there are <code>fstatat()</code>, <code>linkat()</code>, <code>renameat()</code>, <code>unlinkat()</code>, <code>mkdirat()</code>, <code>symlinkat()</code>, and more recently <code>openat2()</code> with a struct-based argument that lets you constrain resolution (no symlinks, stay beneath a dir, etc.). </p><p>POSIX standardized a subset of this idea in POSIX.1-2008: the basic *at() calls exist there, but Linux-specific extensions like <code>openat2()</code> and its resolution flags are not in POSIX.</p><p>Second, file-descriptor–centric design is pushed much further than POSIX. </p><p>Linux prefers operations that take FDs instead of paths and adds syscalls to obtain stable references: <code>O_PATH</code>, <code>name_to_handle_at()</code> and <code>open_by_handle_at()</code> (exportable file handles), <code>pidfd_open()</code> and the broader <code>pidfd</code> API for race-free process management, and <code>memfd_create()</code> for anonymous in-kernel files. </p><p>POSIX largely sticks to PIDs and pathnames; pidfds, memfd, and file handles are Linux-only.</p><p>Third, race-free event and I/O multiplexing. Linux moved from <code>select()</code>/<code>poll()</code> to <code>epoll</code> (edge-triggered, scalable readiness notification) and then to <code>io_uring</code>, which is a much bigger step: shared submission/completion queues, batching, fixed buffers/files, and true async operations with fewer syscalls. </p><p>POSIX includes <code>select()</code> and <code>poll()</code>, and optionally AIO (<code>aio_*</code>), but <code>epoll</code> and <code>io_uring</code> are Linux-specific.</p><p>Fourth, zero-copy and in-kernel data movement. Beyond <code>sendfile()</code> → <code>splice()</code>, there’s <code>tee()</code> (duplicate a pipe buffer without copying) and <code>vmsplice()</code> (map user pages into a pipe). </p><p>These let you build pipelines where data stays in kernel space. POSIX has <code>sendfile()</code> only via non-standard extensions on some systems; <code>splice</code>/<code>tee</code>/<code>vmsplice</code> are not in POSIX.</p><p>Fifth, vector and message-oriented batching. <code>readv()</code>/<code>writev()</code> exist in POSIX, but Linux extends batching with <code>preadv2()</code>/<code>pwritev2()</code> flags, <code>recvmmsg()</code>/<code>sendmmsg()</code> to amortize syscall overhead for datagrams, and various flags for finer control. </p><p>The <code>mmsg</code> calls are Linux-specific.</p><p>Sixth, futexes for user-space synchronization. <code>futex()</code> lets user space do uncontended locking without syscalls and only enter the kernel on contention. </p><p>This is the basis for efficient pthread mutexes/condvars on Linux. </p><p>POSIX defines the pthread APIs, not the futex primitive; futex is Linux-specific.</p><p>Seventh, namespaces and capabilities. Syscalls like <code>unshare()</code>, <code>setns()</code>, and <code>clone()</code> flags create per-process views of resources (mount, PID, net, user namespaces). </p><p>This is foundational for containers. </p><p>POSIX has no concept of namespaces or Linux capabilities.</p><p>Eighth, timers, event FDs, and signal improvements. <code>timerfd_create()</code>, <code>eventfd()</code>, and <code>signalfd()</code> turn timers, counters, and signals into file descriptors that integrate with <code>epoll</code>. </p><p>POSIX has timers and signals, but not these FD-based forms.</p><p>Ninth, process creation refinement. <code>clone3()</code> is a modern, extensible variant of <code>clone()</code> with a struct argument, similar in spirit to <code>openat2()</code>. </p><p>POSIX sticks with <code>fork()</code> and <code>posix_spawn()</code>; <code>clone*</code> is Linux-specific.</p><p>Tenth, memory management extensions. <code>mremap()</code>, <code>madvise()</code> flags beyond POSIX, <code>userfaultfd()</code> (handle page faults in user space), <code>memfd_secret</code> (restricted mappings). </p><p>POSIX defines <code>mmap()</code>/<code>mprotect()</code>/<code>msync()</code>; the rest are Linux extensions.</p><p>Eleventh, mount API overhaul. The newer mount API (<code>open_tree()</code>, <code>move_mount()</code>, <code>fsopen()</code>, <code>fsconfig()</code>, <code>fsmount()</code>) replaces the legacy <code>mount()</code> string interface with FD-based, race-resistant operations. </p><p>This is Linux-only.</p><p>Twelfth, BPF as a syscall-backed subsystem. The <code>bpf()</code> syscall exposes a programmable kernel data path and observability tools.</p><p>Entirely Linux-specific.</p><p>On POSIX coverage, the pattern is consistent: when Linux introduces a generalization that reduces races and global state in a way that’s broadly portable, a conservative subset may eventually appear in POSIX (the *at() family, readv/writev, posix_spawn). The more ambitious pieces that depend on Linux’s internal models or aim at performance and containerization (epoll, io_uring, pidfds, namespaces, futex, BPF, new mount API, zero-copy pipe primitives) are not in POSIX and are unlikely to be standardized in their current form.</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521428373524582</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521428373524582</guid><dc:creator><![CDATA[isotopp@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 10:11:36 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 10:02:56 GMT]]></title><description><![CDATA[<p><span><a href="/user/masek%40infosec.exchange">@<span>masek</span></a></span> </p><p>The biggest thing systemd brought was consistent, well documented behaviour. </p><p>That behaviour is questionable sometimes, but consistent for the user.</p><p>Start a systemd SYSCALL API and both the fediverse and reddit will DDOS itself. </p><p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span></p>]]></description><link>https://board.circlewithadot.net/post/https://norden.social/users/hikhvar/statuses/116521394270610223</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://norden.social/users/hikhvar/statuses/116521394270610223</guid><dc:creator><![CDATA[hikhvar@norden.social]]></dc:creator><pubDate>Tue, 05 May 2026 10:02:56 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 09:58:51 GMT]]></title><description><![CDATA[<p><span><a href="/user/iwein%40mas.to" rel="nofollow noopener">@<span>iwein</span></a></span> I don't care much. If the Linux kernel does it, the rest will eventually follow. Or not, but they are sidelined already anyway, so who cares.</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521378212949661</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/isotopp/statuses/116521378212949661</guid><dc:creator><![CDATA[isotopp@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 09:58:51 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 09:27:27 GMT]]></title><description><![CDATA[<p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span> <a href="https://fosstodon.org/@slink/116486258791687186" rel="nofollow noopener"><span>https://</span><span>fosstodon.org/@slink/116486258</span><span>791687186</span></a></p>]]></description><link>https://board.circlewithadot.net/post/https://fosstodon.org/users/slink/statuses/116521254751992390</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://fosstodon.org/users/slink/statuses/116521254751992390</guid><dc:creator><![CDATA[slink@fosstodon.org]]></dc:creator><pubDate>Tue, 05 May 2026 09:27:27 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 09:22:09 GMT]]></title><description><![CDATA[<p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span> You're aware, that this is a start of the next systemd-like discussion <img src="https://board.circlewithadot.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f603.png?v=28325c671da" class="not-responsive emoji emoji-android emoji--smiley" style="height:23px;width:auto;vertical-align:middle" title="😃" alt="😃" />?</p><p>I may not be 100% in agreement with everything systemd project does. But the people in that project  know things much better than I do and even I clearly can see the desperate need for modernization. </p><p>So I would give them a lot of leeway and am totally aghast about the amount of hate they receive.</p><p>What you (correctly) said above would (as a project) draw 10 times the ire systemd did.</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/masek/statuses/116521233886708502</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/masek/statuses/116521233886708502</guid><dc:creator><![CDATA[masek@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 09:22:09 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 09:22:05 GMT]]></title><description><![CDATA[<p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span> There is no hope for a better past. But we can at least learn from it.</p>]]></description><link>https://board.circlewithadot.net/post/https://floss.social/users/monospace/statuses/116521233632441748</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://floss.social/users/monospace/statuses/116521233632441748</guid><dc:creator><![CDATA[monospace@floss.social]]></dc:creator><pubDate>Tue, 05 May 2026 09:22:05 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 08:53:07 GMT]]></title><description><![CDATA[<p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span> That shit is hard, and the implementations on all operating systems are weirdly different. If only we could improve that instead of another magic "paradigm shift" eh?</p>]]></description><link>https://board.circlewithadot.net/post/https://mas.to/users/iwein/statuses/116521119776693892</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://mas.to/users/iwein/statuses/116521119776693892</guid><dc:creator><![CDATA[iwein@mas.to]]></dc:creator><pubDate>Tue, 05 May 2026 08:53:07 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 08:43:18 GMT]]></title><description><![CDATA[<p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span> Yet you both are right. <img src="https://board.circlewithadot.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f611.png?v=28325c671da" class="not-responsive emoji emoji-android emoji--expressionless" style="height:23px;width:auto;vertical-align:middle" title="😑" alt="😑" /></p>]]></description><link>https://board.circlewithadot.net/post/https://social.tchncs.de/users/aheadofthekrauts/statuses/116521081173965704</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://social.tchncs.de/users/aheadofthekrauts/statuses/116521081173965704</guid><dc:creator><![CDATA[aheadofthekrauts@social.tchncs.de]]></dc:creator><pubDate>Tue, 05 May 2026 08:43:18 GMT</pubDate></item><item><title><![CDATA[Reply to &quot;Hahaha, look at how Rust failed here.&quot; on Tue, 05 May 2026 08:40:08 GMT]]></title><description><![CDATA[<p><span><a href="/user/isotopp%40infosec.exchange">@<span>isotopp</span></a></span> Yes! The file system is just a big ball of race conditions bundled together (and so are processes/PIDs).</p>]]></description><link>https://board.circlewithadot.net/post/https://infosec.exchange/users/barubary/statuses/116521068662957105</link><guid isPermaLink="true">https://board.circlewithadot.net/post/https://infosec.exchange/users/barubary/statuses/116521068662957105</guid><dc:creator><![CDATA[barubary@infosec.exchange]]></dc:creator><pubDate>Tue, 05 May 2026 08:40:08 GMT</pubDate></item></channel></rss>