File emacs-CVE-2024-53920.patch of Package emacs.37736

---
 emacs-27.2/doc/emacs/misc.texi          |   33 +++++++++++++++++
 emacs-27.2/doc/misc/efaq.texi           |    7 +++
 emacs-27.2/etc/NEWS                     |   23 ++++++++++++
 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 
 emacs-27.2/lisp/startup.el              |   14 +++++--
 9 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/doc/misc/efaq.texi
+++ emacs-27.2/doc/misc/efaq.texi	2025-03-03 09:18:41.368169799 +0000
@@ -1001,6 +1001,13 @@ Native support for @acronym{JSON} parsin
 @file{json.el}.
 
 @item
+New user option @code{trusted-contents} to allow potentially dangerous
+Emacs features which could execute arbitrary Lisp code.  Use this
+variable to list files and directories whose contents Emacs should
+trust, thus allowing those potentially dangerous features when those
+files are visited.
+
+@item
 Cairo drawing is no longer experimental.
 
 @cindex portable dumper
--- emacs-27.2/etc/NEWS
+++ emacs-27.2/etc/NEWS	2025-03-03 09:18:41.368169799 +0000
@@ -15,6 +15,29 @@ in older Emacs versions.
 You can narrow news to a specific version by calling 'view-emacs-news'
 with a prefix argument or by typing 'C-u C-h C-n'.
 
+* Changes for CVE-2024-53920
+ 
+** New user option 'trusted-content' to allow potentially dangerous features.
+This variable lists those files and directories whose content Emacs should
+consider as sufficiently trusted to run any part of the code contained
+therein even without any explicit user request.
+For example, Flymake's backend for Emacs Lisp consults this variable
+and disables itself with an "untrusted content" warning if the file
+is not listed.
+
+Emacs Lisp authors should note that a major or minor mode must never set
+this variable to the ':all' value.
+
+This option is used to fix CVE-2024-53920.  See below for details.
+
+** Emacs Lisp mode
+ 
+*** 'elisp-flymake-byte-compile' is disabled for untrusted files.
+For security reasons, this backend can be used only in those files
+specified as trusted according to 'trusted-content' and emits an
+"untrusted content" warning otherwise.
+This fixes CVE-2024-53920.
+
 
 * Changes in Emacs 27.2
 
--- 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-unless-debug 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
@@ -583,6 +583,11 @@ and ignores this variable."
 		 (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.")
+
 (defvar-local untrusted-content nil
   "Non-nil means that current buffer originated from an untrusted source.
 Email clients and some other modes may set this non-nil to mark the
@@ -591,10 +596,57 @@ buffer contents as untrusted.
 This variable might be subject to change without notice.")
 (put 'untrusted-content 'permanent-local t)
 
-(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 buf-name)
       (with-current-buffer (get-buffer-create buf-name)
         (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 buf-name)
     (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--eval-expression-setup')?
           (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
--- emacs-27.2/lisp/startup.el
+++ emacs-27.2/lisp/startup.el	2025-03-03 09:18:41.372169725 +0000
@@ -2316,9 +2316,17 @@ A fancy display is used on graphic displ
 
 (defun startup--get-buffer-create-scratch ()
   (or (get-buffer "*scratch*")
-      (with-current-buffer (get-buffer-create "*scratch*")
-        (set-buffer-major-mode (current-buffer))
-        (current-buffer))))
+      (let ((scratch (get-buffer-create "*scratch*")))
+        ;; Don't touch the buffer contents or mode unless we know that
+        ;; we just created it.
+        (with-current-buffer scratch
+          (when initial-scratch-message
+            (insert (substitute-command-keys initial-scratch-message))
+            (set-buffer-modified-p nil))
+          (funcall initial-major-mode)
+          (when (eq initial-major-mode 'lisp-interaction-mode)
+            (setq-local trusted-content :all)))
+        scratch)))
 
 (defun command-line-1 (args-left)
   "A subroutine of `command-line'."
openSUSE Build Service is sponsored by