aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.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/process.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/process.c')
-rw-r--r--src/process.c36
1 files changed, 18 insertions, 18 deletions
diff --git a/src/process.c b/src/process.c
index 43f0239d301..728abebe758 100644
--- a/src/process.c
+++ b/src/process.c
@@ -208,7 +208,7 @@ static EMACS_INT update_tick;
208#ifndef NON_BLOCKING_CONNECT 208#ifndef NON_BLOCKING_CONNECT
209#ifdef HAVE_SELECT 209#ifdef HAVE_SELECT
210#if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX) 210#if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
211#if defined (O_NONBLOCK) || defined (O_NDELAY) 211#if O_NONBLOCK || O_NDELAY
212#if defined (EWOULDBLOCK) || defined (EINPROGRESS) 212#if defined (EWOULDBLOCK) || defined (EINPROGRESS)
213#define NON_BLOCKING_CONNECT 213#define NON_BLOCKING_CONNECT
214#endif /* EWOULDBLOCK || EINPROGRESS */ 214#endif /* EWOULDBLOCK || EINPROGRESS */
@@ -655,7 +655,7 @@ allocate_pty (void)
655 PTY_OPEN; 655 PTY_OPEN;
656#else /* no PTY_OPEN */ 656#else /* no PTY_OPEN */
657 { 657 {
658# ifdef O_NONBLOCK 658# if O_NONBLOCK
659 fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0); 659 fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
660# else 660# else
661 fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0); 661 fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0);
@@ -672,7 +672,7 @@ allocate_pty (void)
672#else 672#else
673 sprintf (pty_name, "/dev/tty%c%x", c, i); 673 sprintf (pty_name, "/dev/tty%c%x", c, i);
674#endif /* no PTY_TTY_NAME_SPRINTF */ 674#endif /* no PTY_TTY_NAME_SPRINTF */
675 if (access (pty_name, 6) != 0) 675 if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0)
676 { 676 {
677 emacs_close (fd); 677 emacs_close (fd);
678# ifndef __sgi 678# ifndef __sgi
@@ -1624,7 +1624,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
1624#if ! defined (USG) || defined (USG_SUBTTY_WORKS) 1624#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
1625 /* On most USG systems it does not work to open the pty's tty here, 1625 /* On most USG systems it does not work to open the pty's tty here,
1626 then close it and reopen it in the child. */ 1626 then close it and reopen it in the child. */
1627#ifdef O_NOCTTY 1627#if O_NOCTTY
1628 /* Don't let this terminal become our controlling terminal 1628 /* Don't let this terminal become our controlling terminal
1629 (in case we don't have one). */ 1629 (in case we don't have one). */
1630 forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); 1630 forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
@@ -1678,11 +1678,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
1678 } 1678 }
1679#endif 1679#endif
1680 1680
1681#ifdef O_NONBLOCK 1681#if O_NONBLOCK
1682 fcntl (inchannel, F_SETFL, O_NONBLOCK); 1682 fcntl (inchannel, F_SETFL, O_NONBLOCK);
1683 fcntl (outchannel, F_SETFL, O_NONBLOCK); 1683 fcntl (outchannel, F_SETFL, O_NONBLOCK);
1684#else 1684#else
1685#ifdef O_NDELAY 1685#if O_NDELAY
1686 fcntl (inchannel, F_SETFL, O_NDELAY); 1686 fcntl (inchannel, F_SETFL, O_NDELAY);
1687 fcntl (outchannel, F_SETFL, O_NDELAY); 1687 fcntl (outchannel, F_SETFL, O_NDELAY);
1688#endif 1688#endif
@@ -1943,7 +1943,7 @@ create_pty (Lisp_Object process)
1943#if ! defined (USG) || defined (USG_SUBTTY_WORKS) 1943#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
1944 /* On most USG systems it does not work to open the pty's tty here, 1944 /* On most USG systems it does not work to open the pty's tty here,
1945 then close it and reopen it in the child. */ 1945 then close it and reopen it in the child. */
1946#ifdef O_NOCTTY 1946#if O_NOCTTY
1947 /* Don't let this terminal become our controlling terminal 1947 /* Don't let this terminal become our controlling terminal
1948 (in case we don't have one). */ 1948 (in case we don't have one). */
1949 int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); 1949 int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
@@ -1963,11 +1963,11 @@ create_pty (Lisp_Object process)
1963 } 1963 }
1964#endif /* HAVE_PTYS */ 1964#endif /* HAVE_PTYS */
1965 1965
1966#ifdef O_NONBLOCK 1966#if O_NONBLOCK
1967 fcntl (inchannel, F_SETFL, O_NONBLOCK); 1967 fcntl (inchannel, F_SETFL, O_NONBLOCK);
1968 fcntl (outchannel, F_SETFL, O_NONBLOCK); 1968 fcntl (outchannel, F_SETFL, O_NONBLOCK);
1969#else 1969#else
1970#ifdef O_NDELAY 1970#if O_NDELAY
1971 fcntl (inchannel, F_SETFL, O_NDELAY); 1971 fcntl (inchannel, F_SETFL, O_NDELAY);
1972 fcntl (outchannel, F_SETFL, O_NDELAY); 1972 fcntl (outchannel, F_SETFL, O_NDELAY);
1973#endif 1973#endif
@@ -2927,7 +2927,7 @@ usage: (make-network-process &rest ARGS) */)
2927 { 2927 {
2928 /* Don't support network sockets when non-blocking mode is 2928 /* Don't support network sockets when non-blocking mode is
2929 not available, since a blocked Emacs is not useful. */ 2929 not available, since a blocked Emacs is not useful. */
2930#if !defined (O_NONBLOCK) && !defined (O_NDELAY) 2930#if !O_NONBLOCK && !O_NDELAY
2931 error ("Network servers not supported"); 2931 error ("Network servers not supported");
2932#else 2932#else
2933 is_server = 1; 2933 is_server = 1;
@@ -3193,7 +3193,7 @@ usage: (make-network-process &rest ARGS) */)
3193#ifdef NON_BLOCKING_CONNECT 3193#ifdef NON_BLOCKING_CONNECT
3194 if (is_non_blocking_client) 3194 if (is_non_blocking_client)
3195 { 3195 {
3196#ifdef O_NONBLOCK 3196#if O_NONBLOCK
3197 ret = fcntl (s, F_SETFL, O_NONBLOCK); 3197 ret = fcntl (s, F_SETFL, O_NONBLOCK);
3198#else 3198#else
3199 ret = fcntl (s, F_SETFL, O_NDELAY); 3199 ret = fcntl (s, F_SETFL, O_NDELAY);
@@ -3410,10 +3410,10 @@ usage: (make-network-process &rest ARGS) */)
3410 3410
3411 chan_process[inch] = proc; 3411 chan_process[inch] = proc;
3412 3412
3413#ifdef O_NONBLOCK 3413#if O_NONBLOCK
3414 fcntl (inch, F_SETFL, O_NONBLOCK); 3414 fcntl (inch, F_SETFL, O_NONBLOCK);
3415#else 3415#else
3416#ifdef O_NDELAY 3416#if O_NDELAY
3417 fcntl (inch, F_SETFL, O_NDELAY); 3417 fcntl (inch, F_SETFL, O_NDELAY);
3418#endif 3418#endif
3419#endif 3419#endif
@@ -4145,10 +4145,10 @@ server_accept_connection (Lisp_Object server, int channel)
4145 4145
4146 chan_process[s] = proc; 4146 chan_process[s] = proc;
4147 4147
4148#ifdef O_NONBLOCK 4148#if O_NONBLOCK
4149 fcntl (s, F_SETFL, O_NONBLOCK); 4149 fcntl (s, F_SETFL, O_NONBLOCK);
4150#else 4150#else
4151#ifdef O_NDELAY 4151#if O_NDELAY
4152 fcntl (s, F_SETFL, O_NDELAY); 4152 fcntl (s, F_SETFL, O_NDELAY);
4153#endif 4153#endif
4154#endif 4154#endif
@@ -4849,11 +4849,11 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
4849#endif 4849#endif
4850 /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK, 4850 /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK,
4851 and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */ 4851 and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */
4852#ifdef O_NONBLOCK 4852#if O_NONBLOCK
4853 else if (nread == -1 && errno == EAGAIN) 4853 else if (nread == -1 && errno == EAGAIN)
4854 ; 4854 ;
4855#else 4855#else
4856#ifdef O_NDELAY 4856#if O_NDELAY
4857 else if (nread == -1 && errno == EAGAIN) 4857 else if (nread == -1 && errno == EAGAIN)
4858 ; 4858 ;
4859 /* Note that we cannot distinguish between no input 4859 /* Note that we cannot distinguish between no input
@@ -7348,7 +7348,7 @@ init_process_emacs (void)
7348#ifdef HAVE_GETSOCKNAME 7348#ifdef HAVE_GETSOCKNAME
7349 ADD_SUBFEATURE (QCservice, Qt); 7349 ADD_SUBFEATURE (QCservice, Qt);
7350#endif 7350#endif
7351#if defined (O_NONBLOCK) || defined (O_NDELAY) 7351#if O_NONBLOCK || O_NDELAY
7352 ADD_SUBFEATURE (QCserver, Qt); 7352 ADD_SUBFEATURE (QCserver, Qt);
7353#endif 7353#endif
7354 7354