Line
Link Here
|
|
Do not set `trusted-content` in major modes |
|
Do not set `trusted-content` in major modes |
1 |
(elisp-flymake-byte-compile): Improve UX with `debug-on-error` |
1 |
(elisp-flymake-byte-compile): Improve UX with `debug-on-error` |
2 |
Document 'trusted-content |
2 |
Document 'trusted-content |
3 |
* lisp/files.el (trusted-content-p): Make `:all` work in non-file buffers |
3 |
* lisp/files.el (trusted-content-p): Make `:all` work in non-file buffers |
4 |
trusted-content: Adjust the last patch based on preliminary feedback |
4 |
trusted-content: Adjust the last patch based on preliminary feedback |
5 |
elisp-mode.el: Disable Flymake byte-compile backend in untrusted files |
5 |
elisp-mode.el: Disable Flymake byte-compile backend in untrusted files |
6 |
|
6 |
|
7 |
(elisp--local-variables): Fix recent regression |
7 |
(elisp--local-variables): Fix recent regression |
8 |
-- emacs-29.4/doc/emacs/misc.texi |
8 |
++ emacs-29.4/doc/emacs/misc.texi |
Lines 277-282
Link Here
|
277 |
you can set @code{enable-local-variables} to @code{:all}. @xref{Safe |
277 |
you can set @code{enable-local-variables} to @code{:all}. @xref{Safe |
278 |
File Variables}. |
278 |
File Variables}. |
279 |
|
279 |
|
|
|
280 |
@cindex trusted files and directories |
281 |
Loading a file of Emacs Lisp code with @code{load-file} or |
282 |
@code{load-library} (@pxref{Lisp Libraries}) can execute some of the |
283 |
Lisp code in the file being loaded, so you should only load Lisp files |
284 |
whose source you trust. However, some Emacs features can in certain |
285 |
situations execute Lisp code even without your explicit command or |
286 |
request. For example, Flymake, the on-the-fly syntax checker for Emacs |
287 |
(@pxref{Top,,, flymake, GNU Flymake}), if it is enabled, can |
288 |
automatically execute some of the code in a Lisp file you visit as part |
289 |
of its syntax-checking job. Similarly, some completion commands |
290 |
(@pxref{Completion}) in buffers visiting Lisp files sometimes need to |
291 |
expand Lisp macros for best results. In these cases, just visiting a |
292 |
Lisp file and performing some editing in it could trigger execution of |
293 |
Lisp code. If the visited file came from an untrusted source, it could |
294 |
include dangerous or even malicious code that Emacs would execute in |
295 |
those situations. |
296 |
|
297 |
To protect against this, Emacs disables execution of Lisp code by |
298 |
Flymake, completion, and some other features, unless the visited file is |
299 |
@dfn{trusted}. It is up to you to specify which files on your system |
300 |
should be trusted, by customizing the user option |
301 |
@code{trusted-content}. |
302 |
|
303 |
@defopt trusted-content |
304 |
The value of this option is @code{nil} by default, which means no file |
305 |
is trusted. You can customize the variable to be a list of one or more |
306 |
names of trusted files and directories. A file name that ends in a |
307 |
slash @file{/} is interpreted as a directory, which means all its files |
308 |
and subdirectories are also trusted. A special value @code{:all} means |
309 |
@emph{all} the files and directories on your system should be trusted; |
310 |
@strong{this is not recommended}, as it opens a gaping security hole. |
311 |
@end defopt |
312 |
|
280 |
@xref{Security Considerations,,, elisp, The Emacs Lisp Reference |
313 |
@xref{Security Considerations,,, elisp, The Emacs Lisp Reference |
281 |
Manual}, for more information about security considerations when using |
314 |
Manual}, for more information about security considerations when using |
282 |
Emacs as part of a larger application. |
315 |
Emacs as part of a larger application. |
283 |
-- emacs-29.4/lisp/files.el |
316 |
++ emacs-29.4/lisp/files.el |
Lines 703-708
Link Here
|
703 |
This variable might be subject to change without notice.") |
703 |
This variable might be subject to change without notice.") |
704 |
(put 'untrusted-content 'permanent-local t) |
704 |
(put 'untrusted-content 'permanent-local t) |
705 |
|
705 |
|
|
|
706 |
(defcustom trusted-content nil |
707 |
"List of files and directories whose content we trust. |
708 |
Be extra careful here since trusting means that Emacs might execute the |
709 |
code contained within those files and directories without an explicit |
710 |
request by the user. |
711 |
One important case when this might happen is when `flymake-mode' is |
712 |
enabled (for example, when it is added to a mode hook). |
713 |
Each element of the list should be a string: |
714 |
- If it ends in \"/\", it is considered as a directory name and means that |
715 |
Emacs should trust all the files whose name has this directory as a prefix. |
716 |
- Otherwise, it is considered a file name. |
717 |
Use abbreviated file names. For example, an entry \"~/mycode/\" means |
718 |
that Emacs will trust all the files in your directory \"mycode\". |
719 |
This variable can also be set to `:all', in which case Emacs will trust |
720 |
all files, which opens a gaping security hole. Emacs Lisp authors |
721 |
should note that this value must never be set by a major or minor mode." |
722 |
:type '(choice (repeat :tag "List" file) |
723 |
(const :tag "Trust everything (DANGEROUS!)" :all)) |
724 |
:version "30.1") |
725 |
(put 'trusted-content 'risky-local-variable t) |
726 |
|
727 |
(defun trusted-content-p () |
728 |
"Return non-nil if we trust the contents of the current buffer. |
729 |
Here, \"trust\" means that we are willing to run code found inside of it. |
730 |
See also `trusted-content'." |
731 |
;; We compare with `buffer-file-truename' i.s.o `buffer-file-name' |
732 |
;; to try and avoid marking as trusted a file that's merely accessed |
733 |
;; via a symlink that happens to be inside a trusted dir. |
734 |
(and (not untrusted-content) |
735 |
(or |
736 |
(eq trusted-content :all) |
737 |
(and |
738 |
buffer-file-truename |
739 |
(with-demoted-errors "trusted-content-p: %S" |
740 |
(let ((exists (file-exists-p buffer-file-truename))) |
741 |
(or |
742 |
;; We can't avoid trusting the user's init file. |
743 |
(if (and exists user-init-file) |
744 |
(file-equal-p buffer-file-truename user-init-file) |
745 |
(equal buffer-file-truename user-init-file)) |
746 |
(let ((file (abbreviate-file-name buffer-file-truename)) |
747 |
(trusted nil)) |
748 |
(dolist (tf trusted-content) |
749 |
(when (or (if exists (file-equal-p tf file) (equal tf file)) |
750 |
;; We don't use `file-in-directory-p' here, because |
751 |
;; we want to err on the conservative side: "guilty |
752 |
;; until proven innocent". |
753 |
(and (string-suffix-p "/" tf) |
754 |
(string-prefix-p tf file))) |
755 |
(setq trusted t))) |
756 |
trusted)))))))) |
757 |
|
706 |
;; This is an odd variable IMO. |
758 |
;; This is an odd variable IMO. |
707 |
;; You might wonder why it is needed, when we could just do: |
759 |
;; You might wonder why it is needed, when we could just do: |
708 |
;; (setq-local enable-local-variables nil) |
760 |
;; (setq-local enable-local-variables nil) |
709 |
-- emacs-29.4/lisp/ielm.el |
761 |
++ emacs-29.4/lisp/ielm.el |
Lines 647-653
Link Here
|
647 |
(unless (comint-check-proc buf-name) |
647 |
(unless (comint-check-proc buf-name) |
648 |
(with-current-buffer (get-buffer-create buf-name) |
648 |
(with-current-buffer (get-buffer-create buf-name) |
649 |
(unless (zerop (buffer-size)) (setq old-point (point))) |
649 |
(unless (zerop (buffer-size)) (setq old-point (point))) |
650 |
(inferior-emacs-lisp-mode))) |
650 |
(inferior-emacs-lisp-mode) |
|
|
651 |
(setq-local trusted-content :all))) |
651 |
(pop-to-buffer-same-window buf-name) |
652 |
(pop-to-buffer-same-window buf-name) |
652 |
(when old-point (push-mark old-point)))) |
653 |
(when old-point (push-mark old-point)))) |
653 |
|
654 |
|
654 |
-- emacs-29.4/lisp/progmodes/elisp-mode.el |
655 |
++ emacs-29.4/lisp/progmodes/elisp-mode.el |
Lines 430-435
Link Here
|
430 |
|
430 |
|
431 |
(defvar warning-minimum-log-level) |
431 |
(defvar warning-minimum-log-level) |
432 |
|
432 |
|
|
|
433 |
(defvar elisp--local-macroenv |
434 |
`((cl-eval-when . ,(lambda (&rest args) `(progn . ,(cdr args)))) |
435 |
(eval-when-compile . ,(lambda (&rest args) `(progn . ,args))) |
436 |
(eval-and-compile . ,(lambda (&rest args) `(progn . ,args)))) |
437 |
"Environment to use while tentatively expanding macros. |
438 |
This is used to try and avoid the most egregious problems linked to the |
439 |
use of `macroexpand-all' as a way to find the \"underlying raw code\".") |
440 |
|
441 |
(defvar elisp--macroexpand-untrusted-warning t) |
442 |
|
443 |
(defun elisp--safe-macroexpand-all (sexp) |
444 |
(if (not (trusted-content-p)) |
445 |
;; FIXME: We should try and do better here, either using a notion |
446 |
;; of "safe" macros, or with `bwrap', or ... |
447 |
(progn |
448 |
(when elisp--macroexpand-untrusted-warning |
449 |
(setq-local elisp--macroexpand-untrusted-warning nil) ;Don't spam! |
450 |
(let ((inhibit-message t)) ;Only log. |
451 |
(message "Completion of local vars is disabled in %s (untrusted content)" |
452 |
(buffer-name)))) |
453 |
sexp) |
454 |
(let ((macroexpand-advice |
455 |
(lambda (expander form &rest args) |
456 |
(condition-case err |
457 |
(apply expander form args) |
458 |
(error |
459 |
(message "Ignoring macroexpansion error: %S" err) form))))) |
460 |
(unwind-protect |
461 |
;; Silence any macro expansion errors when |
462 |
;; attempting completion at point (bug#58148). |
463 |
(let ((inhibit-message t) |
464 |
(macroexp-inhibit-compiler-macros t) |
465 |
(warning-minimum-log-level :emergency)) |
466 |
(advice-add 'macroexpand-1 :around macroexpand-advice) |
467 |
(macroexpand-all sexp elisp--local-macroenv)) |
468 |
(advice-remove 'macroexpand-1 macroexpand-advice))))) |
469 |
|
433 |
(defun elisp--local-variables () |
470 |
(defun elisp--local-variables () |
434 |
"Return a list of locally let-bound variables at point." |
471 |
"Return a list of locally let-bound variables at point." |
435 |
(save-excursion |
472 |
(save-excursion |
Lines 445-466
Link Here
|
445 |
(car (read-from-string |
482 |
(car (read-from-string |
446 |
(concat txt "elisp--witness--lisp" closer))) |
483 |
(concat txt "elisp--witness--lisp" closer))) |
447 |
((invalid-read-syntax end-of-file) nil))) |
484 |
((invalid-read-syntax end-of-file) nil))) |
448 |
(macroexpand-advice (lambda (expander form &rest args) |
485 |
(vars (elisp--local-variables-1 |
449 |
(condition-case nil |
486 |
nil (elisp--safe-macroexpand-all sexp)))) |
450 |
(apply expander form args) |
|
|
451 |
(error form)))) |
452 |
(sexp |
453 |
(unwind-protect |
454 |
;; Silence any macro expansion errors when |
455 |
;; attempting completion at point (bug#58148). |
456 |
(let ((inhibit-message t) |
457 |
(warning-minimum-log-level :emergency)) |
458 |
(advice-add 'macroexpand :around macroexpand-advice) |
459 |
(condition-case nil |
460 |
(macroexpand-all sexp) |
461 |
(error sexp))) |
462 |
(advice-remove 'macroexpand macroexpand-advice))) |
463 |
(vars (elisp--local-variables-1 nil sexp))) |
464 |
(delq nil |
487 |
(delq nil |
465 |
(mapcar (lambda (var) |
488 |
(mapcar (lambda (var) |
466 |
(and (symbolp var) |
489 |
(and (symbolp var) |
Lines 2164-2169
Link Here
|
2164 |
"A Flymake backend for elisp byte compilation. |
2187 |
"A Flymake backend for elisp byte compilation. |
2165 |
Spawn an Emacs process that byte-compiles a file representing the |
2188 |
Spawn an Emacs process that byte-compiles a file representing the |
2166 |
current buffer state and calls REPORT-FN when done." |
2189 |
current buffer state and calls REPORT-FN when done." |
|
|
2190 |
(unless (trusted-content-p) |
2191 |
;; FIXME: Use `bwrap' and friends to compile untrusted content. |
2192 |
;; FIXME: We emit a message *and* signal an error, because by default |
2193 |
;; Flymake doesn't display the warning it puts into "*flmake log*". |
2194 |
(message "Disabling elisp-flymake-byte-compile in %s (untrusted content)" |
2195 |
(buffer-name)) |
2196 |
(user-error "Disabling elisp-flymake-byte-compile in %s (untrusted content)" |
2197 |
(buffer-name))) |
2167 |
(when elisp-flymake--byte-compile-process |
2198 |
(when elisp-flymake--byte-compile-process |
2168 |
(when (process-live-p elisp-flymake--byte-compile-process) |
2199 |
(when (process-live-p elisp-flymake--byte-compile-process) |
2169 |
(kill-process elisp-flymake--byte-compile-process))) |
2200 |
(kill-process elisp-flymake--byte-compile-process))) |
2170 |
-- emacs-29.4/lisp/simple.el |
2201 |
++ emacs-29.4/lisp/simple.el |
Lines 2029-2034
Link Here
|
2029 |
(set-syntax-table emacs-lisp-mode-syntax-table) |
2029 |
(set-syntax-table emacs-lisp-mode-syntax-table) |
2030 |
(add-hook 'completion-at-point-functions |
2030 |
(add-hook 'completion-at-point-functions |
2031 |
#'elisp-completion-at-point nil t) |
2031 |
#'elisp-completion-at-point nil t) |
|
|
2032 |
(setq-local trusted-content :all) |
2032 |
(run-hooks 'eval-expression-minibuffer-setup-hook)) |
2033 |
(run-hooks 'eval-expression-minibuffer-setup-hook)) |
2033 |
(read-from-minibuffer prompt initial-contents |
2034 |
(read-from-minibuffer prompt initial-contents |
2034 |
read--expression-map t |
2035 |
read--expression-map t |
Lines 10853-10859
Link Here
|
10853 |
(when initial-scratch-message |
10854 |
(when initial-scratch-message |
10854 |
(insert (substitute-command-keys initial-scratch-message)) |
10855 |
(insert (substitute-command-keys initial-scratch-message)) |
10855 |
(set-buffer-modified-p nil)) |
10856 |
(set-buffer-modified-p nil)) |
10856 |
(funcall initial-major-mode)) |
10857 |
(funcall initial-major-mode) |
|
|
10858 |
(when (eq initial-major-mode 'lisp-interaction-mode) |
10859 |
(setq-local trusted-content :all))) |
10857 |
scratch))) |
10860 |
scratch))) |
10858 |
|
10861 |
|
10859 |
(defun scratch-buffer () |
10862 |
(defun scratch-buffer () |