aboutsummaryrefslogtreecommitdiffstats
path: root/src/w32.c
diff options
context:
space:
mode:
authorPaul Eggert2012-11-13 20:55:41 -0800
committerPaul Eggert2012-11-13 20:55:41 -0800
commit73dcdb9f30cb94a3183db54d9b463370c3978d4d (patch)
tree216d47d5bc96bce2a4ca87a57967b0e1c3c151f2 /src/w32.c
parent9c3912d3d9aaa1e20e3f7168f5764695ad5e43fd (diff)
downloademacs-73dcdb9f30cb94a3183db54d9b463370c3978d4d.tar.gz
emacs-73dcdb9f30cb94a3183db54d9b463370c3978d4d.zip
Use faccessat, not access, when checking file permissions.
This fixes a bug that has been present in Emacs since its creation. It was reported by Chris Torek in 1983 even before GNU Emacs existed, which must set some sort of record. (Torek's bug report was against a predecessor of GNU Emacs, but GNU Emacs happened to have the same common flaw.) See Torek's Usenet posting "setuid/setgid programs & Emacs" Article-I.D.: sri-arpa.858 Posted: Fri Apr 8 14:18:56 1983. * .bzrignore: Add lib/fcntl.h. * configure.ac (euidaccess): Remove check; gnulib does this for us now. (gl_FCNTL_O_FLAGS): Define a dummy version. * lib/at-func.c, lib/euidaccess.c, lib/faccessat.c, lib/fcntl.in.h: * lib/getgroups.c, lib/group-member.c, lib/root-uid.h: * lib/xalloc-oversized.h, m4/euidaccess.m4, m4/faccessat.m4: * m4/fcntl_h.m4, m4/getgroups.m4, m4/group-member.m4: New files, from gnulib. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * admin/merge-gnulib (GNULIB_MODULES): Add faccessat. (GNULIB_TOOL_FLAGS): Avoid at-internal, fchdir, malloc-posix, openat-die, openat-h, save-cwd. Do not avoid fcntl-h. Omit gnulib's m4/fcntl-o.m4. * nt/inc/ms-w32.h (AT_FDCWD, AT_EACCESS): New symbols. (access): Remove. (faccessat): New macro. * src/Makefile.in (LIB_EACCESS): New macro. (LIBES): Use it. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/fileio.c (check_existing, check_executable, check_writable) (Ffile_readable_p): * src/lread.c (openp, load_path_check): * src/process.c (allocate_pty): * src/xrdb.c (file_p): Use effective UID when checking permissions, not real UID. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/lread.c (load_path_check, init_lread): Test whether directories are accessible, not merely whether they exist. * src/conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): New macro. * src/fileio.c (check_existing, check_executable, check_writable) (Ffile_readable_p): Use symbolic names instead of integers for the flags, as they're portable now. (check_writable): New arg AMODE. All uses changed. Set errno on failure. (Ffile_readable_p): Use faccessat, not stat + open + close. (Ffile_writable_p): No need to call check_existing + check_writable. Just call check_writable and then look at errno. This saves a syscall. dir should never be nil; replace an unnecessary runtime check with an eassert. When checking the parent directory of a nonexistent file, check that the directory is searchable as well as writable, as we can't create files in unsearchable directories. (file_directory_p): New function, which uses 'stat' on most platforms but faccessat with D_OK (for efficiency) if WINDOWSNT. (Ffile_directory_p, Fset_file_times): Use it. (file_accessible_directory_p): New function, which uses a single syscall for efficiency. (Ffile_accessible_directory_p): Use it. * src/xrdb.c (file_p): Use file_directory_p. * src/lisp.h (file_directory_p, file_accessible_directory_p): New decls. * src/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. (dir_warning): First arg is now a usage string, not a format. Use errno. All uses changed. * src/nsterm.m (ns_term_init): Remove unnecessary call to file-readable that merely introduced a race. * src/process.c, src/sysdep.c, src/term.c: All uses of '#ifdef O_NONBLOCK' changed to '#if O_NONBLOCK', to accommodate gnulib O_* style, and similarly for the other O_* flags. * src/w32.c (sys_faccessat): Rename from sys_access and switch to faccessat's API. All uses changed. * src/xrdb.c: Do not include <sys/stat.h>; no longer needed. (magic_db): Rename from magic_file_p. (magic_db, search_magic_path): Return an XrmDatabase rather than a char *, so that we don't have to test for file existence separately from opening the file for reading. This removes a race fixes a permission-checking problem, and simplifies the code. All uses changed. (file_p): Remove; no longer needed. Fixes: debbugs:12632
Diffstat (limited to 'src/w32.c')
-rw-r--r--src/w32.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/src/w32.c b/src/w32.c
index 5ac1bc3eb7c..0e7da449b81 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -1597,7 +1597,7 @@ init_environment (char ** argv)
1597 see if it succeeds. But I think that's too much to ask. */ 1597 see if it succeeds. But I think that's too much to ask. */
1598 1598
1599 /* MSVCRT's _access crashes with D_OK. */ 1599 /* MSVCRT's _access crashes with D_OK. */
1600 if (tmp && sys_access (tmp, D_OK) == 0) 1600 if (tmp && sys_faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
1601 { 1601 {
1602 char * var = alloca (strlen (tmp) + 8); 1602 char * var = alloca (strlen (tmp) + 8);
1603 sprintf (var, "TMPDIR=%s", tmp); 1603 sprintf (var, "TMPDIR=%s", tmp);
@@ -2714,10 +2714,16 @@ logon_network_drive (const char *path)
2714 long file names. */ 2714 long file names. */
2715 2715
2716int 2716int
2717sys_access (const char * path, int mode) 2717sys_faccessat (int dirfd, const char * path, int mode, int flags)
2718{ 2718{
2719 DWORD attributes; 2719 DWORD attributes;
2720 2720
2721 if (dirfd != AT_FDCWD)
2722 {
2723 errno = EBADF;
2724 return -1;
2725 }
2726
2721 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its 2727 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
2722 newer versions blow up when passed D_OK. */ 2728 newer versions blow up when passed D_OK. */
2723 path = map_w32_filename (path, NULL); 2729 path = map_w32_filename (path, NULL);
@@ -2960,7 +2966,7 @@ sys_mktemp (char * template)
2960 { 2966 {
2961 int save_errno = errno; 2967 int save_errno = errno;
2962 p[0] = first_char[i]; 2968 p[0] = first_char[i];
2963 if (sys_access (template, 0) < 0) 2969 if (sys_faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0)
2964 { 2970 {
2965 errno = save_errno; 2971 errno = save_errno;
2966 return template; 2972 return template;
@@ -4011,7 +4017,7 @@ symlink (char const *filename, char const *linkname)
4011 { 4017 {
4012 /* Non-absolute FILENAME is understood as being relative to 4018 /* Non-absolute FILENAME is understood as being relative to
4013 LINKNAME's directory. We need to prepend that directory to 4019 LINKNAME's directory. We need to prepend that directory to
4014 FILENAME to get correct results from sys_access below, since 4020 FILENAME to get correct results from sys_faccessat below, since
4015 otherwise it will interpret FILENAME relative to the 4021 otherwise it will interpret FILENAME relative to the
4016 directory where the Emacs process runs. Note that 4022 directory where the Emacs process runs. Note that
4017 make-symbolic-link always makes sure LINKNAME is a fully 4023 make-symbolic-link always makes sure LINKNAME is a fully
@@ -4025,10 +4031,10 @@ symlink (char const *filename, char const *linkname)
4025 strncpy (tem, linkfn, p - linkfn); 4031 strncpy (tem, linkfn, p - linkfn);
4026 tem[p - linkfn] = '\0'; 4032 tem[p - linkfn] = '\0';
4027 strcat (tem, filename); 4033 strcat (tem, filename);
4028 dir_access = sys_access (tem, D_OK); 4034 dir_access = sys_faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
4029 } 4035 }
4030 else 4036 else
4031 dir_access = sys_access (filename, D_OK); 4037 dir_access = sys_faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
4032 4038
4033 /* Since Windows distinguishes between symlinks to directories and 4039 /* Since Windows distinguishes between symlinks to directories and
4034 to files, we provide a kludgy feature: if FILENAME doesn't 4040 to files, we provide a kludgy feature: if FILENAME doesn't