public inbox for glibc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
@ 2012-09-13 16:42 mgorny at gentoo dot org
  2012-09-13 17:01 ` [Bug libc/14578] " joseph at codesourcery dot com
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: mgorny at gentoo dot org @ 2012-09-13 16:42 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

             Bug #: 14578
           Summary: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on
                    non-symlinks
           Product: glibc
           Version: unspecified
            Status: NEW
          Severity: normal
          Priority: P2
         Component: libc
        AssignedTo: unassigned@sourceware.org
        ReportedBy: mgorny@gentoo.org
                CC: drepper.fsp@gmail.com
    Classification: Unclassified


Tested with glibc-2.15, the relevant code verified to be the same in current
git.
CHOST: x86_64-unknown-linux-gnu
Kernel: 3.5.0 (vanilla)

Whenever fchmodat() is called with AT_SYMLINK_NOFOLLOW on Linux, it
unconditionally fails with ENOTSUP. The following snippet from
sysdeps/unix/sysv/linux/fchmodat.c is responsible for that:

#ifndef __NR_lchmod     /* Linux so far has no lchmod syscall.  */
  if (flag & AT_SYMLINK_NOFOLLOW)
    {
      __set_errno (ENOTSUP);
      return -1;
    }
#endif

POSIX.2008 however specifies[1] that:

[EOPNOTSUPP]
  The AT_SYMLINK_NOFOLLOW bit is set in the flag argument,
  path names a symbolic link, and the system does not support changing
  ^^^^^^^^^^^^^^^^^^^^^^^^^^
  the mode of a symbolic link.

In other words, I believe that fchmodat() should only return ENOTSUP if
AT_SYMLINK_NOFOLLOW is requested on a symbolic link. On regular files, it
should just change the mode.

[1]:http://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
@ 2012-09-13 17:01 ` joseph at codesourcery dot com
  2012-09-13 17:05 ` joseph at codesourcery dot com
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: joseph at codesourcery dot com @ 2012-09-13 17:01 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #1 from joseph at codesourcery dot com <joseph at codesourcery dot com> 2012-09-13 17:01:22 UTC ---
glibc can't check if it's a symlink itself without a race condition.  
What does the kernel do if AT_SYMLINK_NOFOLLOW is passed to the fchmodat 
syscall (both on symlinks, and on non-symlinks?  (Any code expecting an 
lchmod syscall can clearly be removed from glibc in any case - chmod 
support for symlinks in future would have to be via a *at syscall to 
accord with current Linux kernel practice regarding adding syscalls - so 
#ifndef __NR_lchmod should be unconditional, #ifdef __NR_lchmod removed.)

If the syscall does the right thing, I suppose the check for 
AT_SYMLINK_NOFOLLOW could be moved after the code using the fchmodat 
syscall, so that the issue only applies to old kernels (for which it is 
unavoidable because of the race).

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
  2012-09-13 17:01 ` [Bug libc/14578] " joseph at codesourcery dot com
@ 2012-09-13 17:05 ` joseph at codesourcery dot com
  2012-09-13 22:40 ` bugdal at aerifal dot cx
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: joseph at codesourcery dot com @ 2012-09-13 17:05 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #2 from joseph at codesourcery dot com <joseph at codesourcery dot com> 2012-09-13 17:04:59 UTC ---
Ah, I see the problem is that the fchmodat syscall doesn't take a flags 
argument at all.  In that case I don't think this is fixable (given the 
race) without a new syscall, and then only fixable for kernels using the 
new syscall.  (I.e., unless anyone sees a way to avoid the race this 
should be SUSPENDED until the kernel is fixed.)

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
  2012-09-13 17:01 ` [Bug libc/14578] " joseph at codesourcery dot com
  2012-09-13 17:05 ` joseph at codesourcery dot com
@ 2012-09-13 22:40 ` bugdal at aerifal dot cx
  2012-09-13 23:07 ` joseph at codesourcery dot com
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: bugdal at aerifal dot cx @ 2012-09-13 22:40 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

Rich Felker <bugdal at aerifal dot cx> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugdal at aerifal dot cx

--- Comment #3 from Rich Felker <bugdal at aerifal dot cx> 2012-09-13 22:40:21 UTC ---
I'm not familiar with the semantics of O_PATH on Linux, but would it be
possible to work around thus bug by opening the pathname with O_PATH and then
using fstat on it to determine if it's a link? In other words, does O_PATH
permanently associate the file descriptor with the symbolic link itself, or
just with the current name the symbolic link has in the directory it's
contained it?

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (2 preceding siblings ...)
  2012-09-13 22:40 ` bugdal at aerifal dot cx
@ 2012-09-13 23:07 ` joseph at codesourcery dot com
  2012-09-13 23:09 ` bugdal at aerifal dot cx
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: joseph at codesourcery dot com @ 2012-09-13 23:07 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #4 from joseph at codesourcery dot com <joseph at codesourcery dot com> 2012-09-13 23:06:48 UTC ---
I don't know if O_PATH will do the trick.  If it does, what do kernels 
before 2.6.39 (when O_PATH was introduced) do when O_PATH is used?  (If 
they just ignore it and open the file as if O_PATH were not present, then 
we'd need to make sure not to try using O_PATH on older kernels, to avoid 
any side-effects from opening device files, for example.)

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (3 preceding siblings ...)
  2012-09-13 23:07 ` joseph at codesourcery dot com
@ 2012-09-13 23:09 ` bugdal at aerifal dot cx
  2012-09-13 23:17 ` bugdal at aerifal dot cx
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: bugdal at aerifal dot cx @ 2012-09-13 23:09 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #5 from Rich Felker <bugdal at aerifal dot cx> 2012-09-13 23:09:00 UTC ---
I seem to have a solution. In pseudo-code:

if (flags & AT_SYMLINK_NOFOLLOW) {
    tmpfd = openat(fd, pathname, O_PATH|O_NOFOLLOW);
    if (tmpfd < 0) {
        errno = ENOTSUPP;
        return -1;
    }
    int ret = fchmod(tmpfd, mode);
    close(tmpfd);
    return ret;
}

Obviously this needs some fixes for glibc, like avoiding cancellation points.

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (4 preceding siblings ...)
  2012-09-13 23:09 ` bugdal at aerifal dot cx
@ 2012-09-13 23:17 ` bugdal at aerifal dot cx
  2012-09-14  0:46 ` joseph at codesourcery dot com
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: bugdal at aerifal dot cx @ 2012-09-13 23:17 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #6 from Rich Felker <bugdal at aerifal dot cx> 2012-09-13 23:16:43 UTC ---
Joseph, you're right; actually, I was unfortunately testing on a pre-O_PATH
kernel and didn't notice this, so I can't say for sure yet whether the code
does what's desired on a new kernel with O_PATH. I can confirm your fear about
older kernels though; the kernel happily opens the underlying file, which could
be bad if it's a device file, etc. In order to test for working O_PATH, one
could first open "/" with O_PATH and attempt to call getdents on the resulting
fd. Assuming the open succeeded, that would work if and only if O_PATH support
is missing. If the open failed due to missing permissions, that would also mean
O_PATH support is missing. If it failed for another reason, we probably have a
resource exhaustion issue and can just pass the error up.

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (5 preceding siblings ...)
  2012-09-13 23:17 ` bugdal at aerifal dot cx
@ 2012-09-14  0:46 ` joseph at codesourcery dot com
  2013-07-30 16:16 ` bugdal at aerifal dot cx
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: joseph at codesourcery dot com @ 2012-09-14  0:46 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #7 from joseph at codesourcery dot com <joseph at codesourcery dot com> 2012-09-14 00:46:01 UTC ---
There are a few places with version number checks on the kernel version at 
runtime, I'd probably just use one of those to see if O_PATH is available 
(in the absence of a --enable-kernel=2.6.39 or later option that would 
define __ASSUME_O_PATH).

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (6 preceding siblings ...)
  2012-09-14  0:46 ` joseph at codesourcery dot com
@ 2013-07-30 16:16 ` bugdal at aerifal dot cx
  2013-07-30 16:53 ` bugdal at aerifal dot cx
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: bugdal at aerifal dot cx @ 2013-07-30 16:16 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #8 from Rich Felker <bugdal at aerifal dot cx> ---
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.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (7 preceding siblings ...)
  2013-07-30 16:16 ` bugdal at aerifal dot cx
@ 2013-07-30 16:53 ` bugdal at aerifal dot cx
  2013-08-02 16:21 ` bugdal at aerifal dot cx
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: bugdal at aerifal dot cx @ 2013-07-30 16:53 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #9 from Rich Felker <bugdal at aerifal dot cx> ---
Actually, we still have a problem. I hadn't checked cases that should succeed,
and in fact fchmod STILL fails on O_PATH files. So I still don't know any way
to avoid race conditions changing the permissions on a file unless you have
permission to open it...

-- 
You are receiving this mail because:
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (8 preceding siblings ...)
  2013-07-30 16:53 ` bugdal at aerifal dot cx
@ 2013-08-02 16:21 ` bugdal at aerifal dot cx
  2014-06-17  4:33 ` fweimer at redhat dot com
  2020-09-10 15:40 ` [Bug libc/14578] /proc-based emulation for lchmod, fchmodat bugdal at aerifal dot cx
  11 siblings, 0 replies; 13+ messages in thread
From: bugdal at aerifal dot cx @ 2013-08-02 16:21 UTC (permalink / raw)
  To: glibc-bugs

http://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #10 from Rich Felker <bugdal at aerifal dot cx> ---
I have solved the issue: while various syscalls such as fchmod, and even fstat
on all but very-new kernels, fail on O_PATH file descriptors, the corresponding
non-f-prefixed calls work on /proc/self/fd/%d.

I will be using this approach in musl libc to fix the fchmodat issue in a
completely race-free way that works on all O_PATH kernels, and works modulo the
need for read permissions to open the file even on older kernels. I will also
be using it to fix fchmod, fstat, etc. on O_PATH file descriptors, so that
O_PATH becomes a conforming implementation of O_SEARCH and O_EXEC. I think
glibc could do the same.

(Note that glibc may want to include the test I mentioned in an earlier post on
this issue to make sure O_PATH is supported, in case unintended opening of
files with O_RDONLY is deemed dangerous, e.g. for devices.)

-- 
You are receiving this mail because:
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (9 preceding siblings ...)
  2013-08-02 16:21 ` bugdal at aerifal dot cx
@ 2014-06-17  4:33 ` fweimer at redhat dot com
  2020-09-10 15:40 ` [Bug libc/14578] /proc-based emulation for lchmod, fchmodat bugdal at aerifal dot cx
  11 siblings, 0 replies; 13+ messages in thread
From: fweimer at redhat dot com @ 2014-06-17  4:33 UTC (permalink / raw)
  To: glibc-bugs

https://sourceware.org/bugzilla/show_bug.cgi?id=14578

Florian Weimer <fweimer at redhat dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |fweimer at redhat dot com
              Flags|                            |security-

-- 
You are receiving this mail because:
You are on the CC list for the bug.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug libc/14578] /proc-based emulation for lchmod, fchmodat
  2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
                   ` (10 preceding siblings ...)
  2014-06-17  4:33 ` fweimer at redhat dot com
@ 2020-09-10 15:40 ` bugdal at aerifal dot cx
  11 siblings, 0 replies; 13+ messages in thread
From: bugdal at aerifal dot cx @ 2020-09-10 15:40 UTC (permalink / raw)
  To: glibc-bugs

https://sourceware.org/bugzilla/show_bug.cgi?id=14578

--- Comment #19 from Rich Felker <bugdal at aerifal dot cx> ---
I've posted a proposed kernel patch that will make it so emulation isn't
needed: 

https://lkml.org/lkml/2020/9/10/671

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-09-10 15:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-13 16:42 [Bug libc/14578] New: fchmodat(..., AT_SYMLINK_NOFOLLOW) returns ENOTSUP on non-symlinks mgorny at gentoo dot org
2012-09-13 17:01 ` [Bug libc/14578] " joseph at codesourcery dot com
2012-09-13 17:05 ` joseph at codesourcery dot com
2012-09-13 22:40 ` bugdal at aerifal dot cx
2012-09-13 23:07 ` joseph at codesourcery dot com
2012-09-13 23:09 ` bugdal at aerifal dot cx
2012-09-13 23:17 ` bugdal at aerifal dot cx
2012-09-14  0:46 ` joseph at codesourcery dot com
2013-07-30 16:16 ` bugdal at aerifal dot cx
2013-07-30 16:53 ` bugdal at aerifal dot cx
2013-08-02 16:21 ` bugdal at aerifal dot cx
2014-06-17  4:33 ` fweimer at redhat dot com
2020-09-10 15:40 ` [Bug libc/14578] /proc-based emulation for lchmod, fchmodat bugdal at aerifal dot cx

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).