* [PATCH] Fix fchownat (BZ#3252)
@ 2006-09-25 15:08 Jakub Jelinek
0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2006-09-25 15:08 UTC (permalink / raw)
To: Ulrich Drepper; +Cc: Glibc hackers
Hi!
fchownat on many arches duplicates everything __chown and __lchown functions
do, which is quite error prone (at least the i386 and s390 versions don't
cope properly with AT_SYMLINK_NOFOLLOW) in all the various
--enable-kernel=x.y.z cases. The following patch simplifies that, only
handles the second most common case inline (for ppc __ASSUME_LCHOWN_SYSCALL,
for i386 and simila __ASSUME_32BITUIDS) and leaves the rest of the dirty
work to out of line __chown/__lchown (that is only for glibcs configured to
support < 2.3.39 (resp. < 2.1.18 on ppc), so not a big deal IMHO and it
decreases code duplication).
2006-09-25 Jakub Jelinek <jakub@redhat.com>
[BZ #3252]
* sysdeps/unix/sysv/linux/powerpc/fchownat.c (fchownat): Handle only
fchownat syscall and __ASSUME_LCHOWN_SYSCALL case inline, call __{,l}chown
to handle the rest.
* sysdeps/unix/sysv/linux/i386/fchownat.c (fchownat): Handle only
fchownat syscall and __ASSUME_32BITUIDS case inline, call __{,l}chown to
handle the rest.
* sysdeps/unix/sysv/linux/sparc/sparc32/fchownat.c: Include i386/fchownat.c.
* sysdeps/unix/sysv/linux/s390/s390-32/fchownat.c: Likewise.
* sysdeps/unix/sysv/linux/sh/fchownat.c: Likewise.
--- libc/sysdeps/unix/sysv/linux/powerpc/fchownat.c.jj 2006-08-08 17:41:55.000000000 +0200
+++ libc/sysdeps/unix/sysv/linux/powerpc/fchownat.c 2006-09-25 16:13:48.000000000 +0200
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -81,143 +81,30 @@ fchownat (int fd, const char *file, uid_
file = buf;
}
+# if __ASSUME_LCHOWN_SYSCALL
INTERNAL_SYSCALL_DECL (err);
-# if __ASSUME_LCHOWN_SYSCALL
if (flag & AT_SYMLINK_NOFOLLOW)
result = INTERNAL_SYSCALL (lchown, err, 3, file, owner, group);
else
result = INTERNAL_SYSCALL (chown, err, 3, file, owner, group);
-# else
- char link[PATH_MAX + 2];
- char path[2 * PATH_MAX + 4];
- int loopct;
- size_t filelen;
- static int libc_old_chown = 0 /* -1=old linux, 1=new linux, 0=unknown */;
-
- if (libc_old_chown == 1)
- {
- if (flag & AT_SYMLINK_NOFOLLOW)
- result = INTERNAL_SYSCALL (lchown, err, 3, __ptrvalue (file), owner,
- group);
- else
- result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
- group);
- goto out;
- }
-
-# ifdef __NR_lchown
- if (flag & AT_SYMLINK_NOFOLLOW)
- {
- result = INTERNAL_SYSCALL (lchown, err, 3, __ptrvalue (file), owner,
- group);
- goto out;
- }
-
- if (libc_old_chown == 0)
- {
- result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
- group);
- if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
- return result;
- if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
- {
- libc_old_chown = 1;
- goto fail;
- }
- libc_old_chown = -1;
- }
-# else
- if (flag & AT_SYMLINK_NOFOLLOW)
- {
- result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
- group);
- goto out;
- }
-# endif
-
- result = __readlink (file, link, PATH_MAX + 1);
- if (result == -1)
- {
-# ifdef __NR_lchown
- result = INTERNAL_SYSCALL (lchown, err, 3, __ptrvalue (file), owner,
- group);
-# else
- result = INTERNAL_SYSCALL (chown, err, 3, __ptrvalue (file), owner,
- group);
-# endif
- goto out;
- }
-
- filelen = strlen (file) + 1;
- if (filelen > sizeof (path))
- {
- errno = ENAMETOOLONG;
- return -1;
- }
- memcpy (path, file, filelen);
-
- /* 'The system has an arbitrary limit...' In practise, we'll hit
- ENAMETOOLONG before this, usually. */
- for (loopct = 0; loopct < 128; ++loopct)
- {
- size_t linklen;
-
- if (result >= PATH_MAX + 1)
- {
- errno = ENAMETOOLONG;
- return -1;
- }
-
- link[result] = 0; /* Null-terminate string, just-in-case. */
-
- linklen = strlen (link) + 1;
-
- if (link[0] == '/')
- memcpy (path, link, linklen);
- else
- {
- filelen = strlen (path);
-
- while (filelen > 1 && path[filelen - 1] == '/')
- --filelen;
- while (filelen > 0 && path[filelen - 1] != '/')
- --filelen;
- if (filelen + linklen > sizeof (path))
- {
- errno = ENAMETOOLONG;
- return -1;
- }
- memcpy (path + filelen, link, linklen);
- }
-
- result = __readlink (path, link, PATH_MAX + 1);
-
- if (result == -1)
- {
-# ifdef __NR_lchown
- result = INTERNAL_SYSCALL (lchown, err, 3, path, owner, group);
-# else
- result = INTERNAL_SYSCALL (chown, err, 3, path, owner, group);
-# endif
- goto out;
- }
- }
- __set_errno (ELOOP);
- return -1;
-
- out:
-# endif
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
{
-# if !__ASSUME_LCHOWN_SYSCALL
- fail:
-# endif
__atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
- result = -1;
+ return -1;
}
+# else
+ /* Don't inline the rest to avoid unnecessary code duplication. */
+ if (flag & AT_SYMLINK_NOFOLLOW)
+ result = __lchown (file, owner, group);
+ else
+ result = __chown (file, owner, group);
+ if (result < 0)
+ __atfct_seterrno (errno, fd, buf);
+# endif
return result;
+
#endif
}
--- libc/sysdeps/unix/sysv/linux/sparc/sparc32/fchownat.c.jj 2006-02-28 20:07:32.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/sparc/sparc32/fchownat.c 2006-09-25 16:15:46.000000000 +0200
@@ -1 +1 @@
-#include <sysdeps/unix/sysv/linux/sh/fchownat.c>
+#include <sysdeps/unix/sysv/linux/i386/fchownat.c>
--- libc/sysdeps/unix/sysv/linux/i386/fchownat.c.jj 2006-08-08 17:41:55.000000000 +0200
+++ libc/sysdeps/unix/sysv/linux/i386/fchownat.c 2006-09-25 16:12:06.000000000 +0200
@@ -30,33 +30,6 @@
#include <linux/posix_types.h>
#include <kernel-features.h>
-/*
- In Linux 2.1.x the chown functions have been changed. A new function lchown
- was introduced. The new chown now follows symlinks - the old chown and the
- new lchown do not follow symlinks.
- The new lchown function has the same number as the old chown had and the
- new chown has a new number. When compiling with headers from Linux > 2.1.8x
- it's impossible to run this libc with older kernels. In these cases libc
- has therefore to route calls to chown to the old chown function.
-*/
-
-extern int __chown_is_lchown (const char *__file, uid_t __owner,
- gid_t __group);
-extern int __real_chown (const char *__file, uid_t __owner, gid_t __group);
-
-
-#if defined __NR_lchown || __ASSUME_LCHOWN_SYSCALL > 0
-/* Running under Linux > 2.1.80. */
-
-# ifdef __NR_chown32
-# if __ASSUME_32BITUIDS == 0
-/* This variable is shared with all files that need to check for 32bit
- uids. */
-extern int __libc_missing_32bit_uids;
-# endif
-# endif /* __NR_chown32 */
-#endif
-
int
fchownat (int fd, const char *file, uid_t owner, gid_t group, int flag)
@@ -105,92 +78,33 @@ fchownat (int fd, const char *file, uid_
file = buf;
}
+# if __ASSUME_32BITUIDS > 0
+ /* This implies __ASSUME_LCHOWN_SYSCALL. */
INTERNAL_SYSCALL_DECL (err);
-# if defined __NR_lchown || __ASSUME_LCHOWN_SYSCALL > 0
-# if __ASSUME_LCHOWN_SYSCALL == 0
- static int __libc_old_chown;
-
-# ifdef __NR_chown32
- if (__libc_missing_32bit_uids <= 0)
- {
- if (flag & AT_SYMLINK_NOFOLLOW)
- result = INTERNAL_SYSCALL (lchown32, err, 3, CHECK_STRING (file),
- owner, group);
- else
- result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file),
- owner, group);
-
- if (!INTERNAL_SYSCALL_ERROR_P (result, err))
- return result;
- if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
- goto fail;
-
- __libc_missing_32bit_uids = 1;
- }
-# endif /* __NR_chown32 */
-
- if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
- || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
- {
- __set_errno (EINVAL);
- return -1;
- }
+ if (flag & AT_SYMLINK_NOFOLLOW)
+ result = INTERNAL_SYSCALL (lchown32, err, 3, CHECK_STRING (file), owner,
+ group);
+ else
+ result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
+ group);
- if (!__libc_old_chown && (flag & AT_SYMLINK_NOFOLLOW) == 0)
- {
- result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner,
- group);
-
- if (!INTERNAL_SYSCALL_ERROR_P (result, err))
- return result;
- if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
- goto fail;
-
- __libc_old_chown = 1;
- }
-
- result = INTERNAL_SYSCALL (lchown, err, 3, CHECK_STRING (file), owner,
- group);
-# elif __ASSUME_32BITUIDS
- /* This implies __ASSUME_LCHOWN_SYSCALL. */
- result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
- group);
-# else
- /* !__ASSUME_32BITUIDS && ASSUME_LCHOWN_SYSCALL */
-# ifdef __NR_chown32
- if (__libc_missing_32bit_uids <= 0)
- {
- result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
- group);
- if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
- return result;
- if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
- goto fail;
-
- __libc_missing_32bit_uids = 1;
- }
-# endif /* __NR_chown32 */
- if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
- || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
+ if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
{
- __set_errno (EINVAL);
+ __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
return -1;
}
-
- result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner, group);
-# endif
# else
- result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner, group);
+ /* Don't inline the rest to avoid unnecessary code duplication. */
+ if (flag & AT_SYMLINK_NOFOLLOW)
+ result = __lchown (file, owner, group);
+ else
+ result = __chown (file, owner, group);
+ if (result < 0)
+ __atfct_seterrno (errno, fd, buf);
# endif
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
- goto fail;
-
return result;
- fail:
- __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
- return -1;
#endif
}
--- libc/sysdeps/unix/sysv/linux/sh/fchownat.c.jj 2006-08-08 17:41:55.000000000 +0200
+++ libc/sysdeps/unix/sysv/linux/sh/fchownat.c 2006-09-25 16:15:14.000000000 +0200
@@ -1,140 +1 @@
-/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-#include <bp-checks.h>
-
-#include <linux/posix_types.h>
-#include <kernel-features.h>
-
-#ifdef __NR_chown32
-# if __ASSUME_32BITUIDS == 0
-/* This variable is shared with all files that need to check for 32bit
- uids. */
-extern int __libc_missing_32bit_uids;
-# endif
-#endif /* __NR_chown32 */
-
-int
-fchownat (int fd, const char *file, uid_t owner, gid_t group, int flag)
-{
- int result;
-
-#ifdef __NR_fchownat
-# ifndef __ASSUME_ATFCTS
- if (__have_atfcts >= 0)
-# endif
- {
- result = INLINE_SYSCALL (fchownat, 5, fd, file, owner, group, flag);
-# ifndef __ASSUME_ATFCTS
- if (result == -1 && errno == ENOSYS)
- __have_atfcts = -1;
- else
-# endif
- return result;
- }
-#endif
-
-#ifndef __ASSUME_ATFCTS
- if (flag & ~AT_SYMLINK_NOFOLLOW)
- {
- __set_errno (EINVAL);
- return -1;
- }
-
- char *buf = NULL;
-
- if (fd != AT_FDCWD && file[0] != '/')
- {
- size_t filelen = strlen (file);
- static const char procfd[] = "/proc/self/fd/%d/%s";
- /* Buffer for the path name we are going to use. It consists of
- - the string /proc/self/fd/
- - the file descriptor number
- - the file name provided.
- The final NUL is included in the sizeof. A bit of overhead
- due to the format elements compensates for possible negative
- numbers. */
- size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
- buf = alloca (buflen);
-
- __snprintf (buf, buflen, procfd, fd, file);
- file = buf;
- }
-
- INTERNAL_SYSCALL_DECL (err);
-
-# if __ASSUME_32BITUIDS > 0
- if (flag & AT_SYMLINK_NOFOLLOW)
- result = INTERNAL_SYSCALL (lchown32, err, 3, CHECK_STRING (file), owner,
- group);
- else
- result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
- group);
-# else
-# ifdef __NR_chown32
- if (__libc_missing_32bit_uids <= 0)
- {
- if (flag & AT_SYMLINK_NOFOLLOW)
- result = INTERNAL_SYSCALL (lchown32, err, 3, CHECK_STRING (file),
- owner, group);
- else
- result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
- group);
-
- if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
- return result;
- if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
- goto fail;
-
- __libc_missing_32bit_uids = 1;
- }
-# endif /* __NR_chown32 */
-
- if (((owner + 1) > (gid_t) ((__kernel_uid_t) -1U))
- || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
- {
- __set_errno (EINVAL);
- return -1;
- }
-
- if (flag & AT_SYMLINK_NOFOLLOW)
- result = INTERNAL_SYSCALL (lchown, err, 3, CHECK_STRING (file), owner,
- group);
- else
- result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner,
- group);
-# endif
-
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
- {
- fail:
- __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
- result = -1;
- }
-
- return result;
-#endif
-}
+#include <sysdeps/unix/sysv/linux/i386/fchownat.c>
--- libc/sysdeps/unix/sysv/linux/s390/s390-32/fchownat.c.jj 2006-08-08 17:41:55.000000000 +0200
+++ libc/sysdeps/unix/sysv/linux/s390/s390-32/fchownat.c 2006-09-25 16:18:46.000000000 +0200
@@ -1,159 +1 @@
-/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-#include <shlib-compat.h>
-#include <bp-checks.h>
-
-#include <linux/posix_types.h>
-#include <kernel-features.h>
-
-/*
- In Linux 2.1.x the chown functions have been changed. A new function lchown
- was introduced. The new chown now follows symlinks - the old chown and the
- new lchown do not follow symlinks.
- The new lchown function has the same number as the old chown had and the
- new chown has a new number. When compiling with headers from Linux > 2.1.8x
- it's impossible to run this libc with older kernels. In these cases libc
- has therefore to route calls to chown to the old chown function.
-*/
-
-/* Running under Linux > 2.1.80. */
-
-#ifdef __NR_chown32
-# if __ASSUME_32BITUIDS == 0
-/* This variable is shared with all files that need to check for 32bit
- uids. */
-extern int __libc_missing_32bit_uids;
-# endif
-#endif /* __NR_chown32 */
-
-int
-fchownat (int fd, const char *file, uid_t owner, gid_t group, int flag)
-{
- int result;
-
-#ifdef __NR_fchownat
-# ifndef __ASSUME_ATFCTS
- if (__have_atfcts >= 0)
-# endif
- {
- result = INLINE_SYSCALL (fchownat, 5, fd, file, owner, group, flag);
-# ifndef __ASSUME_ATFCTS
- if (result == -1 && errno == ENOSYS)
- __have_atfcts = -1;
- else
-# endif
- return result;
- }
-#endif
-
-#ifndef __ASSUME_ATFCTS
- if (flag & ~AT_SYMLINK_NOFOLLOW)
- {
- __set_errno (EINVAL);
- return -1;
- }
-
- char *buf = NULL;
-
- if (fd != AT_FDCWD && file[0] != '/')
- {
- size_t filelen = strlen (file);
- static const char procfd[] = "/proc/self/fd/%d/%s";
- /* Buffer for the path name we are going to use. It consists of
- - the string /proc/self/fd/
- - the file descriptor number
- - the file name provided.
- The final NUL is included in the sizeof. A bit of overhead
- due to the format elements compensates for possible negative
- numbers. */
- size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
- buf = alloca (buflen);
-
- __snprintf (buf, buflen, procfd, fd, file);
- file = buf;
- }
-
- INTERNAL_SYSCALL_DECL (err);
-
-# if __ASSUME_32BITUIDS > 0
- result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file), owner,
- group);
-# else
- static int __libc_old_chown;
-
-# ifdef __NR_chown32
- if (__libc_missing_32bit_uids <= 0)
- {
- if (flag & AT_SYMLINK_NOFOLLOW)
- result = INTERNAL_SYSCALL (lchown32, err, 3, CHECK_STRING (file),
- owner, group);
- else
- result = INTERNAL_SYSCALL (chown32, err, 3, CHECK_STRING (file),
- owner, group);
-
- if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1))
- return result;
- if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
- goto fail;
-
- __libc_missing_32bit_uids = 1;
- }
-# endif /* __NR_chown32 */
- if (((owner + 1) > (uid_t) ((__kernel_uid_t) -1U))
- || ((group + 1) > (gid_t) ((__kernel_gid_t) -1U)))
- {
- __set_errno (EINVAL);
- return -1;
- }
-
- if (!__libc_old_chown && (flag & AT_SYMLINK_NOFOLLOW) == 0)
- {
- result = INTERNAL_SYSCALL (chown, err, 3, CHECK_STRING (file), owner,
- group);
-
- if (!INTERNAL_SYSCALL_ERROR_P (result, err))
- return result;
- if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS)
- goto fail;
-
- __libc_old_chown = 1;
- }
-
- result = INTERNAL_SYSCALL (lchown, err, 3, CHECK_STRING (file), owner,
- group);
-# endif
-
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
- {
- fail:
- __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf);
- result = -1;
- }
-
- return result;
-#endif
-}
+#include <sysdeps/unix/sysv/linux/i386/fchownat.c>
Jakub
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2006-09-25 15:08 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-09-25 15:08 [PATCH] Fix fchownat (BZ#3252) Jakub Jelinek
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).