From: Paul Eggert <eggert@cs.ucla.edu>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 12632@debbugs.gnu.org
Subject: bug#12632: file permissions checking mishandled when setuid
Date: Sat, 13 Oct 2012 23:16:44 -0700 [thread overview]
Message-ID: <507A58CC.10209@cs.ucla.edu> (raw)
In-Reply-To: <83a9vq7oqh.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 971 bytes --]
On 10/13/2012 12:23 AM, Eli Zaretskii wrote:
> The FIXMEs are OK, but I see no reason for them to come _instead_ of
> comments which explain why 'access' is used instead of 'stat'.
OK, I left those comments alone in the attached revision
of the patch.
> How will the new code work if 'dir' is nil?
'dir' can't be nil there. But this is a separate issue, so I've
omitted that change from the revised patch.
> Also, what about lread.c:openp, around line 1555: doesn't it want
> 'euidaccess' as well, rather than 'stat'?
Sure, we can do that. Done in the revised patch.
> I don't understand why is it a good idea to use 'euidaccess' in
> check_existing. Isn't the fact of the mere existence of a file
> independent of user's access rights?
No, because you cannot even stat a file that's in a directory that you
can't search. Using 'access' rather than 'euidaccess' might
let a setuid Emacs search directories that it shouldn't be able
to search, or vice versa.
[-- Attachment #2: euidaccess.txt --]
[-- Type: text/plain, Size: 47247 bytes --]
=== modified file 'ChangeLog'
--- ChangeLog 2012-10-11 11:29:47 +0000
+++ ChangeLog 2012-10-14 06:03:50 +0000
@@ -1,3 +1,12 @@
+2012-10-14 Paul Eggert <eggert@cs.ucla.edu>
+
+ Use euidaccess, not access, when checking file permissions (Bug#12632).
+ * configure.ac (euidaccess): Remove check; gnulib does this for us now.
+ * lib/euidaccess.c, lib/getgroups.c, lib/group-member.c:
+ * lib/root-uid.h, lib/xalloc-oversized.h, m4/euidaccess.m4:
+ * m4/getgroups.m4, m4/group-member.m4: New files, from gnulib.
+ * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
2012-10-11 Kenichi Handa <handa@gnu.org>
* .bzrignore: Add several files under admin/charsets.
=== modified file 'admin/ChangeLog'
--- admin/ChangeLog 2012-10-11 11:29:47 +0000
+++ admin/ChangeLog 2012-10-14 06:03:50 +0000
@@ -1,3 +1,9 @@
+2012-10-14 Paul Eggert <eggert@cs.ucla.edu>
+
+ Use euidaccess, not access, when checking file permissions (Bug#12632).
+ * merge-gnulib (GNULIB_MODULES): Add euidaccess.
+ (GNULIB_TOOL_FLAGS): Avoid malloc-posix.
+
2012-10-11 Kenichi Handa <handa@gnu.org>
* charsets/mapconv: Adjusted for the change of mapfiles/*.gz to
=== modified file 'admin/merge-gnulib'
--- admin/merge-gnulib 2012-09-27 01:06:23 +0000
+++ admin/merge-gnulib 2012-10-12 23:28:31 +0000
@@ -28,7 +28,7 @@
GNULIB_MODULES='
alloca-opt c-ctype c-strcase
careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
- dtoastr dtotimespec dup2 environ execinfo
+ dtoastr dtotimespec dup2 environ euidaccess execinfo
filemode getloadavg getopt-gnu gettime gettimeofday
ignore-value intprops largefile lstat
manywarnings mktime pselect pthread_sigmask readlink
@@ -40,7 +40,7 @@
GNULIB_TOOL_FLAGS='
--avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat
- --avoid=msvc-inval --avoid=msvc-nothrow
+ --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow
--avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types
--avoid=threadlib
--conditional-dependencies --import --no-changelog --no-vc-files
=== modified file 'configure.ac'
--- configure.ac 2012-10-08 16:09:00 +0000
+++ configure.ac 2012-10-12 23:28:31 +0000
@@ -2872,7 +2872,7 @@
AC_CHECK_FUNCS(gethostname \
closedir getrusage get_current_dir_name \
lrand48 setsid \
-fpathconf select euidaccess getpagesize setlocale \
+fpathconf select getpagesize setlocale \
utimes getrlimit setrlimit setpgid getcwd shutdown getaddrinfo \
__fpending strsignal setitimer \
sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
=== added file 'lib/euidaccess.c'
--- lib/euidaccess.c 1970-01-01 00:00:00 +0000
+++ lib/euidaccess.c 2012-10-12 23:28:31 +0000
@@ -0,0 +1,221 @@
+/* euidaccess -- check if effective user id can access file
+
+ Copyright (C) 1990-1991, 1995, 1998, 2000, 2003-2006, 2008-2012 Free
+ Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by David MacKenzie and Torbjorn Granlund.
+ Adapted for GNU C library by Roland McGrath. */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "root-uid.h"
+
+#if HAVE_LIBGEN_H
+# include <libgen.h>
+#endif
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#if defined EACCES && !defined EACCESS
+# define EACCESS EACCES
+#endif
+
+#ifndef F_OK
+# define F_OK 0
+# define X_OK 1
+# define W_OK 2
+# define R_OK 4
+#endif
+
+
+#ifdef _LIBC
+
+# define access __access
+# define getuid __getuid
+# define getgid __getgid
+# define geteuid __geteuid
+# define getegid __getegid
+# define group_member __group_member
+# define euidaccess __euidaccess
+# undef stat
+# define stat stat64
+
+#endif
+
+/* Return 0 if the user has permission of type MODE on FILE;
+ otherwise, return -1 and set 'errno'.
+ Like access, except that it uses the effective user and group
+ id's instead of the real ones, and it does not always check for read-only
+ file system, text busy, etc. */
+
+int
+euidaccess (const char *file, int mode)
+{
+#if HAVE_FACCESSAT /* glibc, AIX 7, Solaris 11, Cygwin 1.7 */
+ return faccessat (AT_FDCWD, file, mode, AT_EACCESS);
+#elif defined EFF_ONLY_OK /* IRIX, OSF/1, Interix */
+ return access (file, mode | EFF_ONLY_OK);
+#elif defined ACC_SELF /* AIX */
+ return accessx (file, mode, ACC_SELF);
+#elif HAVE_EACCESS /* FreeBSD */
+ return eaccess (file, mode);
+#else /* Mac OS X, NetBSD, OpenBSD, HP-UX, Solaris, Cygwin, mingw, BeOS */
+
+ uid_t uid = getuid ();
+ gid_t gid = getgid ();
+ uid_t euid = geteuid ();
+ gid_t egid = getegid ();
+ struct stat stats;
+
+# if HAVE_DECL_SETREGID && PREFER_NONREENTRANT_EUIDACCESS
+
+ /* Define PREFER_NONREENTRANT_EUIDACCESS if you prefer euidaccess to
+ return the correct result even if this would make it
+ nonreentrant. Define this only if your entire application is
+ safe even if the uid or gid might temporarily change. If your
+ application uses signal handlers or threads it is probably not
+ safe. */
+
+ if (mode == F_OK)
+ return stat (file, &stats);
+ else
+ {
+ int result;
+ int saved_errno;
+
+ if (uid != euid)
+ setreuid (euid, uid);
+ if (gid != egid)
+ setregid (egid, gid);
+
+ result = access (file, mode);
+ saved_errno = errno;
+
+ /* Restore them. */
+ if (uid != euid)
+ setreuid (uid, euid);
+ if (gid != egid)
+ setregid (gid, egid);
+
+ errno = saved_errno;
+ return result;
+ }
+
+# else
+
+ /* The following code assumes the traditional Unix model, and is not
+ correct on systems that have ACLs or the like. However, it's
+ better than nothing, and it is reentrant. */
+
+ unsigned int granted;
+ if (uid == euid && gid == egid)
+ /* If we are not set-uid or set-gid, access does the same. */
+ return access (file, mode);
+
+ if (stat (file, &stats) != 0)
+ return -1;
+
+ /* The super-user can read and write any file, and execute any file
+ that anyone can execute. */
+ if (euid == ROOT_UID
+ && ((mode & X_OK) == 0
+ || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
+ return 0;
+
+ /* Convert the mode to traditional form, clearing any bogus bits. */
+ if (R_OK == 4 && W_OK == 2 && X_OK == 1 && F_OK == 0)
+ mode &= 7;
+ else
+ mode = ((mode & R_OK ? 4 : 0)
+ + (mode & W_OK ? 2 : 0)
+ + (mode & X_OK ? 1 : 0));
+
+ if (mode == 0)
+ return 0; /* The file exists. */
+
+ /* Convert the file's permission bits to traditional form. */
+ if (S_IRUSR == (4 << 6) && S_IWUSR == (2 << 6) && S_IXUSR == (1 << 6)
+ && S_IRGRP == (4 << 3) && S_IWGRP == (2 << 3) && S_IXGRP == (1 << 3)
+ && S_IROTH == (4 << 0) && S_IWOTH == (2 << 0) && S_IXOTH == (1 << 0))
+ granted = stats.st_mode;
+ else
+ granted = ((stats.st_mode & S_IRUSR ? 4 << 6 : 0)
+ + (stats.st_mode & S_IWUSR ? 2 << 6 : 0)
+ + (stats.st_mode & S_IXUSR ? 1 << 6 : 0)
+ + (stats.st_mode & S_IRGRP ? 4 << 3 : 0)
+ + (stats.st_mode & S_IWGRP ? 2 << 3 : 0)
+ + (stats.st_mode & S_IXGRP ? 1 << 3 : 0)
+ + (stats.st_mode & S_IROTH ? 4 << 0 : 0)
+ + (stats.st_mode & S_IWOTH ? 2 << 0 : 0)
+ + (stats.st_mode & S_IXOTH ? 1 << 0 : 0));
+
+ if (euid == stats.st_uid)
+ granted >>= 6;
+ else if (egid == stats.st_gid || group_member (stats.st_gid))
+ granted >>= 3;
+
+ if ((mode & ~granted) == 0)
+ return 0;
+ __set_errno (EACCESS);
+ return -1;
+
+# endif
+#endif
+}
+#undef euidaccess
+#ifdef weak_alias
+weak_alias (__euidaccess, euidaccess)
+#endif
+\f
+#ifdef TEST
+# include <error.h>
+# include <stdio.h>
+# include <stdlib.h>
+
+char *program_name;
+
+int
+main (int argc, char **argv)
+{
+ char *file;
+ int mode;
+ int err;
+
+ program_name = argv[0];
+ if (argc < 3)
+ abort ();
+ file = argv[1];
+ mode = atoi (argv[2]);
+
+ err = euidaccess (file, mode);
+ printf ("%d\n", err);
+ if (err != 0)
+ error (0, errno, "%s", file);
+ exit (0);
+}
+#endif
=== added file 'lib/getgroups.c'
--- lib/getgroups.c 1970-01-01 00:00:00 +0000
+++ lib/getgroups.c 2012-10-12 23:28:31 +0000
@@ -0,0 +1,116 @@
+/* provide consistent interface to getgroups for systems that don't allow N==0
+
+ Copyright (C) 1996, 1999, 2003, 2006-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* written by Jim Meyering */
+
+#include <config.h>
+
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#if !HAVE_GETGROUPS
+
+/* Provide a stub that fails with ENOSYS, since there is no group
+ information available on mingw. */
+int
+getgroups (int n _GL_UNUSED, GETGROUPS_T *groups _GL_UNUSED)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+#else /* HAVE_GETGROUPS */
+
+# undef getgroups
+# ifndef GETGROUPS_ZERO_BUG
+# define GETGROUPS_ZERO_BUG 0
+# endif
+
+/* On at least Ultrix 4.3 and NextStep 3.2, getgroups (0, NULL) always
+ fails. On other systems, it returns the number of supplemental
+ groups for the process. This function handles that special case
+ and lets the system-provided function handle all others. However,
+ it can fail with ENOMEM if memory is tight. It is unspecified
+ whether the effective group id is included in the list. */
+
+int
+rpl_getgroups (int n, gid_t *group)
+{
+ int n_groups;
+ GETGROUPS_T *gbuf;
+ int saved_errno;
+
+ if (n < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (n != 0 || !GETGROUPS_ZERO_BUG)
+ {
+ int result;
+ if (sizeof *group == sizeof *gbuf)
+ return getgroups (n, (GETGROUPS_T *) group);
+
+ if (SIZE_MAX / sizeof *gbuf <= n)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ gbuf = malloc (n * sizeof *gbuf);
+ if (!gbuf)
+ return -1;
+ result = getgroups (n, gbuf);
+ if (0 <= result)
+ {
+ n = result;
+ while (n--)
+ group[n] = gbuf[n];
+ }
+ saved_errno = errno;
+ free (gbuf);
+ errno == saved_errno;
+ return result;
+ }
+
+ n = 20;
+ while (1)
+ {
+ /* No need to worry about address arithmetic overflow here,
+ since the ancient systems that we're running on have low
+ limits on the number of secondary groups. */
+ gbuf = malloc (n * sizeof *gbuf);
+ if (!gbuf)
+ return -1;
+ n_groups = getgroups (n, gbuf);
+ if (n_groups == -1 ? errno != EINVAL : n_groups < n)
+ break;
+ free (gbuf);
+ n *= 2;
+ }
+
+ saved_errno = errno;
+ free (gbuf);
+ errno = saved_errno;
+
+ return n_groups;
+}
+
+#endif /* HAVE_GETGROUPS */
=== modified file 'lib/gnulib.mk'
--- lib/gnulib.mk 2012-10-04 07:15:42 +0000
+++ lib/gnulib.mk 2012-10-12 23:28:31 +0000
@@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ euidaccess execinfo filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings
MOSTLYCLEANFILES += core *.stackdump
@@ -150,6 +150,15 @@
## end gnulib module dup2
+## begin gnulib module euidaccess
+
+
+EXTRA_DIST += euidaccess.c
+
+EXTRA_libgnu_a_SOURCES += euidaccess.c
+
+## end gnulib module euidaccess
+
## begin gnulib module execinfo
BUILT_SOURCES += $(EXECINFO_H)
@@ -183,6 +192,17 @@
## end gnulib module filemode
+## begin gnulib module getgroups
+
+if gl_GNULIB_ENABLED_getgroups
+
+endif
+EXTRA_DIST += getgroups.c
+
+EXTRA_libgnu_a_SOURCES += getgroups.c
+
+## end gnulib module getgroups
+
## begin gnulib module getloadavg
@@ -242,6 +262,17 @@
## end gnulib module gettimeofday
+## begin gnulib module group-member
+
+if gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1
+
+endif
+EXTRA_DIST += group-member.c
+
+EXTRA_libgnu_a_SOURCES += group-member.c
+
+## end gnulib module group-member
+
## begin gnulib module ignore-value
@@ -354,6 +385,13 @@
## end gnulib module readlink
+## begin gnulib module root-uid
+
+
+EXTRA_DIST += root-uid.h
+
+## end gnulib module root-uid
+
## begin gnulib module signal-h
BUILT_SOURCES += signal.h
@@ -1312,6 +1350,15 @@
## end gnulib module verify
+## begin gnulib module xalloc-oversized
+
+if gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec
+
+endif
+EXTRA_DIST += xalloc-oversized.h
+
+## end gnulib module xalloc-oversized
+
mostlyclean-local: mostlyclean-generic
@for dir in '' $(MOSTLYCLEANDIRS); do \
=== added file 'lib/group-member.c'
--- lib/group-member.c 1970-01-01 00:00:00 +0000
+++ lib/group-member.c 2012-10-12 23:28:31 +0000
@@ -0,0 +1,119 @@
+/* group-member.c -- determine whether group id is in calling user's group list
+
+ Copyright (C) 1994, 1997-1998, 2003, 2005-2006, 2009-2012 Free Software
+ Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <unistd.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "xalloc-oversized.h"
+
+/* Most processes have no more than this many groups, and for these
+ processes we can avoid using malloc. */
+enum { GROUPBUF_SIZE = 100 };
+
+struct group_info
+ {
+ gid_t *group;
+ gid_t groupbuf[GROUPBUF_SIZE];
+ };
+
+static void
+free_group_info (struct group_info const *g)
+{
+ if (g->group != g->groupbuf)
+ free (g->group);
+}
+
+static int
+get_group_info (struct group_info *gi)
+{
+ int n_groups = getgroups (GROUPBUF_SIZE, gi->groupbuf);
+ gi->group = gi->groupbuf;
+
+ if (n_groups < 0)
+ {
+ int n_group_slots = getgroups (0, NULL);
+ if (0 <= n_group_slots
+ && ! xalloc_oversized (n_group_slots, sizeof *gi->group))
+ {
+ gi->group = malloc (n_group_slots * sizeof *gi->group);
+ if (gi->group)
+ n_groups = getgroups (n_group_slots, gi->group);
+ }
+ }
+
+ /* In case of error, the user loses. */
+ return n_groups;
+}
+
+/* Return non-zero if GID is one that we have in our groups list.
+ Note that the groups list is not guaranteed to contain the current
+ or effective group ID, so they should generally be checked
+ separately. */
+
+int
+group_member (gid_t gid)
+{
+ int i;
+ int found;
+ struct group_info gi;
+ int n_groups = get_group_info (&gi);
+
+ /* Search through the list looking for GID. */
+ found = 0;
+ for (i = 0; i < n_groups; i++)
+ {
+ if (gid == gi.group[i])
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ free_group_info (&gi);
+
+ return found;
+}
+
+#ifdef TEST
+
+char *program_name;
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ program_name = argv[0];
+
+ for (i = 1; i < argc; i++)
+ {
+ gid_t gid;
+
+ gid = atoi (argv[i]);
+ printf ("%d: %s\n", gid, group_member (gid) ? "yes" : "no");
+ }
+ exit (0);
+}
+
+#endif /* TEST */
=== added file 'lib/root-uid.h'
--- lib/root-uid.h 1970-01-01 00:00:00 +0000
+++ lib/root-uid.h 2012-10-12 23:28:31 +0000
@@ -0,0 +1,30 @@
+/* The user ID that always has appropriate privileges in the POSIX sense.
+
+ Copyright 2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Written by Paul Eggert. */
+
+#ifndef ROOT_UID_H_
+#define ROOT_UID_H_
+
+/* The user ID that always has appropriate privileges in the POSIX sense. */
+#ifdef __TANDEM
+# define ROOT_UID 65535
+#else
+# define ROOT_UID 0
+#endif
+
+#endif
=== added file 'lib/xalloc-oversized.h'
--- lib/xalloc-oversized.h 1970-01-01 00:00:00 +0000
+++ lib/xalloc-oversized.h 2012-10-12 23:28:31 +0000
@@ -0,0 +1,38 @@
+/* xalloc-oversized.h -- memory allocation size checking
+
+ Copyright (C) 1990-2000, 2003-2004, 2006-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef XALLOC_OVERSIZED_H_
+# define XALLOC_OVERSIZED_H_
+
+# include <stddef.h>
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+ to size arithmetic overflow. S must be positive and N must be
+ nonnegative. This is a macro, not a function, so that it
+ works correctly even when SIZE_MAX < N.
+
+ By gnulib convention, SIZE_MAX represents overflow in size
+ calculations, so the conservative dividend to use here is
+ SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+ However, malloc (SIZE_MAX) fails on all known hosts where
+ sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+ exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+ branch when S is known to be 1. */
+# define xalloc_oversized(n, s) \
+ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+
+#endif /* !XALLOC_OVERSIZED_H_ */
=== added file 'm4/euidaccess.m4'
--- m4/euidaccess.m4 1970-01-01 00:00:00 +0000
+++ m4/euidaccess.m4 2012-10-12 23:28:31 +0000
@@ -0,0 +1,52 @@
+# euidaccess.m4 serial 14
+dnl Copyright (C) 2002-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_NONREENTRANT_EUIDACCESS],
+[
+ AC_REQUIRE([gl_FUNC_EUIDACCESS])
+ AC_DEFINE([PREFER_NONREENTRANT_EUIDACCESS], [1],
+ [Define this if you prefer euidaccess to return the correct result
+ even if this would make it nonreentrant. Define this only if your
+ entire application is safe even if the uid or gid might temporarily
+ change. If your application uses signal handlers or threads it
+ is probably not safe.])
+])
+
+AC_DEFUN([gl_FUNC_EUIDACCESS],
+[
+ AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+
+ dnl Persuade glibc <unistd.h> to declare euidaccess().
+ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+ AC_CHECK_FUNCS([euidaccess])
+ if test $ac_cv_func_euidaccess = no; then
+ HAVE_EUIDACCESS=0
+ fi
+])
+
+# Prerequisites of lib/euidaccess.c.
+AC_DEFUN([gl_PREREQ_EUIDACCESS], [
+ dnl Prefer POSIX faccessat over non-standard euidaccess.
+ AC_CHECK_FUNCS_ONCE([faccessat])
+ dnl Try various other non-standard fallbacks.
+ AC_CHECK_HEADERS_ONCE([libgen.h])
+ AC_CHECK_DECLS_ONCE([setregid])
+ AC_REQUIRE([AC_FUNC_GETGROUPS])
+
+ # Solaris 9 and 10 need -lgen to get the eaccess function.
+ # Save and restore LIBS so -lgen isn't added to it. Otherwise, *all*
+ # programs in the package would end up linked with that potentially-shared
+ # library, inducing unnecessary run-time overhead.
+ LIB_EACCESS=
+ AC_SUBST([LIB_EACCESS])
+ gl_saved_libs=$LIBS
+ AC_SEARCH_LIBS([eaccess], [gen],
+ [test "$ac_cv_search_eaccess" = "none required" ||
+ LIB_EACCESS=$ac_cv_search_eaccess])
+ AC_CHECK_FUNCS([eaccess])
+ LIBS=$gl_saved_libs
+])
=== added file 'm4/getgroups.m4'
--- m4/getgroups.m4 1970-01-01 00:00:00 +0000
+++ m4/getgroups.m4 2012-10-12 23:28:31 +0000
@@ -0,0 +1,107 @@
+# serial 18
+
+dnl From Jim Meyering.
+dnl A wrapper around AC_FUNC_GETGROUPS.
+
+# Copyright (C) 1996-1997, 1999-2004, 2008-2012 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+m4_version_prereq([2.70], [] ,[
+
+# This is taken from the following Autoconf patch:
+# http://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=7fbb553727ed7e0e689a17594b58559ecf3ea6e9
+AC_DEFUN([AC_FUNC_GETGROUPS],
+[
+ AC_REQUIRE([AC_TYPE_GETGROUPS])dnl
+ AC_REQUIRE([AC_TYPE_SIZE_T])dnl
+ AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
+ AC_CHECK_FUNC([getgroups])
+
+ # If we don't yet have getgroups, see if it's in -lbsd.
+ # This is reported to be necessary on an ITOS 3000WS running SEIUX 3.1.
+ ac_save_LIBS=$LIBS
+ if test $ac_cv_func_getgroups = no; then
+ AC_CHECK_LIB(bsd, getgroups, [GETGROUPS_LIB=-lbsd])
+ fi
+
+ # Run the program to test the functionality of the system-supplied
+ # getgroups function only if there is such a function.
+ if test $ac_cv_func_getgroups = yes; then
+ AC_CACHE_CHECK([for working getgroups], [ac_cv_func_getgroups_works],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [AC_INCLUDES_DEFAULT],
+ [[/* On Ultrix 4.3, getgroups (0, 0) always fails. */
+ return getgroups (0, 0) == -1;]])
+ ],
+ [ac_cv_func_getgroups_works=yes],
+ [ac_cv_func_getgroups_works=no],
+ [case "$host_os" in # ((
+ # Guess yes on glibc systems.
+ *-gnu*) ac_cv_func_getgroups_works="guessing yes" ;;
+ # If we don't know, assume the worst.
+ *) ac_cv_func_getgroups_works="guessing no" ;;
+ esac
+ ])
+ ])
+ else
+ ac_cv_func_getgroups_works=no
+ fi
+ case "$ac_cv_func_getgroups_works" in
+ *yes)
+ AC_DEFINE([HAVE_GETGROUPS], [1],
+ [Define to 1 if your system has a working `getgroups' function.])
+ ;;
+ esac
+ LIBS=$ac_save_LIBS
+])# AC_FUNC_GETGROUPS
+
+])
+
+AC_DEFUN([gl_FUNC_GETGROUPS],
+[
+ AC_REQUIRE([AC_TYPE_GETGROUPS])
+ AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+ AC_FUNC_GETGROUPS
+ if test $ac_cv_func_getgroups != yes; then
+ HAVE_GETGROUPS=0
+ else
+ if test "$ac_cv_type_getgroups" != gid_t \
+ || { case "$ac_cv_func_getgroups_works" in
+ *yes) false;;
+ *) true;;
+ esac
+ }; then
+ REPLACE_GETGROUPS=1
+ AC_DEFINE([GETGROUPS_ZERO_BUG], [1], [Define this to 1 if
+ getgroups(0,NULL) does not return the number of groups.])
+ else
+ dnl Detect FreeBSD bug; POSIX requires getgroups(-1,ptr) to fail.
+ AC_CACHE_CHECK([whether getgroups handles negative values],
+ [gl_cv_func_getgroups_works],
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+ [[int size = getgroups (0, 0);
+ gid_t *list = malloc (size * sizeof *list);
+ return getgroups (-1, list) != -1;]])],
+ [gl_cv_func_getgroups_works=yes],
+ [gl_cv_func_getgroups_works=no],
+ [case "$host_os" in
+ # Guess yes on glibc systems.
+ *-gnu*) gl_cv_func_getgroups_works="guessing yes" ;;
+ # If we don't know, assume the worst.
+ *) gl_cv_func_getgroups_works="guessing no" ;;
+ esac
+ ])])
+ case "$gl_cv_func_getgroups_works" in
+ *yes) ;;
+ *) REPLACE_GETGROUPS=1 ;;
+ esac
+ fi
+ fi
+ test -n "$GETGROUPS_LIB" && LIBS="$GETGROUPS_LIB $LIBS"
+])
=== modified file 'm4/gnulib-comp.m4'
--- m4/gnulib-comp.m4 2012-09-27 01:06:23 +0000
+++ m4/gnulib-comp.m4 2012-10-12 23:28:31 +0000
@@ -53,17 +53,20 @@
# Code from module dtotimespec:
# Code from module dup2:
# Code from module environ:
+ # Code from module euidaccess:
# Code from module execinfo:
# Code from module extensions:
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
# Code from module extern-inline:
# Code from module filemode:
+ # Code from module getgroups:
# Code from module getloadavg:
# Code from module getopt-gnu:
# Code from module getopt-posix:
# Code from module gettext-h:
# Code from module gettime:
# Code from module gettimeofday:
+ # Code from module group-member:
# Code from module ignore-value:
# Code from module include_next:
# Code from module intprops:
@@ -79,6 +82,7 @@
# Code from module pselect:
# Code from module pthread_sigmask:
# Code from module readlink:
+ # Code from module root-uid:
# Code from module signal-h:
# Code from module snippet/_Noreturn:
# Code from module snippet/arg-nonnull:
@@ -120,6 +124,7 @@
# Code from module utimens:
# Code from module verify:
# Code from module warnings:
+ # Code from module xalloc-oversized:
])
# This macro should be invoked from ./configure.ac, in the section
@@ -154,6 +159,12 @@
gl_UNISTD_MODULE_INDICATOR([dup2])
gl_ENVIRON
gl_UNISTD_MODULE_INDICATOR([environ])
+ gl_FUNC_EUIDACCESS
+ if test $HAVE_EUIDACCESS = 0; then
+ AC_LIBOBJ([euidaccess])
+ gl_PREREQ_EUIDACCESS
+ fi
+ gl_UNISTD_MODULE_INDICATOR([euidaccess])
gl_EXECINFO_H
AC_REQUIRE([gl_EXTERN_INLINE])
gl_FILEMODE
@@ -269,18 +280,32 @@
gl_UNISTD_H
gl_UTIMENS
gl_gnulib_enabled_dosname=false
+ gl_gnulib_enabled_getgroups=false
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
+ gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
gl_gnulib_enabled_pathmax=false
gl_gnulib_enabled_stat=false
gl_gnulib_enabled_strtoll=false
gl_gnulib_enabled_strtoull=false
gl_gnulib_enabled_verify=false
+ gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
func_gl_gnulib_m4code_dosname ()
{
if ! $gl_gnulib_enabled_dosname; then
gl_gnulib_enabled_dosname=true
fi
}
+ func_gl_gnulib_m4code_getgroups ()
+ {
+ if ! $gl_gnulib_enabled_getgroups; then
+ gl_FUNC_GETGROUPS
+ if test $HAVE_GETGROUPS = 0 || test $REPLACE_GETGROUPS = 1; then
+ AC_LIBOBJ([getgroups])
+ fi
+ gl_UNISTD_MODULE_INDICATOR([getgroups])
+ gl_gnulib_enabled_getgroups=true
+ fi
+ }
func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36 ()
{
if ! $gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36; then
@@ -289,6 +314,24 @@
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=true
fi
}
+ func_gl_gnulib_m4code_a9786850e999ae65a836a6041e8e5ed1 ()
+ {
+ if ! $gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1; then
+ gl_FUNC_GROUP_MEMBER
+ if test $HAVE_GROUP_MEMBER = 0; then
+ AC_LIBOBJ([group-member])
+ gl_PREREQ_GROUP_MEMBER
+ fi
+ gl_UNISTD_MODULE_INDICATOR([group-member])
+ gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=true
+ if test $HAVE_GROUP_MEMBER = 0; then
+ func_gl_gnulib_m4code_getgroups
+ fi
+ if test $HAVE_GROUP_MEMBER = 0; then
+ func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec
+ fi
+ fi
+ }
func_gl_gnulib_m4code_pathmax ()
{
if ! $gl_gnulib_enabled_pathmax; then
@@ -347,6 +390,18 @@
gl_gnulib_enabled_verify=true
fi
}
+ func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
+ {
+ if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
+ gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=true
+ fi
+ }
+ if test $HAVE_EUIDACCESS = 0; then
+ func_gl_gnulib_m4code_a9786850e999ae65a836a6041e8e5ed1
+ fi
+ if test $HAVE_EUIDACCESS = 0; then
+ func_gl_gnulib_m4code_stat
+ fi
if test $REPLACE_GETOPT = 1; then
func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36
fi
@@ -373,12 +428,15 @@
fi
m4_pattern_allow([^gl_GNULIB_ENABLED_])
AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname])
+ AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
+ AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax])
AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull])
AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify])
+ AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
# End of code from modules
m4_ifval(gl_LIBSOURCES_LIST, [
m4_syscmd([test ! -d ]m4_defn([gl_LIBSOURCES_DIR])[ ||
@@ -538,12 +596,14 @@
lib/dtoastr.c
lib/dtotimespec.c
lib/dup2.c
+ lib/euidaccess.c
lib/execinfo.c
lib/execinfo.in.h
lib/filemode.c
lib/filemode.h
lib/ftoastr.c
lib/ftoastr.h
+ lib/getgroups.c
lib/getloadavg.c
lib/getopt.c
lib/getopt.in.h
@@ -552,6 +612,7 @@
lib/gettext.h
lib/gettime.c
lib/gettimeofday.c
+ lib/group-member.c
lib/ignore-value.h
lib/intprops.h
lib/inttypes.in.h
@@ -564,6 +625,7 @@
lib/pselect.c
lib/pthread_sigmask.c
lib/readlink.c
+ lib/root-uid.h
lib/sha1.c
lib/sha1.h
lib/sha256.c
@@ -605,21 +667,25 @@
lib/utimens.c
lib/utimens.h
lib/verify.h
+ lib/xalloc-oversized.h
m4/00gnulib.m4
m4/alloca.m4
m4/c-strtod.m4
m4/clock_time.m4
m4/dup2.m4
m4/environ.m4
+ m4/euidaccess.m4
m4/execinfo.m4
m4/extensions.m4
m4/extern-inline.m4
m4/filemode.m4
+ m4/getgroups.m4
m4/getloadavg.m4
m4/getopt.m4
m4/gettime.m4
m4/gettimeofday.m4
m4/gnulib-common.m4
+ m4/group-member.m4
m4/include_next.m4
m4/inttypes.m4
m4/largefile.m4
=== added file 'm4/group-member.m4'
--- m4/group-member.m4 1970-01-01 00:00:00 +0000
+++ m4/group-member.m4 2012-10-12 23:28:31 +0000
@@ -0,0 +1,29 @@
+# serial 14
+
+# Copyright (C) 1999-2001, 2003-2007, 2009-2012 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl Written by Jim Meyering
+
+AC_DEFUN([gl_FUNC_GROUP_MEMBER],
+[
+ AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+
+ dnl Persuade glibc <unistd.h> to declare group_member().
+ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+ dnl Do this replacement check manually because I want the hyphen
+ dnl (not the underscore) in the filename.
+ AC_CHECK_FUNC([group_member], , [
+ HAVE_GROUP_MEMBER=0
+ ])
+])
+
+# Prerequisites of lib/group-member.c.
+AC_DEFUN([gl_PREREQ_GROUP_MEMBER],
+[
+ AC_REQUIRE([AC_FUNC_GETGROUPS])
+])
=== modified file 'src/ChangeLog'
--- src/ChangeLog 2012-10-14 00:17:07 +0000
+++ src/ChangeLog 2012-10-14 06:02:52 +0000
@@ -1,3 +1,27 @@
+2012-10-14 Paul Eggert <eggert@cs.ucla.edu>
+
+ Use euidaccess, not access, when checking file permissions (Bug#12632).
+ * Makefile.in (LIB_EACCESS): New macro.
+ (LIBES): Use it.
+ * callproc.c (init_callproc):
+ * charset.c (init_charset):
+ * fileio.c (check_existing) [!DOS_NT]:
+ (check_executable) [!DOS_NT && !HAVE_EUIDACCESS]:
+ * lread.c (openp, load_path_check):
+ * process.c (allocate_pty):
+ * xrdb.c (file_p):
+ Use euidaccess, not access. Use symbolic names instead of integers
+ for the flags, as they're portable now.
+ * fileio.c (Ffile_readable_p) [!DOS_NT && !macintosh]:
+ Use euidaccess, not stat + open + close.
+ (file_directory_p): New function, which uses 'stat' on most places
+ but 'access' (for efficiency) if WINDOWSNT.
+ (Ffile_directory_p): Use it.
+ * lisp.h (file_directory_p): New decl.
+ * lread.c (openp): When opening a file, use fstat rather than
+ stat, as that avoids a permissions race. When not opening a file,
+ use file_directory_p rather than stat.
+
2012-10-13 Jan Djärv <jan.h.d@swipnet.se>
* gtkutil.c (xg_set_widget_bg): Divide by 65535 (Bug#12612).
=== modified file 'src/Makefile.in'
--- src/Makefile.in 2012-10-08 12:53:18 +0000
+++ src/Makefile.in 2012-10-13 01:49:41 +0000
@@ -150,6 +150,7 @@
M17N_FLT_LIBS = @M17N_FLT_LIBS@
LIB_CLOCK_GETTIME=@LIB_CLOCK_GETTIME@
+LIB_EACCESS=@LIB_EACCESS@
LIB_TIMER_TIME=@LIB_TIMER_TIME@
DBUS_CFLAGS = @DBUS_CFLAGS@
@@ -392,7 +393,7 @@
LIBES = $(LIBS) $(W32_LIBS) $(LIBX_BASE) $(LIBIMAGE) \
$(LIBX_OTHER) $(LIBSOUND) \
$(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \
- $(LIB_TIMER_TIME) $(DBUS_LIBS) \
+ $(LIB_EACCESS) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
$(LIB_EXECINFO) \
$(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
=== modified file 'src/callproc.c'
--- src/callproc.c 2012-09-23 22:25:22 +0000
+++ src/callproc.c 2012-10-12 23:28:31 +0000
@@ -1597,13 +1597,13 @@
#endif
{
tempdir = Fdirectory_file_name (Vexec_directory);
- if (access (SSDATA (tempdir), 0) < 0)
+ if (euidaccess (SSDATA (tempdir), F_OK) < 0)
dir_warning ("Warning: arch-dependent data dir (%s) does not exist.\n",
Vexec_directory);
}
tempdir = Fdirectory_file_name (Vdata_directory);
- if (access (SSDATA (tempdir), 0) < 0)
+ if (euidaccess (SSDATA (tempdir), F_OK) < 0)
dir_warning ("Warning: arch-independent data dir (%s) does not exist.\n",
Vdata_directory);
=== modified file 'src/charset.c'
--- src/charset.c 2012-10-01 06:36:54 +0000
+++ src/charset.c 2012-10-12 23:28:31 +0000
@@ -2293,7 +2293,7 @@
{
Lisp_Object tempdir;
tempdir = Fexpand_file_name (build_string ("charsets"), Vdata_directory);
- if (access (SSDATA (tempdir), 0) < 0)
+ if (euidaccess (SSDATA (tempdir), F_OK) != 0)
{
/* This used to be non-fatal (dir_warning), but it should not
happen, and if it does sooner or later it will cause some
=== modified file 'src/fileio.c'
--- src/fileio.c 2012-10-13 08:55:26 +0000
+++ src/fileio.c 2012-10-14 06:02:52 +0000
@@ -2428,10 +2428,11 @@
/* The full emulation of Posix 'stat' is too expensive on
DOS/Windows, when all we want to know is whether the file exists.
So we use 'access' instead, which is much more lightweight. */
+ /* FIXME: an euidaccess implementation should be added to the
+ DOS/Windows ports and this #ifdef branch should be removed. */
return (access (filename, F_OK) >= 0);
#else
- struct stat st;
- return (stat (filename, &st) >= 0);
+ return euidaccess (filename, F_OK) == 0;
#endif
}
@@ -2441,19 +2442,14 @@
check_executable (char *filename)
{
#ifdef DOS_NT
+ /* FIXME: an euidaccess implementation should be added to the
+ DOS/Windows ports and this #ifdef branch should be removed. */
struct stat st;
if (stat (filename, &st) < 0)
return 0;
return ((st.st_mode & S_IEXEC) != 0);
#else /* not DOS_NT */
-#ifdef HAVE_EUIDACCESS
- return (euidaccess (filename, 1) >= 0);
-#else
- /* Access isn't quite right because it uses the real uid
- and we really want to test with the effective uid.
- But Unix doesn't give us a right way to do it. */
- return (access (filename, 1) >= 0);
-#endif
+ return euidaccess (filename, X_OK) == 0;
#endif /* not DOS_NT */
}
@@ -2463,13 +2459,14 @@
check_writable (const char *filename)
{
#ifdef MSDOS
+ /* FIXME: an euidaccess implementation should be added to the
+ DOS/Windows ports and this #ifdef branch should be removed. */
struct stat st;
if (stat (filename, &st) < 0)
return 0;
return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode));
#else /* not MSDOS */
-#ifdef HAVE_EUIDACCESS
- bool res = (euidaccess (filename, 2) >= 0);
+ bool res = euidaccess (filename, W_OK) == 0;
#ifdef CYGWIN
/* euidaccess may have returned failure because Cygwin couldn't
determine the file's UID or GID; if so, we return success. */
@@ -2482,14 +2479,6 @@
}
#endif /* CYGWIN */
return res;
-#else /* not HAVE_EUIDACCESS */
- /* Access isn't quite right because it uses the real uid
- and we really want to test with the effective uid.
- But Unix doesn't give us a right way to do it.
- Opening with O_WRONLY could work for an ordinary file,
- but would lose for directories. */
- return (access (filename, 2) >= 0);
-#endif /* not HAVE_EUIDACCESS */
#endif /* not MSDOS */
}
@@ -2546,9 +2535,6 @@
{
Lisp_Object absname;
Lisp_Object handler;
- int desc;
- int flags;
- struct stat statbuf;
CHECK_STRING (filename);
absname = Fexpand_file_name (filename, Qnil);
@@ -2562,28 +2548,13 @@
absname = ENCODE_FILE (absname);
#if defined (DOS_NT) || defined (macintosh)
- /* Under MS-DOS, Windows, and Macintosh, open does not work for
- directories. */
+ /* FIXME: an euidaccess implementation should be added to the
+ DOS/Windows ports and this #ifdef branch should be removed. */
if (access (SDATA (absname), 0) == 0)
return Qt;
return Qnil;
#else /* not DOS_NT and not macintosh */
- flags = O_RDONLY;
-#ifdef O_NONBLOCK
- /* Opening a fifo without O_NONBLOCK can wait.
- We don't want to wait. But we don't want to mess wth O_NONBLOCK
- except in the case of a fifo, on a system which handles it. */
- desc = stat (SSDATA (absname), &statbuf);
- if (desc < 0)
- return Qnil;
- if (S_ISFIFO (statbuf.st_mode))
- flags |= O_NONBLOCK;
-#endif
- desc = emacs_open (SSDATA (absname), flags, 0);
- if (desc < 0)
- return Qnil;
- emacs_close (desc);
- return Qt;
+ return euidaccess (SSDATA (absname), R_OK) == 0 ? Qt : Qnil;
#endif /* not DOS_NT and not macintosh */
}
@@ -2702,8 +2673,7 @@
See `file-symlink-p' to distinguish symlinks. */)
(Lisp_Object filename)
{
- register Lisp_Object absname;
- struct stat st;
+ Lisp_Object absname;
Lisp_Object handler;
absname = expand_and_dir_to_file (filename, BVAR (current_buffer, directory));
@@ -2716,9 +2686,20 @@
absname = ENCODE_FILE (absname);
- if (stat (SSDATA (absname), &st) < 0)
- return Qnil;
- return S_ISDIR (st.st_mode) ? Qt : Qnil;
+ return file_directory_p (SSDATA (absname)) ? Qt : Qnil;
+}
+
+/* Return true if FILE is a directory or a symlink to a directory. */
+bool
+file_directory_p (char const *file)
+{
+#ifdef WINDOWSNT
+ /* 'access' is cheaper than 'stat'. */
+ return access (file, D_OK) == 0;
+#else
+ struct stat st;
+ return stat (file, &st) == 0 && S_ISDIR (st.st_mode);
+#endif
}
DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p,
=== modified file 'src/lisp.h'
--- src/lisp.h 2012-10-12 15:19:54 +0000
+++ src/lisp.h 2012-10-14 06:00:40 +0000
@@ -3179,6 +3179,7 @@
extern Lisp_Object restore_point_unwind (Lisp_Object);
extern _Noreturn void report_file_error (const char *, Lisp_Object);
extern void internal_delete_file (Lisp_Object);
+extern bool file_directory_p (const char *);
extern void syms_of_fileio (void);
extern Lisp_Object make_temp_name (Lisp_Object, bool);
extern Lisp_Object Qdelete_file;
=== modified file 'src/lread.c'
--- src/lread.c 2012-10-12 15:19:54 +0000
+++ src/lread.c 2012-10-14 06:00:40 +0000
@@ -1404,7 +1404,7 @@
If SUFFIXES is non-nil, it should be a list of suffixes to append to
file name when searching.
If non-nil, PREDICATE is used instead of `file-readable-p'.
-PREDICATE can also be an integer to pass to the access(2) function,
+PREDICATE can also be an integer to pass to the euidaccess(2) function,
in which case file-name-handlers are ignored.
This function will normally skip directories, so if you want it to find
directories, make sure the PREDICATE function returns `dir-ok' for them. */)
@@ -1442,7 +1442,6 @@
int
openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *storeptr, Lisp_Object predicate)
{
- int fd;
ptrdiff_t fn_size = 100;
char buf[100];
char *fn = buf;
@@ -1497,7 +1496,6 @@
{
ptrdiff_t fnlen, lsuffix = SBYTES (XCAR (tail));
Lisp_Object handler;
- bool exists;
/* Concatenate path element/specified name with the suffix.
If the directory starts with /:, remove that. */
@@ -1521,6 +1519,7 @@
handler = Ffind_file_name_handler (string, Qfile_exists_p);
if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate))
{
+ bool exists;
if (NILP (predicate))
exists = !NILP (Ffile_readable_p (string));
else
@@ -1542,37 +1541,38 @@
}
else
{
-#ifndef WINDOWSNT
- struct stat st;
-#endif
+ int fd;
const char *pfn;
encoded_fn = ENCODE_FILE (string);
pfn = SSDATA (encoded_fn);
-#ifdef WINDOWSNT
- exists = access (pfn, F_OK) == 0 && access (pfn, D_OK) < 0;
-#else
- exists = (stat (pfn, &st) == 0 && ! S_ISDIR (st.st_mode));
-#endif
- if (exists)
+
+ /* Check that we can access or open it. */
+ if (NATNUMP (predicate))
+ fd = (((XFASTINT (predicate) & ~INT_MAX) == 0
+ && euidaccess (pfn, XFASTINT (predicate)) == 0
+ && ! file_directory_p (pfn))
+ ? 1 : -1);
+ else
{
- /* Check that we can access or open it. */
- if (NATNUMP (predicate))
- fd = (((XFASTINT (predicate) & ~INT_MAX) == 0
- && access (pfn, XFASTINT (predicate)) == 0)
- ? 1 : -1);
- else
- fd = emacs_open (pfn, O_RDONLY, 0);
-
- if (fd >= 0)
+ struct stat st;
+ fd = emacs_open (pfn, O_RDONLY, 0);
+ if (0 <= fd
+ && (fstat (fd, &st) != 0 || S_ISDIR (st.st_mode)))
{
- /* We succeeded; return this descriptor and filename. */
- if (storeptr)
- *storeptr = string;
- UNGCPRO;
- return fd;
+ emacs_close (fd);
+ fd = -1;
}
}
+
+ if (fd >= 0)
+ {
+ /* We succeeded; return this descriptor and filename. */
+ if (storeptr)
+ *storeptr = string;
+ UNGCPRO;
+ return fd;
+ }
}
}
if (absolute)
@@ -4088,7 +4088,7 @@
if (STRINGP (dirfile))
{
dirfile = Fdirectory_file_name (dirfile);
- if (access (SSDATA (dirfile), 0) < 0)
+ if (euidaccess (SSDATA (dirfile), F_OK) != 0)
dir_warning ("Warning: Lisp directory `%s' does not exist.\n",
XCAR (path_tail));
}
=== modified file 'src/process.c'
--- src/process.c 2012-10-13 00:52:01 +0000
+++ src/process.c 2012-10-13 00:55:20 +0000
@@ -663,7 +663,7 @@
#else
sprintf (pty_name, "/dev/tty%c%x", c, i);
#endif /* no PTY_TTY_NAME_SPRINTF */
- if (access (pty_name, 6) != 0)
+ if (euidaccess (pty_name, R_OK | W_OK) != 0)
{
emacs_close (fd);
# ifndef __sgi
=== modified file 'src/xrdb.c'
--- src/xrdb.c 2012-09-15 07:06:56 +0000
+++ src/xrdb.c 2012-10-12 23:28:31 +0000
@@ -268,7 +268,7 @@
{
struct stat status;
- return (access (filename, 4) == 0 /* exists and is readable */
+ return (euidaccess (filename, R_OK) == 0 /* exists and is readable */
&& stat (filename, &status) == 0 /* get the status */
&& (S_ISDIR (status.st_mode)) == 0); /* not a directory */
}
next prev parent reply other threads:[~2012-10-14 6:16 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-13 1:58 bug#12632: file permissions checking mishandled when setuid Paul Eggert
2012-10-13 7:23 ` Eli Zaretskii
2012-10-13 8:36 ` Eli Zaretskii
2012-10-14 6:16 ` Paul Eggert [this message]
2012-10-14 6:56 ` Eli Zaretskii
2012-10-14 18:14 ` Paul Eggert
2012-10-14 18:39 ` Eli Zaretskii
2012-10-14 19:42 ` Paul Eggert
2012-10-14 20:10 ` Eli Zaretskii
2012-10-14 20:17 ` Eli Zaretskii
2012-10-14 20:40 ` Paul Eggert
2012-10-14 20:53 ` Eli Zaretskii
2012-10-15 6:17 ` Paul Eggert
2012-10-15 17:31 ` Eli Zaretskii
2012-10-15 21:38 ` Paul Eggert
2012-10-16 3:46 ` Eli Zaretskii
2012-10-16 6:00 ` Paul Eggert
2012-10-16 16:36 ` Eli Zaretskii
2012-10-19 17:01 ` Paul Eggert
2012-10-19 18:41 ` Eli Zaretskii
2012-10-19 18:54 ` Paul Eggert
2012-10-19 19:05 ` Glenn Morris
2012-10-19 19:36 ` Paul Eggert
2012-10-20 2:25 ` Richard Stallman
2012-10-20 4:36 ` Paul Eggert
2012-10-21 1:44 ` Glenn Morris
2012-10-21 2:52 ` Paul Eggert
2012-10-21 4:24 ` Glenn Morris
2012-10-22 6:03 ` Paul Eggert
2012-10-22 17:19 ` Eli Zaretskii
2012-10-22 20:33 ` Paul Eggert
2012-10-22 21:04 ` Eli Zaretskii
2012-10-22 21:30 ` Paul Eggert
2012-10-23 0:40 ` Stefan Monnier
2012-10-23 1:46 ` Paul Eggert
2012-10-23 3:49 ` Eli Zaretskii
2012-10-23 3:47 ` Eli Zaretskii
2012-10-23 5:07 ` Paul Eggert
2012-10-23 16:44 ` Eli Zaretskii
2012-10-23 19:27 ` Paul Eggert
2012-10-23 19:50 ` Eli Zaretskii
2012-10-23 20:01 ` Paul Eggert
2012-10-23 23:15 ` Andy Moreton
2012-10-24 3:51 ` Eli Zaretskii
2012-10-19 19:10 ` Eli Zaretskii
2012-11-13 2:19 ` bug#12632: updated version of the patch Paul Eggert
2012-11-14 5:10 ` Paul Eggert
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=507A58CC.10209@cs.ucla.edu \
--to=eggert@cs.ucla.edu \
--cc=12632@debbugs.gnu.org \
--cc=eliz@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
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).