diff options
author | Florian Weimer <fweimer@redhat.com> | 2020-02-18 17:52:27 +0100 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2020-02-18 17:52:27 +0100 |
commit | a492b1e5ef7ab50c6fdd4e4e9879ea5569ab0a6c (patch) | |
tree | 5d8e3df1b0ec115d93d47bbf83a5c03a9bed4b84 /sysdeps/unix/sysv/linux | |
parent | f4349837d93b4dfe9ba09791e280ee2d6c99919f (diff) | |
download | glibc-a492b1e5ef7ab50c6fdd4e4e9879ea5569ab0a6c.tar.gz glibc-a492b1e5ef7ab50c6fdd4e4e9879ea5569ab0a6c.tar.xz glibc-a492b1e5ef7ab50c6fdd4e4e9879ea5569ab0a6c.zip |
Linux: Work around kernel bugs in chmod on /proc/self/fd paths [BZ #14578]
It appears that the ability to change symbolic link modes through such paths is unintended. On several file systems, the operation fails with EOPNOTSUPP, even though the symbolic link permissions are updated. The expected behavior is a failure to update the permissions, without file system changes. Reviewed-by: Matheus Castanho <msc@linux.ibm.com>
Diffstat (limited to 'sysdeps/unix/sysv/linux')
-rw-r--r-- | sysdeps/unix/sysv/linux/fchmodat.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/sysdeps/unix/sysv/linux/fchmodat.c b/sysdeps/unix/sysv/linux/fchmodat.c index 719053b333..17eca54051 100644 --- a/sysdeps/unix/sysv/linux/fchmodat.c +++ b/sysdeps/unix/sysv/linux/fchmodat.c @@ -45,6 +45,30 @@ fchmodat (int fd, const char *file, mode_t mode, int flag) caller can treat them as temporary if necessary. */ return pathfd; + /* Use fstatat because fstat does not work on O_PATH descriptors + before Linux 3.6. */ + struct stat64 st; + if (fstatat64 (pathfd, "", &st, AT_EMPTY_PATH) != 0) + { + __close_nocancel (pathfd); + return -1; + } + + /* Some Linux versions with some file systems can actually + change symbolic link permissions via /proc, but this is not + intentional, and it gives inconsistent results (e.g., error + return despite mode change). The expected behavior is that + symbolic link modes cannot be changed at all, and this check + enforces that. */ + if (S_ISLNK (st.st_mode)) + { + __close_nocancel (pathfd); + __set_errno (EOPNOTSUPP); + return -1; + } + + /* For most file systems, fchmod does not operate on O_PATH + descriptors, so go through /proc. */ char buf[32]; if (__snprintf (buf, sizeof (buf), "/proc/self/fd/%d", pathfd) < 0) { @@ -54,10 +78,6 @@ fchmodat (int fd, const char *file, mode_t mode, int flag) return -1; } - /* This operates directly on the symbolic link if it is one. - /proc/self/fd files look like symbolic links, but they are - not. (fchmod and fchmodat do not work on O_PATH descriptors, - similar to fstat before Linux 3.6.) */ int ret = __chmod (buf, mode); if (ret != 0) { |