<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:#954F72;
text-decoration:underline;}
.MsoChpDefault
{mso-style-type:export-only;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style></head><body lang=EN-US link=blue vlink="#954F72"><div class=WordSection1><p class=MsoNormal>> We're in agreement here that eliminating the TOCTOU is the only way to</p><p class=MsoNormal>> eliminate the vulnerability. However, much of security is about taking</p><p class=MsoNormal>> many small steps to mitigate security issues and reduce attack vectors</p><p class=MsoNormal>> as part of defense-in-depth.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Defense in depth is about taking a system that you think is secure, and building additional barriers such that compromise of one part of that system does not compromise a machine. Defense in depth is not a thing when the original thing is already full of holes. There is no defense in depth thing you can do to an API like exists to avoid this problem.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Billy3</p><p class=MsoNormal><o:p> </o:p></p><div style='mso-element:para-border-div;border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in'><p class=MsoNormal style='border:none;padding:0in'><b>From: </b><a href="mailto:aaron@aaronballman.com">Aaron Ballman</a><br><b>Sent: </b>Wednesday, July 18, 2018 11:03 AM<br><b>To: </b><a href="mailto:gromer@google.com">Geoffrey Romer</a><br><b>Cc: </b><a href="mailto:billy.oneal@gmail.com">Billy O'Neal</a>; <a href="mailto:eric@efcs.ca">Eric Fiselier</a>; <a href="mailto:cfe-dev@lists.llvm.org">Clang Dev</a>; <a href="mailto:mclow.lists@gmail.com">Marshall Clow</a>; <a href="mailto:titus@google.com">Titus Winters</a><br><b>Subject: </b>Re: [cfe-dev] [libc++][RFC] Implementing Directory Entry CachingforFilesystem</p></div><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>On Wed, Jul 18, 2018 at 1:46 PM, Geoffrey Romer <gromer@google.com> wrote:</p><p class=MsoNormal>><o:p> </o:p></p><p class=MsoNormal>> On Wed, Jul 18, 2018 at 9:52 AM Aaron Ballman <aaron@aaronballman.com></p><p class=MsoNormal>> wrote:</p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>> On Tue, Jul 17, 2018 at 5:53 PM, Geoffrey Romer <gromer@google.com> wrote:</p><p class=MsoNormal>>> ></p><p class=MsoNormal>>> ></p><p class=MsoNormal>>> > On Tue, Jul 17, 2018 at 10:40 AM Billy O'Neal <billy.oneal@gmail.com></p><p class=MsoNormal>>> > wrote:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> Does anyone have an example of something that is secure without caching</p><p class=MsoNormal>>> >> that is insecure with caching? All of the examples posted as</p><p class=MsoNormal>>> >> problematic are</p><p class=MsoNormal>>> >> still insecure.</p><p class=MsoNormal>>> ></p><p class=MsoNormal>>> ></p><p class=MsoNormal>>> > +1. By my reading, different caching decisions can only make TOCTOU</p><p class=MsoNormal>>> > problems</p><p class=MsoNormal>>> > more or less acute; caching can't introduce TOCTOU problems that don't</p><p class=MsoNormal>>> > already exist.</p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>> That is my belief as well. However, I don't find the argument to be</p><p class=MsoNormal>>> persuasive, so it's a -1 from me.</p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>> > From that point of view, caching could actually be helpful,</p><p class=MsoNormal>>> > by making the TOCTOU problems more obvious.</p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>> Caching is hidden from the user's view, and I fail to see how</p><p class=MsoNormal>>> something hidden from the user's view will will make anything more</p><p class=MsoNormal>>> obvious. What caching does do is extend the length of time over which</p><p class=MsoNormal>>> TOCTOU bugs can occur, which is worse behavior from a security</p><p class=MsoNormal>>> perspective. Users will definitely introduce exciting TOCTOU bugs into</p><p class=MsoNormal>>> their code with or without the caching mechanism, but I'm worried</p><p class=MsoNormal>>> about worsening the effects in practice.</p><p class=MsoNormal>><o:p> </o:p></p><p class=MsoNormal>><o:p> </o:p></p><p class=MsoNormal>> Generally speaking, I would expect "worsening the effects" of the bugs to</p><p class=MsoNormal>> make those bugs more obvious.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>I don't think that applies to cases that are timing based. You have to</p><p class=MsoNormal>know to be actively testing that scenario to notice the worsening</p><p class=MsoNormal>effects, at which point you'd likely have already fixed the TOCTOU.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>>> > The only change we could</p><p class=MsoNormal>>> > meaningfully make here is to give users some conditions under which</p><p class=MsoNormal>>> > non-modifying operations on the same file are guaranteed to reflect a</p><p class=MsoNormal>>> > single</p><p class=MsoNormal>>> > self-consistent state of the file (which may or may not be the present</p><p class=MsoNormal>>> > state), but the benefit of that seems minimal.</p><p class=MsoNormal>>> ></p><p class=MsoNormal>>> > I think this ship sailed when we decided to standardize a TOCTOU-prone</p><p class=MsoNormal>>> > API;</p><p class=MsoNormal>>> > all we can do now is try to educate users about what not to use</p><p class=MsoNormal>>> > std::filesystem for (e.g. anything remotely related to security).</p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>> "This doesn't introduce new security issues, it just makes existing</p><p class=MsoNormal>>> ones worse" is not an argument that leaves me with warm, fuzzy</p><p class=MsoNormal>>> feelings. The goal is obviously to prevent the TOCTOU bugs in the</p><p class=MsoNormal>>> first place, but if we cannot achieve that, we shouldn't exacerbate</p><p class=MsoNormal>>> the TOCTOU problems only because we can't achieve the ideal.</p><p class=MsoNormal>><o:p> </o:p></p><p class=MsoNormal>><o:p> </o:p></p><p class=MsoNormal>> That's not so obvious to me. If exacerbating the TOCTOU problems makes</p><p class=MsoNormal>> people more aware of those problems, that could well be a net win.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>How is it making more people aware of the problem, though? Silently</p><p class=MsoNormal>exacerbating the issue doesn't mean people are going to become aware</p><p class=MsoNormal>of it when they previously were not, unless you consider "there's a</p><p class=MsoNormal>new CVE out today" being the kind of education that raises awareness,</p><p class=MsoNormal>but I'd hardly call that a net win.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>> Conversely, to the extent that the caching design makes it easier to use</p><p class=MsoNormal>> std::filesystem in security-sensitive contexts, that is likely to be a net</p><p class=MsoNormal>> loss, because std::filesystem simply should not be used in</p><p class=MsoNormal>> security-sensitive contexts.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Last time I looked into it, Clang and LLVM had quite a few TOCTOU</p><p class=MsoNormal>bugs. No one was compelled to fix them because hey, we're just a</p><p class=MsoNormal>compiler, so who cares -- it's not a security-sensitive context. Well,</p><p class=MsoNormal>until people started running it on web servers... (It's been a number</p><p class=MsoNormal>of years since I looked, and we may have improved this since clangd</p><p class=MsoNormal>came along, but the example still holds.)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>The trouble is that "security-sensitive context" is a moving target</p><p class=MsoNormal>for a whole lot of code.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>> Keep in mind, security exploits are generally not statistical in nature;</p><p class=MsoNormal>> halving the time window for a TOCTOU attack does not halve your</p><p class=MsoNormal>> vulnerability, because the components of the attack are not occurring at</p><p class=MsoNormal>> random; they're being induced by an attacker. Shortening the time window may</p><p class=MsoNormal>> have some security benefit on the margins in terms of increasing the effort</p><p class=MsoNormal>> required for a successful exploit, but that's highly contingent and</p><p class=MsoNormal>> uncertain. I expect the security benefits of eliminating a TOCTOU</p><p class=MsoNormal>> vulnerability (e.g. by using a safer filesystem API) to dwarf the benefits</p><p class=MsoNormal>> of almost any reduction in the vulnerability time window.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>We're in agreement here that eliminating the TOCTOU is the only way to</p><p class=MsoNormal>eliminate the vulnerability. However, much of security is about taking</p><p class=MsoNormal>many small steps to mitigate security issues and reduce attack vectors</p><p class=MsoNormal>as part of defense-in-depth.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>I guess my point is: let's not be quick to say "well, we can't solve</p><p class=MsoNormal>this to the ideal, so we can do whatever we want in the name of</p><p class=MsoNormal>performance." As history has unkindly demonstrated, that way lies many</p><p class=MsoNormal>years of CVEs. I think a lit review of TOCTOU papers might be</p><p class=MsoNormal>interesting to see if anyone has explored the ramifications of a</p><p class=MsoNormal>widened time window. I'll try to do that when I have a spare moment,</p><p class=MsoNormal>but if anyone gets to it before me, I'd love to hear the results.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>~Aaron</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>><o:p> </o:p></p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>> ~Aaron</p><p class=MsoNormal>>><o:p> </o:p></p><p class=MsoNormal>>> ></p><p class=MsoNormal>>> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> Billy3</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> From: Aaron Ballman</p><p class=MsoNormal>>> >> Sent: Tuesday, July 17, 2018 4:46 AM</p><p class=MsoNormal>>> >> To: Eric Fiselier</p><p class=MsoNormal>>> >> Cc: clang developer list; Marshall Clow; Titus Winters; Billy O'Neal;</p><p class=MsoNormal>>> >> Geoffrey Romer</p><p class=MsoNormal>>> >> Subject: Re: [cfe-dev] [libc++][RFC] Implementing Directory Entry</p><p class=MsoNormal>>> >> Caching</p><p class=MsoNormal>>> >> forFilesystem</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> Thank you for putting this together, I greatly appreciate it!</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> Out of curiosity, is the caching behavior something you expect you'll</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> make configurable for users of libc++ (for instance, a macro to enable</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> or disable caching), or are there issues preventing such an</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> implementation? My feeling is that we're going to have the usual push</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> and pull between security and performance where different users will</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> have different (and equally valid) use cases in mind justifying the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> need for the performance provided by caching or the security red flags</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> enhanced by not caching. We should obviously pick a good default</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> behavior (and can argue over the definition of "good" in that</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> context), but I think no matter what option we pick, users will want</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> the other option to be available.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ~Aaron</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> On Mon, Jul 16, 2018 at 10:39 PM, Eric Fiselier via cfe-dev</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> <cfe-dev@lists.llvm.org> wrote:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Hi All,</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > I have a couple of questions and concerns regarding implementations</p><p class=MsoNormal>>> >> > of</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > P0317R1 [1], which I would like help from the community answering.</p><p class=MsoNormal>>> >> > The</p><p class=MsoNormal>>> >> > paper</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > changes `directory_entry` to cache a number of attributes, including</p><p class=MsoNormal>>> >> > file</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > status, permissions, file size, number of hard links, last write</p><p class=MsoNormal>>> >> > time,</p><p class=MsoNormal>>> >> > and</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > more. For reference, this is the interface of `directory_entry`</p><p class=MsoNormal>>> >> > before</p><p class=MsoNormal>>> >> > this</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > paper [2], and this is the interface after [3].</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > The implementation has a lot of latitude over which attributes it</p><p class=MsoNormal>>> >> > caches, if</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > any, and how it caches them. As I'll explain below, each different</p><p class=MsoNormal>>> >> > approach</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > can cause non-obvious behavior, possibly leading to TOCTOU bugs and</p><p class=MsoNormal>>> >> > security</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > vulnerabilities!</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > My question for the community is this:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Given the considerations below, what should libc++ choose to do?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > 1. Cache nothing?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > 2. Cache as much as possible, when possible?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > 3. Something in between?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > I would like to land std::filesystem before the 7.0 branch, and doing</p><p class=MsoNormal>>> >> > so</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > requires deciding on which implementation to provide now.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Note that this paper only considers POSIX based implementations of</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > filesystem.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > TOCTOU Violations</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > ============================</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Time of check to time of use, or TOCTOU, is a class of software bugs</p><p class=MsoNormal>>> >> > caused</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > by changes in a system between the time a condition is checked, and</p><p class=MsoNormal>>> >> > the</p><p class=MsoNormal>>> >> > time</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > the result is used [4]. If libc++ chooses to do any caching in</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > directory_entry, it will be vulnerable to this. If libc++ chooses to</p><p class=MsoNormal>>> >> > do</p><p class=MsoNormal>>> >> > no</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > caching at all, it will also be vulnerable to this but in different</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > scenarios.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Most importantly, whichever approach is taken, libc++ will bare some</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > responsibility for the TOCTOU bugs it allows users to write</p><p class=MsoNormal>>> >> > accidently.</p><p class=MsoNormal>>> >> > So</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > it’s imperative we consider all approaches carefully.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Let’s take a simple example:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > void remove_symlinks_in_dir(path p) {</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > for (directory_entry ent : directory_iterator(p)) {</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > if (ent.is_symlink())</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > remove(ent);</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > }</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > }</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Above, a TOCTOU violation may occur if another process acts on the</p><p class=MsoNormal>>> >> > file</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > referenced by `ent`, changing the attributes between the point the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > directory_entry was created and the point at which the `is_symlink`</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > condition is checked.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > At this point it's important to note that <filesystem> interface is,</p><p class=MsoNormal>>> >> > in</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > general, vulnerable to TOCTOU --- even without directory_entry</p><p class=MsoNormal>>> >> > caching.</p><p class=MsoNormal>>> >> > For</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > example:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > void remove_symlinks_in_dir(path p) {</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > for (directory_entry ent : directory_iterator(p)) {</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > if (is_symlink(ent))</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > remove(ent);</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > }</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > }</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > In the above case, a TOCTOU violation still occurs, since changes to</p><p class=MsoNormal>>> >> > `ent`</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > can take place between the check and the call to `remove`. However,</p><p class=MsoNormal>>> >> > at</p><p class=MsoNormal>>> >> > least</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > the above example makes it clear *when* the check is occuring.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Simply eliminating caching will not prevent TOCTOU violations, but,</p><p class=MsoNormal>>> >> > in</p><p class=MsoNormal>>> >> > this</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > particular case, it would make them harder to write and make it more</p><p class=MsoNormal>>> >> > obvious</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > where they may occur. Having a cache both extends the period of time</p><p class=MsoNormal>>> >> > between</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > the check and the use, as well as hiding when the check actually</p><p class=MsoNormal>>> >> > occurs.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Perhaps the above concessions make it worthwhile to support a more</p><p class=MsoNormal>>> >> > efficient</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > interface with caching and fewer file system accesses?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > If we do choose to cache some attributes, then, at minimum, it should</p><p class=MsoNormal>>> >> > be</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > obvious to the user which values are cached and which are not. The</p><p class=MsoNormal>>> >> > following</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > section will explore the feasibility of this.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Directory Iteration VS Refresh</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > ==================================</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > The paper's intention is to allow attributes returned during</p><p class=MsoNormal>>> >> > directory</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > iteration to be accessed by the user without additional calls to the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > underlying filesystem.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > The cache is populated two different ways:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > During directory iteration, the cache is populated with only the</p><p class=MsoNormal>>> >> > attributes</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > returned by directory iteration function. With POSIX `readdir`, only</p><p class=MsoNormal>>> >> > the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > file type as returned by `lstat` is available.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Using the `refresh` function, either called directly by the user, or</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > implicitly by the constructors or modifying methods (Ex. `assign`).</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > `refresh` has the ability to fully populate the cache (but not</p><p class=MsoNormal>>> >> > atomically in</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > some cases, see the symlink considerations below).</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Note that const accessors may not update the cache.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Therefore the state of the cache depends on whether the</p><p class=MsoNormal>>> >> > `directory_entry`</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > was created during directory iteration or by the</p><p class=MsoNormal>>> >> > `directory_entry(path&)`</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > constructor, and whether there have been any intervening calls to</p><p class=MsoNormal>>> >> > `refresh`</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > or any other modifying member functions.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > The following case demonstrates a surprising TOCTOU violation, only</p><p class=MsoNormal>>> >> > when</p><p class=MsoNormal>>> >> > the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > `directory_entry` cache was populated during directory iteration, and</p><p class=MsoNormal>>> >> > not by</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > a call to refresh:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > // Assume the filesystem supports permissions on symlinks.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > bool is_readable_symlink(directory_entry ent) {</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > if (!ent.is_symlink())</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > return false;</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > // We should have the file_status for the symlink cached, right?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > file_status st = ent.symlink_status();</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > // Nope! Only when `refresh` has been called are the perms cached.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > assert(is_symlink(st)); // May fail!</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > return (st.permissions() & perms::others_read) != perms::none;</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > }</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > The above example is intended to demonstrate that the different</p><p class=MsoNormal>>> >> > accessors</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > may return a mix of cached and uncached values. Here `is_symlink()`</p><p class=MsoNormal>>> >> > is</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > cached, but `symlink_status()` may not be.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > If the symlink has been replaced with a regular file, then the result</p><p class=MsoNormal>>> >> > of</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > this function is potentially dangerous nonsense.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > So what happens when the user calls `refresh()` before accessing the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > attributes? Does this make it safer?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > The answer depends on the caching behavior of the implementation. and</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > whether that behavior provides "atomic" or "non-atomic" attribute</p><p class=MsoNormal>>> >> > access</p><p class=MsoNormal>>> >> > (as</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > defined in the next section).</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Atomic VS Non-Atomic Attribute Access</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > =============================================</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > As previously described, TOCTOU violations require there to be</p><p class=MsoNormal>>> >> > intervening</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > time between the check and the use. We'll call any filesystem</p><p class=MsoNormal>>> >> > function,</p><p class=MsoNormal>>> >> > or</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > set of functions, which don’t allow for TOCTOU bugs "atomic". All</p><p class=MsoNormal>>> >> > other</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > functions or set of functions are considered "non-atomic".</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Therefore, a `directory_entry` object can be said to provide "atomic</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > attribute access" across all accessors if and only if (A) all of the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > attributes are cached, and (B) the cache was populated atomically. A</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > non-caching implementation of `directory_entry` never provides atomic</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > attribute access.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Let’s consider the consequences using the following example:</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > bool is_empty_regular_file(path p) {</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > directory_entry ent(p); // Calls refresh()</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > return ent.is_regular_file() && ent.file_size() == 0;</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > }</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > In a non-caching implementation `refresh()` is a nop, and therefore</p><p class=MsoNormal>>> >> > opens</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > the user up to TOCTOU issues occuring between the call to</p><p class=MsoNormal>>> >> > `is_symlink()`</p><p class=MsoNormal>>> >> > and</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > `is_regular_file()`.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > In a fully-caching implementation, which provides atomic attribute</p><p class=MsoNormal>>> >> > access,</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > no such problem occurs.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > In this case it seems preferable for libc++ to provide a</p><p class=MsoNormal>>> >> > fully-caching</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > implementation with "atomic attribute access". But is this possible?</p><p class=MsoNormal>>> >> > The</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > answer is "sometimes, but not always" as we'll see below.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Problems with Symlinks And Refresh()</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > ===========================================</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Above we established that if refresh caches at all, then it should do</p><p class=MsoNormal>>> >> > so</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > "atomically", retrieving all attributes from the filesystem in a</p><p class=MsoNormal>>> >> > atomic</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > manner. Note that for symlinks, some of the cached attributes refer</p><p class=MsoNormal>>> >> > to</p><p class=MsoNormal>>> >> > the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > symlink (is_symlink() and `symlink_status()), while the rest refer to</p><p class=MsoNormal>>> >> > the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > linked entity (is_regular_file(), file_size(), etc).</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > When the directory entry does not refer to a symlink, a single call</p><p class=MsoNormal>>> >> > to</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > `lstat` provides enough information to fully populate the cache</p><p class=MsoNormal>>> >> > atomically.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > However, when the entity is a symlink, we would need a second call to</p><p class=MsoNormal>>> >> > `stat`</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > to determine the properties of the linked file.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Therefore, "atomic attribute access" is not possible to guarantee.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > An implementation may choose to partially populate the caches,</p><p class=MsoNormal>>> >> > omitting</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > attributes about the linked entity; or it may choose to fully</p><p class=MsoNormal>>> >> > populate</p><p class=MsoNormal>>> >> > the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > cache non-atomically using a non-atomic series of calls to `lstat`</p><p class=MsoNormal>>> >> > and</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > `stat`.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > The former case obfuscates from the user which attributes are cached</p><p class=MsoNormal>>> >> > and</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > which are not, opening them up to TOCTOU violations.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Worse yet, the latter case, which fully populates the cache</p><p class=MsoNormal>>> >> > non-atomically,</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > potentially commits a TOCTOU violation itself, and this violation is</p><p class=MsoNormal>>> >> > hidden</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > from the user, preventing them from knowing it exists or being able</p><p class=MsoNormal>>> >> > to</p><p class=MsoNormal>>> >> > do</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > anything about it.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Both solutions seem fraught with problems.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Conclusion</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > ===============</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > I hope to have shown the pros and cons of different directory entry</p><p class=MsoNormal>>> >> > caching</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > implementations. Now I need your help deciding what's best for</p><p class=MsoNormal>>> >> > Libc++!</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Personally, I think the best solution is to revert these changes to</p><p class=MsoNormal>>> >> > the</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > standard, since each possible implementation seems broken in one way</p><p class=MsoNormal>>> >> > or</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > another. Directory entries should not cache, and directory iterators</p><p class=MsoNormal>>> >> > should</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > not attempt to populate the cache incompletely. Afterwards, a better</p><p class=MsoNormal>>> >> > and</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > safer proposal can be put forward which to provides efficient and</p><p class=MsoNormal>>> >> > atomic</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > access to multiple attributes for the same entity can be proposed.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Unfortunately, it might be to late at this point to revert the paper,</p><p class=MsoNormal>>> >> > even</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > if the committee generally agrees with these problems.</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > Thoughts?</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > [1]</p><p class=MsoNormal>>> >> > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0317r1.html</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > [2] https://en.cppreference.com/w/cpp/experimental/fs/directory_entry</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > [3] https://en.cppreference.com/w/cpp/filesystem/directory_entry</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > [4] https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > _______________________________________________</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > cfe-dev mailing list</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > cfe-dev@lists.llvm.org</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >> ></p><p class=MsoNormal>>> >></p><p class=MsoNormal>>> >></p><p class=MsoNormal><o:p> </o:p></p></div></body></html>