Fix arbitrary code execution via Lisp macro expansion
Resolves: RHEL-69394
This commit is contained in:
parent
f90f68c9f9
commit
2db5d6b832
242
emacs-CVE-2024-53920.patch
Normal file
242
emacs-CVE-2024-53920.patch
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
---
|
||||||
|
emacs-27.2/doc/emacs/misc.texi | 33 +++++++++++++++++
|
||||||
|
emacs-27.2/lisp/emacs-lisp/macroexp.el | 10 ++++-
|
||||||
|
emacs-27.2/lisp/files.el | 60 +++++++++++++++++++++++++++++---
|
||||||
|
emacs-27.2/lisp/ielm.el | 3 +
|
||||||
|
emacs-27.2/lisp/progmodes/elisp-mode.el | 58 +++++++++++++++++++++++++-----
|
||||||
|
emacs-27.2/lisp/simple.el | 1
|
||||||
|
6 files changed, 189 insertions(+), 20 deletions(-)
|
||||||
|
|
||||||
|
--- emacs-27.2/doc/emacs/misc.texi
|
||||||
|
+++ emacs-27.2/doc/emacs/misc.texi 2025-03-03 09:18:41.368169799 +0000
|
||||||
|
@@ -279,6 +279,39 @@ trusted and the default checking for the
|
||||||
|
you can set @code{enable-local-variables} to @code{:all}. @xref{Safe
|
||||||
|
File Variables}.
|
||||||
|
|
||||||
|
+@cindex trusted files and directories
|
||||||
|
+Loading a file of Emacs Lisp code with @code{load-file} or
|
||||||
|
+@code{load-library} (@pxref{Lisp Libraries}) can execute some of the
|
||||||
|
+Lisp code in the file being loaded, so you should only load Lisp files
|
||||||
|
+whose source you trust. However, some Emacs features can in certain
|
||||||
|
+situations execute Lisp code even without your explicit command or
|
||||||
|
+request. For example, Flymake, the on-the-fly syntax checker for Emacs
|
||||||
|
+(@pxref{Top,,, flymake, GNU Flymake}), if it is enabled, can
|
||||||
|
+automatically execute some of the code in a Lisp file you visit as part
|
||||||
|
+of its syntax-checking job. Similarly, some completion commands
|
||||||
|
+(@pxref{Completion}) in buffers visiting Lisp files sometimes need to
|
||||||
|
+expand Lisp macros for best results. In these cases, just visiting a
|
||||||
|
+Lisp file and performing some editing in it could trigger execution of
|
||||||
|
+Lisp code. If the visited file came from an untrusted source, it could
|
||||||
|
+include dangerous or even malicious code that Emacs would execute in
|
||||||
|
+those situations.
|
||||||
|
+
|
||||||
|
+To protect against this, Emacs disables execution of Lisp code by
|
||||||
|
+Flymake, completion, and some other features, unless the visited file is
|
||||||
|
+@dfn{trusted}. It is up to you to specify which files on your system
|
||||||
|
+should be trusted, by customizing the user option
|
||||||
|
+@code{trusted-content}.
|
||||||
|
+
|
||||||
|
+@defopt trusted-content
|
||||||
|
+The value of this option is @code{nil} by default, which means no file
|
||||||
|
+is trusted. You can customize the variable to be a list of one or more
|
||||||
|
+names of trusted files and directories. A file name that ends in a
|
||||||
|
+slash @file{/} is interpreted as a directory, which means all its files
|
||||||
|
+and subdirectories are also trusted. A special value @code{:all} means
|
||||||
|
+@emph{all} the files and directories on your system should be trusted;
|
||||||
|
+@strong{this is not recommended}, as it opens a gaping security hole.
|
||||||
|
+@end defopt
|
||||||
|
+
|
||||||
|
@xref{Security Considerations,,, elisp, The Emacs Lisp Reference
|
||||||
|
Manual}, for more information about security considerations when using
|
||||||
|
Emacs as part of a larger application.
|
||||||
|
--- emacs-27.2/lisp/emacs-lisp/macroexp.el
|
||||||
|
+++ emacs-27.2/lisp/emacs-lisp/macroexp.el 2025-03-03 09:18:41.368169799 +0000
|
||||||
|
@@ -94,12 +94,20 @@ each clause."
|
||||||
|
(macroexp--all-forms clause skip)
|
||||||
|
clause)))
|
||||||
|
|
||||||
|
+(defvar macroexp-inhibit-compiler-macros nil
|
||||||
|
+ "Inhibit application of compiler macros if non-nil.")
|
||||||
|
+
|
||||||
|
(defun macroexp--compiler-macro (handler form)
|
||||||
|
+ "Apply compiler macro HANDLER to FORM and return the result.
|
||||||
|
+Unless `macroexp-inhibit-compiler-macros' is non-nil, in which
|
||||||
|
+case return FORM unchanged."
|
||||||
|
+ (if macroexp-inhibit-compiler-macros
|
||||||
|
+ form
|
||||||
|
(condition-case err
|
||||||
|
(apply handler form (cdr form))
|
||||||
|
(error
|
||||||
|
(message "Compiler-macro error for %S: %S" (car form) err)
|
||||||
|
- form)))
|
||||||
|
+ form))))
|
||||||
|
|
||||||
|
(defun macroexp--funcall-if-compiled (_form)
|
||||||
|
"Pseudo function used internally by macroexp to delay warnings.
|
||||||
|
--- emacs-27.2/lisp/files.el
|
||||||
|
+++ emacs-27.2/lisp/files.el 2025-03-03 09:20:04.078645249 +0000
|
||||||
|
@@ -591,10 +596,57 @@ buffer contents as untrusted.
|
||||||
|
(other :tag "Query" other))
|
||||||
|
:group 'find-file)
|
||||||
|
|
||||||
|
-(defvar enable-dir-local-variables t
|
||||||
|
- "Non-nil means enable use of directory-local variables.
|
||||||
|
-Some modes may wish to set this to nil to prevent directory-local
|
||||||
|
-settings being applied, but still respect file-local ones.")
|
||||||
|
+(defcustom trusted-content nil
|
||||||
|
+ "List of files and directories whose content we trust.
|
||||||
|
+Be extra careful here since trusting means that Emacs might execute the
|
||||||
|
+code contained within those files and directories without an explicit
|
||||||
|
+request by the user.
|
||||||
|
+One important case when this might happen is when `flymake-mode' is
|
||||||
|
+enabled (for example, when it is added to a mode hook).
|
||||||
|
+Each element of the list should be a string:
|
||||||
|
+- If it ends in \"/\", it is considered as a directory name and means that
|
||||||
|
+ Emacs should trust all the files whose name has this directory as a prefix.
|
||||||
|
+- Otherwise, it is considered a file name.
|
||||||
|
+Use abbreviated file names. For example, an entry \"~/mycode/\" means
|
||||||
|
+that Emacs will trust all the files in your directory \"mycode\".
|
||||||
|
+This variable can also be set to `:all', in which case Emacs will trust
|
||||||
|
+all files, which opens a gaping security hole. Emacs Lisp authors
|
||||||
|
+should note that this value must never be set by a major or minor mode."
|
||||||
|
+ :type '(choice (repeat :tag "List" file)
|
||||||
|
+ (const :tag "Trust everything (DANGEROUS!)" :all))
|
||||||
|
+ :version "27.2")
|
||||||
|
+(put 'trusted-content 'risky-local-variable t)
|
||||||
|
+
|
||||||
|
+(defun trusted-content-p ()
|
||||||
|
+ "Return non-nil if we trust the contents of the current buffer.
|
||||||
|
+Here, \"trust\" means that we are willing to run code found inside of it.
|
||||||
|
+See also `trusted-content'."
|
||||||
|
+ ;; We compare with `buffer-file-truename' i.s.o `buffer-file-name'
|
||||||
|
+ ;; to try and avoid marking as trusted a file that's merely accessed
|
||||||
|
+ ;; via a symlink that happens to be inside a trusted dir.
|
||||||
|
+ (and (not untrusted-content)
|
||||||
|
+ (or
|
||||||
|
+ (eq trusted-content :all)
|
||||||
|
+ (and
|
||||||
|
+ buffer-file-truename
|
||||||
|
+ (with-demoted-errors "trusted-content-p: %S"
|
||||||
|
+ (let ((exists (file-exists-p buffer-file-truename)))
|
||||||
|
+ (or
|
||||||
|
+ ;; We can't avoid trusting the user's init file.
|
||||||
|
+ (if (and exists user-init-file)
|
||||||
|
+ (file-equal-p buffer-file-truename user-init-file)
|
||||||
|
+ (equal buffer-file-truename user-init-file))
|
||||||
|
+ (let ((file (abbreviate-file-name buffer-file-truename))
|
||||||
|
+ (trusted nil))
|
||||||
|
+ (dolist (tf trusted-content)
|
||||||
|
+ (when (or (if exists (file-equal-p tf file) (equal tf file))
|
||||||
|
+ ;; We don't use `file-in-directory-p' here, because
|
||||||
|
+ ;; we want to err on the conservative side: "guilty
|
||||||
|
+ ;; until proven innocent".
|
||||||
|
+ (and (string-suffix-p "/" tf)
|
||||||
|
+ (string-prefix-p tf file)))
|
||||||
|
+ (setq trusted t)))
|
||||||
|
+ trusted))))))))
|
||||||
|
|
||||||
|
;; This is an odd variable IMO.
|
||||||
|
;; You might wonder why it is needed, when we could just do:
|
||||||
|
--- emacs-27.2/lisp/ielm.el
|
||||||
|
+++ emacs-27.2/lisp/ielm.el 2025-03-03 09:18:41.372169725 +0000
|
||||||
|
@@ -616,7 +616,8 @@ See `inferior-emacs-lisp-mode' for detai
|
||||||
|
(unless (comint-check-proc "*ielm*")
|
||||||
|
(with-current-buffer (get-buffer-create "*ielm*")
|
||||||
|
(unless (zerop (buffer-size)) (setq old-point (point)))
|
||||||
|
- (inferior-emacs-lisp-mode)))
|
||||||
|
+ (inferior-emacs-lisp-mode)
|
||||||
|
+ (setq-local trusted-content :all)))
|
||||||
|
(pop-to-buffer-same-window "*ielm*")
|
||||||
|
(when old-point (push-mark old-point))))
|
||||||
|
|
||||||
|
--- emacs-27.2/lisp/progmodes/elisp-mode.el
|
||||||
|
+++ emacs-27.2/lisp/progmodes/elisp-mode.el 2025-03-03 09:18:41.372169725 +0000
|
||||||
|
@@ -333,6 +333,43 @@ Blank lines separate paragraphs. Semico
|
||||||
|
|
||||||
|
(defvar warning-minimum-log-level)
|
||||||
|
|
||||||
|
+(defvar elisp--local-macroenv
|
||||||
|
+ `((cl-eval-when . ,(lambda (&rest args) `(progn . ,(cdr args))))
|
||||||
|
+ (eval-when-compile . ,(lambda (&rest args) `(progn . ,args)))
|
||||||
|
+ (eval-and-compile . ,(lambda (&rest args) `(progn . ,args))))
|
||||||
|
+ "Environment to use while tentatively expanding macros.
|
||||||
|
+This is used to try and avoid the most egregious problems linked to the
|
||||||
|
+use of `macroexpand-all' as a way to find the \"underlying raw code\".")
|
||||||
|
+
|
||||||
|
+(defvar elisp--macroexpand-untrusted-warning t)
|
||||||
|
+
|
||||||
|
+(defun elisp--safe-macroexpand-all (sexp)
|
||||||
|
+ (if (not (trusted-content-p))
|
||||||
|
+ ;; FIXME: We should try and do better here, either using a notion
|
||||||
|
+ ;; of "safe" macros, or with `bwrap', or ...
|
||||||
|
+ (progn
|
||||||
|
+ (when elisp--macroexpand-untrusted-warning
|
||||||
|
+ (setq-local elisp--macroexpand-untrusted-warning nil) ;Don't spam!
|
||||||
|
+ (let ((inhibit-message t)) ;Only log.
|
||||||
|
+ (message "Completion of local vars is disabled in %s (untrusted content)"
|
||||||
|
+ (buffer-name))))
|
||||||
|
+ sexp)
|
||||||
|
+ (let ((macroexpand-advice
|
||||||
|
+ (lambda (expander form &rest args)
|
||||||
|
+ (condition-case err
|
||||||
|
+ (apply expander form args)
|
||||||
|
+ (error
|
||||||
|
+ (message "Ignoring macroexpansion error: %S" err) form)))))
|
||||||
|
+ (unwind-protect
|
||||||
|
+ ;; Silence any macro expansion errors when
|
||||||
|
+ ;; attempting completion at point (bug#58148).
|
||||||
|
+ (let ((inhibit-message t)
|
||||||
|
+ (macroexp-inhibit-compiler-macros t)
|
||||||
|
+ (warning-minimum-log-level :emergency))
|
||||||
|
+ (advice-add 'macroexpand-1 :around macroexpand-advice)
|
||||||
|
+ (macroexpand-all sexp elisp--local-macroenv))
|
||||||
|
+ (advice-remove 'macroexpand-1 macroexpand-advice)))))
|
||||||
|
+
|
||||||
|
(defun elisp--local-variables ()
|
||||||
|
"Return a list of locally let-bound variables at point."
|
||||||
|
(save-excursion
|
||||||
|
@@ -348,17 +385,8 @@ Blank lines separate paragraphs. Semico
|
||||||
|
(car (read-from-string
|
||||||
|
(concat txt "elisp--witness--lisp" closer)))
|
||||||
|
((invalid-read-syntax end-of-file) nil)))
|
||||||
|
- (macroexpand-advice (lambda (expander form &rest args)
|
||||||
|
- (condition-case nil
|
||||||
|
- (apply expander form args)
|
||||||
|
- (error form))))
|
||||||
|
- (sexp
|
||||||
|
- (unwind-protect
|
||||||
|
- (let ((warning-minimum-log-level :emergency))
|
||||||
|
- (advice-add 'macroexpand :around macroexpand-advice)
|
||||||
|
- (macroexpand-all sexp))
|
||||||
|
- (advice-remove 'macroexpand macroexpand-advice)))
|
||||||
|
- (vars (elisp--local-variables-1 nil sexp)))
|
||||||
|
+ (vars (elisp--local-variables-1
|
||||||
|
+ nil (elisp--safe-macroexpand-all sexp))))
|
||||||
|
(delq nil
|
||||||
|
(mapcar (lambda (var)
|
||||||
|
(and (symbolp var)
|
||||||
|
@@ -1721,6 +1749,14 @@ directory of the buffer being compiled,
|
||||||
|
"A Flymake backend for elisp byte compilation.
|
||||||
|
Spawn an Emacs process that byte-compiles a file representing the
|
||||||
|
current buffer state and calls REPORT-FN when done."
|
||||||
|
+ (unless (trusted-content-p)
|
||||||
|
+ ;; FIXME: Use `bwrap' and friends to compile untrusted content.
|
||||||
|
+ ;; FIXME: We emit a message *and* signal an error, because by default
|
||||||
|
+ ;; Flymake doesn't display the warning it puts into "*flmake log*".
|
||||||
|
+ (message "Disabling elisp-flymake-byte-compile in %s (untrusted content)"
|
||||||
|
+ (buffer-name))
|
||||||
|
+ (error "Disabling elisp-flymake-byte-compile in %s (untrusted content)"
|
||||||
|
+ (buffer-name)))
|
||||||
|
(when elisp-flymake--byte-compile-process
|
||||||
|
(when (process-live-p elisp-flymake--byte-compile-process)
|
||||||
|
(kill-process elisp-flymake--byte-compile-process)))
|
||||||
|
--- emacs-27.2/lisp/simple.el
|
||||||
|
+++ emacs-27.2/lisp/simple.el 2025-03-03 09:18:41.372169725 +0000
|
||||||
|
@@ -1621,6 +1621,7 @@ display the result of expression evaluat
|
||||||
|
(eldoc-mode 1)
|
||||||
|
(add-hook 'completion-at-point-functions
|
||||||
|
#'elisp-completion-at-point nil t)
|
||||||
|
+ (setq-local trusted-content :all)
|
||||||
|
(run-hooks 'eval-expression-minibuffer-setup-hook))
|
||||||
|
(read-from-minibuffer prompt initial-contents
|
||||||
|
read-expression-map t
|
@ -5,7 +5,7 @@ Summary: GNU Emacs text editor
|
|||||||
Name: emacs
|
Name: emacs
|
||||||
Epoch: 1
|
Epoch: 1
|
||||||
Version: 26.1
|
Version: 26.1
|
||||||
Release: 13%{?dist}
|
Release: 14%{?dist}
|
||||||
License: GPLv3+ and CC0-1.0
|
License: GPLv3+ and CC0-1.0
|
||||||
URL: http://www.gnu.org/software/emacs/
|
URL: http://www.gnu.org/software/emacs/
|
||||||
Group: Applications/Editors
|
Group: Applications/Editors
|
||||||
@ -33,6 +33,7 @@ Patch8: emacs-consider-org-file-contents-unsafe.patch
|
|||||||
Patch9: emacs-org-link-expand-abbrev-unsafe-elisp.patch
|
Patch9: emacs-org-link-expand-abbrev-unsafe-elisp.patch
|
||||||
Patch10: emacs-mark-contents-untrusted.patch
|
Patch10: emacs-mark-contents-untrusted.patch
|
||||||
Patch11: emacs-man-el-shell-injection-vulnerability.patch
|
Patch11: emacs-man-el-shell-injection-vulnerability.patch
|
||||||
|
Patch12: emacs-CVE-2024-53920.patch
|
||||||
|
|
||||||
BuildRequires: atk-devel
|
BuildRequires: atk-devel
|
||||||
BuildRequires: cairo-devel
|
BuildRequires: cairo-devel
|
||||||
@ -195,6 +196,7 @@ packages that add functionality to Emacs.
|
|||||||
%patch9 -p1 -b .org-link-expand-abbrev-unsafe-elisp
|
%patch9 -p1 -b .org-link-expand-abbrev-unsafe-elisp
|
||||||
%patch10 -p1 -b .mark-contents-untrusted
|
%patch10 -p1 -b .mark-contents-untrusted
|
||||||
%patch11 -p1 -b .emacs-man-el-shell-injection-vulnerability
|
%patch11 -p1 -b .emacs-man-el-shell-injection-vulnerability
|
||||||
|
%patch12 -p1 -b .CVE-2024-53920
|
||||||
autoconf
|
autoconf
|
||||||
|
|
||||||
# We prefer our emacs.desktop file
|
# We prefer our emacs.desktop file
|
||||||
@ -481,6 +483,9 @@ fi
|
|||||||
%dir %{_datadir}/emacs/site-lisp/site-start.d
|
%dir %{_datadir}/emacs/site-lisp/site-start.d
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon May 05 2025 Jacek Migacz <jmigacz@redhat.com> - 1:26.1-14
|
||||||
|
- Fix arbitrary code execution via Lisp macro expansion (RHEL-69394)
|
||||||
|
|
||||||
* Wed Feb 19 2025 Jacek Migacz <jmigacz@redhat.com> - 1:26.1-13
|
* Wed Feb 19 2025 Jacek Migacz <jmigacz@redhat.com> - 1:26.1-13
|
||||||
- Fix man.el shell injection vulnerability (RHEL-79016)
|
- Fix man.el shell injection vulnerability (RHEL-79016)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user