From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11970 invoked by alias); 30 Jul 2013 16:16:42 -0000 Mailing-List: contact glibc-bugs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: glibc-bugs-owner@sourceware.org Received: (qmail 11812 invoked by uid 48); 30 Jul 2013 16:16:38 -0000 From: "bugdal at aerifal dot cx" To: glibc-bugs@sourceware.org Subject: [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks Date: Tue, 30 Jul 2013 16:16:00 -0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: glibc X-Bugzilla-Component: libc X-Bugzilla-Version: unspecified X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: bugdal at aerifal dot cx X-Bugzilla-Status: NEW X-Bugzilla-Priority: P2 X-Bugzilla-Assigned-To: unassigned at sourceware dot org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit X-Bugzilla-URL: http://sourceware.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-SW-Source: 2013-07/txt/msg00181.txt.bz2 http://sourceware.org/bugzilla/show_bug.cgi?id=14578 --- Comment #8 from Rich Felker --- On modern Linux (just tested on 3.10.4), the following solution works with no race condition: 1. Check fstatat, fail if symlink. 2. Use openat with O_PATH|O_NOFOLLOW. 3. Use fstat on the resulting fd, fail if symlink. 4. Use fchmod on the resulting fd. Step 1 is not strictly necessary, but it's nice to definitively fail on symlinks that aren't racing, whereas the subsequent tests could fail spuriously on hitting the open file limit, etc. There are however failure cases that need to be considered: Step 2 can act as a plain O_RDONLY open if O_PATH is not available on the kernel in use. I believe this can be tested for by attempting to open /dev/null with O_PATH and trying to write to the resulting file descriptor. If it succeeds, the kernel lacks O_PATH. Note that, aside from the nasty case of opening a device file and having it do something when you open it, plain O_RDONLY would do just fine and would make this workaround work even on ancient kernels, BUT it will spuriously fail if the file is mode 000 and the caller is not root. Also, if O_PATH is not supported, O_NOFOLLOW will cause ELOOP if the target is a symlink, instead of opening a fd to the symlink itself, which would need to be treated as an error condition. Also note that, since O_NOFOLLOW Is being used, there is no danger of following a symlink to a device file if O_PATH is not supported. The bad behavior with devices could only happen if the device name were passed directly. Step 2 can also simply fail for reasons like having too many open files. Step 3 can also fail. On a large number of kernel versions (2.6 up through 3.5 or maybe a little later), file descriptors obtained by O_PATH are not valid for passing to fstat, fchmod, etc. I do not believe there is any workaround for this case, unless you want to fall back to just using O_RDONLY. Since current Linux admits a workaround, I believe a solution based on this approach should be applied to glibc. However, some more discussion is needed to determine how to handle old kernels and errors. -- You are receiving this mail because: You are on the CC list for the bug.