mirror of
https://github.com/doomemacs/doomemacs
synced 2025-08-01 12:17:25 -05:00
fix(syntax): disable checker in non-project elisp files
CVE-2024-53920 describes an arbitrary code execution vulnerability during macro expansion, which occurs during byte-compilation or when evaluating macro calls in uncompiled elisp files. Flycheck and flymake use byte-compilation to lint elisp files, exposing users to this vulnerability. This commit attempts to protect users from this by disabling both in elisp files that aren't part of a project (because, presumably, untrusted elisp won't live in a project). What a "project" is depends on your projectile settings, but generally means a file that lives in a version controlled directory and/or a directory containing a recognizable project root marker (like a packages.json or Cargo.toml file). This heuristic won't catch cases of untrusted elisp living within legitimate projects, or the case where the user's $HOME is a project and *all* their elisp files live under it, but there are already too many ways to shoot yourself in the foot with Emacs to begin with, and disabling fly(check|make) altogether stands a higher chance of making people blindly re-enable them to "work around" the fact it's not "working as expected", bringing them back to square one. Anyhow, long story short, don't open elisp files you don't trust in Emacs, mkay? Ref: CVE-2024-53920
This commit is contained in:
@ -23,6 +23,20 @@
|
||||
;; Display errors a little quicker (default is 0.9s)
|
||||
(setq flycheck-display-errors-delay 0.25)
|
||||
|
||||
;; HACK: Protect against eager expansion of `setf'. The gv setter won't be
|
||||
;; available until after `flycheck' loads, but macro expand occurs when this
|
||||
;; file is loaded.
|
||||
(eval '(setf (flycheck-checker-get 'emacs-lisp 'predicate)
|
||||
(lambda ()
|
||||
(and
|
||||
;; Do not check buffers that ask not to be byte-compiled.
|
||||
(not (bound-and-true-p no-byte-compile))
|
||||
;; Disable the emacs-lisp checker in non-project (likely
|
||||
;; untrusted) buffers to mitigate potential code execution
|
||||
;; vulnerability during macro expansion. See CVE-2024-53920.
|
||||
(doom-project-p))))
|
||||
t)
|
||||
|
||||
;; Don't commandeer input focus if the error message pops up (happens when
|
||||
;; tooltips and childframes are disabled).
|
||||
(set-popup-rules!
|
||||
@ -111,7 +125,15 @@
|
||||
:when (modulep! +flymake)
|
||||
:hook ((prog-mode text-mode) . flymake-mode)
|
||||
:config
|
||||
(setq flymake-fringe-indicator-position 'right-fringe))
|
||||
(setq flymake-fringe-indicator-position 'right-fringe)
|
||||
|
||||
;; HACK: Disable the emacs-lisp checker in non-project (likely untrusted)
|
||||
;; buffers to mitigate potential code execution vulnerability during macro
|
||||
;; expansion. See CVE-2024-53920.
|
||||
(defadvice! +syntax--only-check-elisp-buffers-in-projects-a (fn &rest args)
|
||||
"Prevent the elisp checker in non-project buffers (for CVE-2024-53920)."
|
||||
:before-while #'elisp-flymake-byte-compile
|
||||
(doom-project-p)))
|
||||
|
||||
|
||||
(use-package! flymake-popon
|
||||
|
@ -306,55 +306,56 @@ are set by `+emacs-lisp-linter-warnings'
|
||||
|
||||
This backend does not need to be added directly
|
||||
as `+emacs-lisp-non-package-mode' will enable it and disable the other checkers."
|
||||
;; if a process already exists. kill it.
|
||||
(when (and +emacs-lisp-reduced-flymake-byte-compile--process
|
||||
(process-live-p +emacs-lisp-reduced-flymake-byte-compile--process))
|
||||
(kill-process +emacs-lisp-reduced-flymake-byte-compile--process))
|
||||
(let ((source (current-buffer))
|
||||
(tmp-file (make-temp-file "+emacs-lisp-byte-compile-src"))
|
||||
(out-buf (generate-new-buffer "+emacs-lisp-byte-compile-out")))
|
||||
;; write the content to a temp file
|
||||
(save-restriction
|
||||
(widen)
|
||||
(write-region nil nil tmp-file nil 'nomessage))
|
||||
;; make the process
|
||||
(setq +emacs-lisp-reduced-flymake-byte-compile--process
|
||||
(make-process
|
||||
:name "+emacs-reduced-flymake"
|
||||
:noquery t
|
||||
:connection-type 'pipe
|
||||
:buffer out-buf
|
||||
:command `(,(expand-file-name invocation-name invocation-directory)
|
||||
"-Q"
|
||||
"--batch"
|
||||
,@(mapcan (lambda (p) (list "-L" p)) elisp-flymake-byte-compile-load-path)
|
||||
;; this is what silences the byte compiler
|
||||
"--eval" ,(prin1-to-string `(setq doom-modules ',doom-modules
|
||||
doom-disabled-packages ',doom-disabled-packages
|
||||
byte-compile-warnings ',+emacs-lisp-linter-warnings))
|
||||
"-f" "elisp-flymake--batch-compile-for-flymake"
|
||||
,tmp-file)
|
||||
:stderr "*stderr of +elisp-flymake-byte-compile-out*"
|
||||
:sentinel
|
||||
;; deal with the process when it exits
|
||||
(lambda (proc _event)
|
||||
(when (memq (process-status proc) '(exit signal))
|
||||
(unwind-protect
|
||||
(cond
|
||||
;; if the buffer is dead or the process is not the same, log the process as old.
|
||||
((or (not (buffer-live-p source))
|
||||
(not (with-current-buffer source (eq proc +emacs-lisp-reduced-flymake-byte-compile--process))))
|
||||
(flymake-log :warning "byte compile process %s is old" proc))
|
||||
;; if the process exited without problem process the buffer
|
||||
((zerop (process-exit-status proc))
|
||||
(elisp-flymake--byte-compile-done report-fn source out-buf))
|
||||
;; otherwise something else horrid has gone wrong and we panic
|
||||
(t (funcall report-fn :panic
|
||||
:explanation
|
||||
(format "byte compile process %s died" proc))))
|
||||
;; cleanup
|
||||
(ignore-errors (delete-file tmp-file))
|
||||
(kill-buffer out-buf))))))))
|
||||
(when (doom-project-p)
|
||||
;; if a process already exists. kill it.
|
||||
(when (and +emacs-lisp-reduced-flymake-byte-compile--process
|
||||
(process-live-p +emacs-lisp-reduced-flymake-byte-compile--process))
|
||||
(kill-process +emacs-lisp-reduced-flymake-byte-compile--process))
|
||||
(let ((source (current-buffer))
|
||||
(tmp-file (make-temp-file "+emacs-lisp-byte-compile-src"))
|
||||
(out-buf (generate-new-buffer "+emacs-lisp-byte-compile-out")))
|
||||
;; write the content to a temp file
|
||||
(save-restriction
|
||||
(widen)
|
||||
(write-region nil nil tmp-file nil 'nomessage))
|
||||
;; make the process
|
||||
(setq +emacs-lisp-reduced-flymake-byte-compile--process
|
||||
(make-process
|
||||
:name "+emacs-reduced-flymake"
|
||||
:noquery t
|
||||
:connection-type 'pipe
|
||||
:buffer out-buf
|
||||
:command `(,(expand-file-name invocation-name invocation-directory)
|
||||
"-Q"
|
||||
"--batch"
|
||||
,@(mapcan (lambda (p) (list "-L" p)) elisp-flymake-byte-compile-load-path)
|
||||
;; this is what silences the byte compiler
|
||||
"--eval" ,(prin1-to-string `(setq doom-modules ',doom-modules
|
||||
doom-disabled-packages ',doom-disabled-packages
|
||||
byte-compile-warnings ',+emacs-lisp-linter-warnings))
|
||||
"-f" "elisp-flymake--batch-compile-for-flymake"
|
||||
,tmp-file)
|
||||
:stderr "*stderr of +elisp-flymake-byte-compile-out*"
|
||||
:sentinel
|
||||
;; deal with the process when it exits
|
||||
(lambda (proc _event)
|
||||
(when (memq (process-status proc) '(exit signal))
|
||||
(unwind-protect
|
||||
(cond
|
||||
;; if the buffer is dead or the process is not the same, log the process as old.
|
||||
((or (not (buffer-live-p source))
|
||||
(not (with-current-buffer source (eq proc +emacs-lisp-reduced-flymake-byte-compile--process))))
|
||||
(flymake-log :warning "byte compile process %s is old" proc))
|
||||
;; if the process exited without problem process the buffer
|
||||
((zerop (process-exit-status proc))
|
||||
(elisp-flymake--byte-compile-done report-fn source out-buf))
|
||||
;; otherwise something else horrid has gone wrong and we panic
|
||||
(t (funcall report-fn :panic
|
||||
:explanation
|
||||
(format "byte compile process %s died" proc))))
|
||||
;; cleanup
|
||||
(ignore-errors (delete-file tmp-file))
|
||||
(kill-buffer out-buf)))))))))
|
||||
|
||||
(define-minor-mode +emacs-lisp--flymake-non-package-mode
|
||||
""
|
||||
|
Reference in New Issue
Block a user