diff options
| author | Paul Eggert | 2020-02-23 16:19:42 -0800 |
|---|---|---|
| committer | Paul Eggert | 2020-02-23 16:45:50 -0800 |
| commit | 9d626dffc6ba62c0d7a1a5c712f576ed8684fd66 (patch) | |
| tree | 6cc8fbe8e5bc02c3bb74139710814a0400e91a8a /src | |
| parent | c4ca8219dd6b8f06e67a0b767475b1259653b8e0 (diff) | |
| download | emacs-9d626dffc6ba62c0d7a1a5c712f576ed8684fd66.tar.gz emacs-9d626dffc6ba62c0d7a1a5c712f576ed8684fd66.zip | |
Add 'nofollow' flag to set-file-modes etc.
This avoids some race conditions (Bug#39683). E.g., if some other
program changes a file to a symlink between the time Emacs creates
the file and the time it changes the file’s permissions, using the
new flag prevents Emacs from inadvertently changing the
permissions of a victim in some completely unrelated directory.
* admin/merge-gnulib (GNULIB_MODULES): Add fchmodat.
* doc/lispref/files.texi (Testing Accessibility, Changing Files):
* doc/lispref/os.texi (File Notifications):
* etc/NEWS:
Adjust documentation accordingly.
* lib/chmodat.c, lib/fchmodat.c, lib/lchmod.c, m4/fchmodat.m4:
* m4/lchmod.m4: New files, copied from Gnulib.
* lib/gnulib.mk.in: Regenerate.
* lisp/dired-aux.el (dired-do-chmod):
* lisp/doc-view.el (doc-view-make-safe-dir):
* lisp/emacs-lisp/autoload.el (autoload--save-buffer):
* lisp/emacs-lisp/bytecomp.el (byte-compile-file):
* lisp/eshell/em-pred.el (eshell-pred-file-mode):
* lisp/files.el (backup-buffer-copy, copy-directory):
* lisp/gnus/mail-source.el (mail-source-movemail):
* lisp/gnus/mm-decode.el (mm-display-external):
* lisp/gnus/nnmail.el (nnmail-write-region):
* lisp/net/tramp-adb.el (tramp-adb-handle-file-local-copy)
(tramp-adb-handle-write-region):
* lisp/net/tramp-sh.el (tramp-do-copy-or-rename-file-directly):
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-write-region):
* lisp/net/tramp.el (tramp-handle-write-region)
(tramp-make-tramp-temp-file):
* lisp/server.el (server-ensure-safe-dir):
* lisp/url/url-util.el (url-make-private-file):
When getting or setting file modes, avoid following symbolic links
when the file is not supposed to be a symbolic link.
* lisp/doc-view.el (doc-view-make-safe-dir):
Omit no-longer-needed separate symlink test.
* lisp/gnus/gnus-util.el (gnus-set-file-modes):
* lisp/net/tramp.el (tramp-handle-file-modes):
* lisp/net/tramp-gvfs.el (tramp-gvfs-handle-set-file-modes):
* src/fileio.c (symlink_nofollow_flag): New function.
(Ffile_modes, Fset_file_modes):
Support an optional FLAG arg. All C callers changed.
* lisp/net/ange-ftp.el (ange-ftp-set-file-modes):
* lisp/net/tramp-adb.el (tramp-adb-handle-set-file-modes):
* lisp/net/tramp-sh.el (tramp-sh-handle-set-file-modes):
* lisp/net/tramp-smb.el (tramp-smb-handle-set-file-modes):
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-set-file-modes):
Accept an optional FLAG arg that is currently ignored,
and add a FIXME comment for it.
* m4/gnulib-comp.m4: Regenerate.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 46 |
1 files changed, 28 insertions, 18 deletions
diff --git a/src/fileio.c b/src/fileio.c index 6b56c473abf..2532f5233c4 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -3332,50 +3332,60 @@ support. */) | |||
| 3332 | return Qnil; | 3332 | return Qnil; |
| 3333 | } | 3333 | } |
| 3334 | 3334 | ||
| 3335 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, | 3335 | static int |
| 3336 | symlink_nofollow_flag (Lisp_Object flag) | ||
| 3337 | { | ||
| 3338 | /* For now, treat all non-nil FLAGs like 'nofollow'. */ | ||
| 3339 | return !NILP (flag) ? AT_SYMLINK_NOFOLLOW : 0; | ||
| 3340 | } | ||
| 3341 | |||
| 3342 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 2, 0, | ||
| 3336 | doc: /* Return mode bits of file named FILENAME, as an integer. | 3343 | doc: /* Return mode bits of file named FILENAME, as an integer. |
| 3337 | Return nil if FILENAME does not exist. */) | 3344 | Return nil if FILENAME does not exist. If optional FLAG is `nofollow', |
| 3338 | (Lisp_Object filename) | 3345 | do not follow FILENAME if it is a symbolic link. */) |
| 3346 | (Lisp_Object filename, Lisp_Object flag) | ||
| 3339 | { | 3347 | { |
| 3340 | struct stat st; | 3348 | struct stat st; |
| 3349 | int nofollow = symlink_nofollow_flag (flag); | ||
| 3341 | Lisp_Object absname = expand_and_dir_to_file (filename); | 3350 | Lisp_Object absname = expand_and_dir_to_file (filename); |
| 3342 | 3351 | ||
| 3343 | /* If the file name has special constructs in it, | 3352 | /* If the file name has special constructs in it, |
| 3344 | call the corresponding file name handler. */ | 3353 | call the corresponding file name handler. */ |
| 3345 | Lisp_Object handler = Ffind_file_name_handler (absname, Qfile_modes); | 3354 | Lisp_Object handler = Ffind_file_name_handler (absname, Qfile_modes); |
| 3346 | if (!NILP (handler)) | 3355 | if (!NILP (handler)) |
| 3347 | return call2 (handler, Qfile_modes, absname); | 3356 | return call3 (handler, Qfile_modes, absname, flag); |
| 3348 | 3357 | ||
| 3349 | if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname)), &st, 0) != 0) | 3358 | char *fname = SSDATA (ENCODE_FILE (absname)); |
| 3359 | if (emacs_fstatat (AT_FDCWD, fname, &st, nofollow) != 0) | ||
| 3350 | return file_attribute_errno (absname, errno); | 3360 | return file_attribute_errno (absname, errno); |
| 3351 | return make_fixnum (st.st_mode & 07777); | 3361 | return make_fixnum (st.st_mode & 07777); |
| 3352 | } | 3362 | } |
| 3353 | 3363 | ||
| 3354 | DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, | 3364 | DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 3, |
| 3355 | "(let ((file (read-file-name \"File: \"))) \ | 3365 | "(let ((file (read-file-name \"File: \"))) \ |
| 3356 | (list file (read-file-modes nil file)))", | 3366 | (list file (read-file-modes nil file)))", |
| 3357 | doc: /* Set mode bits of file named FILENAME to MODE (an integer). | 3367 | doc: /* Set mode bits of file named FILENAME to MODE (an integer). |
| 3358 | Only the 12 low bits of MODE are used. | 3368 | Only the 12 low bits of MODE are used. If optional FLAG is `nofollow', |
| 3369 | do not follow FILENAME if it is a symbolic link. | ||
| 3359 | 3370 | ||
| 3360 | Interactively, mode bits are read by `read-file-modes', which accepts | 3371 | Interactively, mode bits are read by `read-file-modes', which accepts |
| 3361 | symbolic notation, like the `chmod' command from GNU Coreutils. */) | 3372 | symbolic notation, like the `chmod' command from GNU Coreutils. */) |
| 3362 | (Lisp_Object filename, Lisp_Object mode) | 3373 | (Lisp_Object filename, Lisp_Object mode, Lisp_Object flag) |
| 3363 | { | 3374 | { |
| 3364 | Lisp_Object absname, encoded_absname; | ||
| 3365 | Lisp_Object handler; | ||
| 3366 | |||
| 3367 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)); | ||
| 3368 | CHECK_FIXNUM (mode); | 3375 | CHECK_FIXNUM (mode); |
| 3376 | int nofollow = symlink_nofollow_flag (flag); | ||
| 3377 | Lisp_Object absname = Fexpand_file_name (filename, | ||
| 3378 | BVAR (current_buffer, directory)); | ||
| 3369 | 3379 | ||
| 3370 | /* If the file name has special constructs in it, | 3380 | /* If the file name has special constructs in it, |
| 3371 | call the corresponding file name handler. */ | 3381 | call the corresponding file name handler. */ |
| 3372 | handler = Ffind_file_name_handler (absname, Qset_file_modes); | 3382 | Lisp_Object handler = Ffind_file_name_handler (absname, Qset_file_modes); |
| 3373 | if (!NILP (handler)) | 3383 | if (!NILP (handler)) |
| 3374 | return call3 (handler, Qset_file_modes, absname, mode); | 3384 | return call4 (handler, Qset_file_modes, absname, mode, flag); |
| 3375 | |||
| 3376 | encoded_absname = ENCODE_FILE (absname); | ||
| 3377 | 3385 | ||
| 3378 | if (chmod (SSDATA (encoded_absname), XFIXNUM (mode) & 07777) < 0) | 3386 | char *fname = SSDATA (ENCODE_FILE (absname)); |
| 3387 | mode_t imode = XFIXNUM (mode) & 07777; | ||
| 3388 | if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0) | ||
| 3379 | report_file_error ("Doing chmod", absname); | 3389 | report_file_error ("Doing chmod", absname); |
| 3380 | 3390 | ||
| 3381 | return Qnil; | 3391 | return Qnil; |
| @@ -5740,7 +5750,7 @@ auto_save_1 (void) | |||
| 5740 | == 0) | 5750 | == 0) |
| 5741 | /* But make sure we can overwrite it later! */ | 5751 | /* But make sure we can overwrite it later! */ |
| 5742 | auto_save_mode_bits = (st.st_mode | 0600) & 0777; | 5752 | auto_save_mode_bits = (st.st_mode | 0600) & 0777; |
| 5743 | else if (modes = Ffile_modes (BVAR (current_buffer, filename)), | 5753 | else if (modes = Ffile_modes (BVAR (current_buffer, filename), Qnil), |
| 5744 | FIXNUMP (modes)) | 5754 | FIXNUMP (modes)) |
| 5745 | /* Remote files don't cooperate with fstatat. */ | 5755 | /* Remote files don't cooperate with fstatat. */ |
| 5746 | auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777; | 5756 | auto_save_mode_bits = (XFIXNUM (modes) | 0600) & 0777; |