diff --git a/SPECS/emacs/CVE-2026-79992.patch b/SPECS/emacs/CVE-2026-79992.patch new file mode 100644 index 00000000000..c84061e1ea3 --- /dev/null +++ b/SPECS/emacs/CVE-2026-79992.patch @@ -0,0 +1,282 @@ +From f39b1124616c17ff8eaf6330aa466b16c51e8eeb Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Sun, 30 Aug 2026 20:19:33 +0000 +Subject: [PATCH] Restrict Tramp user name + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://cgit.git.savannah.gnu.org/cgit/emacs.git/patch/?id=f3e7104d05bdb8e32ba13bf75604108ad88536dc + +--- + doc/misc/tramp.texi | 4 +++- + lisp/net/tramp-gvfs.el | 36 ++++++++++++++++++++---------------- + lisp/net/tramp-rclone.el | 4 ++-- + lisp/net/tramp-smb.el | 6 +++--- + lisp/net/tramp.el | 16 ++++++++++++---- + 5 files changed, 40 insertions(+), 26 deletions(-) + +diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi +index 0bed7db..4573218 100644 +--- a/doc/misc/tramp.texi ++++ b/doc/misc/tramp.texi +@@ -3420,7 +3420,9 @@ brackets @file{@value{ipv6prefix}} and @file{@value{ipv6postfix}}. + By default, @value{tramp} will use the current local user name as the + remote user name for log in to the remote host. Specifying a + different name using the proper syntax will override this default +-behavior: @file{@trampfn{method,user@@host,path/to/file}}. ++behavior: @file{@trampfn{method,user@@host,path/to/file}}. The user ++name can also be taken from an environment variable, like ++@file{@trampfn{method,@env{$MY_REMOTE_USER}@@host,path/to/file}}. + + @file{@trampfn{ssh,daniel@@melancholia,.emacs}} is for file + @file{.emacs} in @code{daniel}'s home directory on the host, +diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el +index 2ccba85..5081a81 100644 +--- a/lisp/net/tramp-gvfs.el ++++ b/lisp/net/tramp-gvfs.el +@@ -1202,7 +1202,7 @@ file names." + (tramp-compat-rx bos "/" (+ (not "/")) (group "/.." (? "/"))) + localname) + (setq localname (replace-match "/" t t localname 1))) +- (when (string-match (rx bol "/.." (? "/")) localname) ++ (when (string-match (rx bos "/.." (? "/")) localname) + (setq localname (replace-match "/" t t localname)))) + ;; There might be a double slash. Remove this. + (while (string-match "//" localname) +@@ -1296,9 +1296,9 @@ If FILE-SYSTEM is non-nil, return file system attributes." + (with-parsed-tramp-file-name filename nil + (setq localname (tramp-compat-file-name-unquote localname)) + (if (or (and (string-match-p +- (rx bol (| "afp" (: "dav" (? "s")) "smb") eol) method) ++ (rx bos (| "afp" (: "dav" (? "s")) "smb") eos) method) + (string-match-p +- (tramp-compat-rx bol (? "/") (+ (not "/")) eol) localname)) ++ (tramp-compat-rx bos (? "/") (+ (not "/")) eos) localname)) + (string-equal localname "/")) + (tramp-gvfs-get-root-attributes filename) + (assoc +@@ -1332,7 +1332,11 @@ If FILE-SYSTEM is non-nil, return file system attributes." + (lambda (x) + (unibyte-string (string-to-number (match-string 1 x) 16))) + res-symlink-target) +- 'utf-8))) ++ 'utf-8)) ++ ;; If the resulting localname looks remote, we must quote it ++ ;; for security reasons. ++ (when (tramp-tramp-file-p res-symlink-target) ++ (setq res-symlink-target (file-name-quote res-symlink-target 'top)))) + ;; ... number links + (setq res-numlinks + (string-to-number +@@ -1755,7 +1759,7 @@ ID-FORMAT valid values are `string' and `integer'." + "Retrieve file name from D-Bus OBJECT-PATH." + (dbus-unescape-from-identifier + (replace-regexp-in-string +- (tramp-compat-rx bol (* nonl) "/" (group (+ (not "/"))) eol) "\\1" ++ (tramp-compat-rx bos (* nonl) "/" (group (+ (not "/"))) eos) "\\1" + object-path))) + + (defun tramp-gvfs-url-host (url) +@@ -1763,7 +1767,7 @@ ID-FORMAT valid values are `string' and `integer'." + We cannot use `url-host', because `url-generic-parse-url' returns + a downcased host name only." + (and (stringp url) +- (string-match (rx bol (+ alnum) "://" (group (+ (not (any "/:"))))) url) ++ (string-match (rx bos (+ alnum) "://" (group (+ (not (any "/:"))))) url) + (match-string 1 url))) + + +@@ -1899,7 +1903,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" and + (cadr (assoc "ssl" (cadr mount-spec))))) + (uri (tramp-gvfs-dbus-byte-array-to-string + (cadr (assoc "uri" (cadr mount-spec)))))) +- (when (string-match (rx bol (group (| "afp" "smb"))) method) ++ (when (string-match (rx bos (group (| "afp" "smb"))) method) + (setq method (match-string 1 method))) + (when (and (string-equal "dav" method) (string-equal "true" ssl)) + (setq method "davs")) +@@ -1999,7 +2003,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" and + (or + (cadr (assoc "share" (cadr mount-spec))) + (cadr (assoc "volume" (cadr mount-spec))))))) +- (when (string-match (rx bol (group (| "afp" "smb"))) method) ++ (when (string-match (rx bos (group (| "afp" "smb"))) method) + (setq method (match-string 1 method))) + (when (and (string-equal "dav" method) (string-equal "true" ssl)) + (setq method "davs")) +@@ -2032,7 +2036,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" and + (string-equal host (tramp-file-name-host vec)) + (string-equal port (tramp-file-name-port vec)) + (string-match-p +- (tramp-compat-rx bol "/" (literal (or share ""))) ++ (tramp-compat-rx bos "/" (literal (or share ""))) + (tramp-file-name-unquote-localname vec))) + ;; Set mountpoint and location. + (tramp-set-file-property vec "/" "fuse-mountpoint" fuse-mountpoint) +@@ -2058,7 +2062,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" and + (defun tramp-gvfs-mount-spec-entry (key value) + "Construct a mount-spec entry to be used in a mount_spec. + It was \"a(say)\", but has changed to \"a{sv})\"." +- (if (string-match-p (rx bol "(aya{sv})") tramp-gvfs-mountlocation-signature) ++ (if (string-match-p (rx bos "(aya{sv})") tramp-gvfs-mountlocation-signature) + (list :dict-entry key + (list :variant (tramp-gvfs-dbus-string-to-byte-array value))) + (list :struct key (tramp-gvfs-dbus-string-to-byte-array value)))) +@@ -2077,10 +2081,10 @@ It was \"a(say)\", but has changed to \"a{sv})\"." + (tramp-media-device-port media) (tramp-file-name-port vec))) + (localname (tramp-file-name-unquote-localname vec)) + (share (when (string-match +- (tramp-compat-rx bol (? "/") (group (+ (not "/")))) ++ (tramp-compat-rx bos (? "/") (group (+ (not "/")))) + localname) + (match-string 1 localname))) +- (ssl (if (string-match-p (rx bol (| "davs" "nextcloud")) method) ++ (ssl (if (string-match-p (rx bos (| "davs" "nextcloud")) method) + "true" "false")) + (mount-spec + `(:array +@@ -2089,7 +2093,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"." + (list (tramp-gvfs-mount-spec-entry "type" "smb-share") + (tramp-gvfs-mount-spec-entry "server" host) + (tramp-gvfs-mount-spec-entry "share" share))) +- ((string-match-p (rx bol (| "davs" "nextcloud")) method) ++ ((string-match-p (rx bos (| "davs" "nextcloud")) method) + (list (tramp-gvfs-mount-spec-entry "type" "dav") + (tramp-gvfs-mount-spec-entry "host" host) + (tramp-gvfs-mount-spec-entry "ssl" ssl))) +@@ -2103,7 +2107,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"." + ((string-equal "nextcloud" method) + (list (tramp-gvfs-mount-spec-entry "type" "owncloud") + (tramp-gvfs-mount-spec-entry "host" host))) +- ((string-match-p (rx bol "http") method) ++ ((string-match-p (rx bos "http") method) + (list (tramp-gvfs-mount-spec-entry "type" "http") + (tramp-gvfs-mount-spec-entry + "uri" +@@ -2120,9 +2124,9 @@ It was \"a(say)\", but has changed to \"a{sv})\"." + ,@(when port + (list (tramp-gvfs-mount-spec-entry "port" port))))) + (mount-pref +- (if (and (string-match-p (rx bol "dav") method) ++ (if (and (string-match-p (rx bos "dav") method) + (string-match +- (tramp-compat-rx bol (? "/") (+ (not "/"))) localname)) ++ (tramp-compat-rx bos (? "/") (+ (not "/"))) localname)) + (match-string 0 localname) + (tramp-gvfs-get-remote-prefix vec)))) + +diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el +index 6ebd17d..3aa63db 100644 +--- a/lisp/net/tramp-rclone.el ++++ b/lisp/net/tramp-rclone.el +@@ -188,7 +188,7 @@ arguments to pass to the OPERATION." + (delq nil + (mapcar + (lambda (line) +- (when (string-match (rx bol (group (+ (not blank))) ":" eol) line) ++ (when (string-match (rx bos (group (+ (not blank))) ":" eos) line) + `(nil ,(match-string 1 line)))) + (tramp-process-lines nil tramp-rclone-program "listremotes"))))) + +@@ -362,7 +362,7 @@ file names." + (tramp-rclone-maybe-open-connection v) + ;; TODO: This shall be handled by `expand-file-name'. + (setq localname +- (replace-regexp-in-string (rx bol ".") "" (or localname ""))) ++ (replace-regexp-in-string (rx bos ".") "" (or localname ""))) + (format "%s%s" (tramp-fuse-mounted-p v) localname))) + ;; It is a local file name. + filename)) +diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el +index 6d5697a..d07b81d 100644 +--- a/lisp/net/tramp-smb.el ++++ b/lisp/net/tramp-smb.el +@@ -1650,7 +1650,7 @@ VEC or USER, or if there is no home directory, return nil." + (save-match-data + (let ((localname (tramp-file-name-unquote-localname vec))) + (when (string-match +- (tramp-compat-rx bol (? "/") (group (+ (not "/"))) "/") localname) ++ (tramp-compat-rx bos (? "/") (group (+ (not "/"))) "/") localname) + (match-string 1 localname))))) + + (defun tramp-smb-get-localname (vec) +@@ -1661,7 +1661,7 @@ If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"." + (setq + localname + (if (string-match +- (tramp-compat-rx bol (? "/") (+ (not "/")) (group "/" (* nonl))) ++ (tramp-compat-rx bos (? "/") (+ (not "/")) (group "/" (* nonl))) + localname) + ;; There is a share, separated by "/". + (if (not (tramp-smb-get-cifs-capabilities vec)) +@@ -1671,7 +1671,7 @@ If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"." + (match-string 1 localname)) + ;; There is just a share. + (if (string-match +- (tramp-compat-rx bol (? "/") (group (+ (not "/"))) eol) localname) ++ (tramp-compat-rx bos (? "/") (group (+ (not "/"))) eos) localname) + (match-string 1 localname) + ""))) + +diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el +index 2d6db31..66c8d95 100644 +--- a/lisp/net/tramp.el ++++ b/lisp/net/tramp.el +@@ -931,11 +931,11 @@ Used in `tramp-make-tramp-file-name'.") + + (defun tramp-build-prefix-regexp () + "Return `tramp-prefix-regexp'." +- (tramp-compat-rx bol (literal (tramp-build-prefix-format)))) ++ (tramp-compat-rx bos (literal (tramp-build-prefix-format)))) + + (defvar tramp-prefix-regexp nil ; Initialized when defining `tramp-syntax'! + "Regexp matching the very beginning of Tramp file names. +-Should always start with \"^\". Derived from `tramp-prefix-format'.") ++Should always start with \"\\\\=`\". Derived from `tramp-prefix-format'.") + + (defconst tramp-method-regexp-alist + `((default . ,(tramp-compat-rx +@@ -976,7 +976,10 @@ Used in `tramp-make-tramp-file-name'.") + "Regexp matching delimiter between method and user or host names. + Derived from `tramp-postfix-method-format'.") + +-(defconst tramp-user-regexp (rx (+ (not (any "/:|" blank)))) ++(defconst tramp-user-regexp ++ (rx (| (+ (not (any "/\\^$?*:;|[]{}()<>`'\"" blank))) ++ ;; Environment variable. ++ (: "$" (+ (any "_" alnum))))) + "Regexp matching user names.") + + (defconst tramp-prefix-domain-format "%" +@@ -1735,6 +1738,8 @@ default values are used." + (hop (match-string (nth 5 tramp-file-name-structure) name)) + domain port v) + (when user ++ (while (string-match (rx bos "$" (group (+ (any "_" alnum))) eos) user) ++ (setq user (getenv (match-string 1 user)))) + (when (string-match tramp-user-with-domain-regexp user) + (setq domain (match-string 2 user) + user (match-string 1 user)))) +@@ -2753,9 +2758,9 @@ Fall back to normal file name handler if no Tramp file name handler exists." + ;; `file-remote-p' is called for everything, even for symbolic + ;; links which look remote. We don't want to get an error. + (non-essential (or non-essential (eq operation 'file-remote-p)))) ++ (setq filename (tramp-replace-environment-variables filename)) + (if (tramp-tramp-file-p filename) + (save-match-data +- (setq filename (tramp-replace-environment-variables filename)) + (with-parsed-tramp-file-name filename nil + (let ((current-connection tramp-current-connection) + (foreign +@@ -6352,6 +6357,9 @@ to cache the result. Return the modified ATTR." + (caar attr)) + (decode-coding-string + (match-string 1 (caar attr)) 'utf-8)))) ++ ;; Quote remote-like symlink. ++ (when (and (stringp (car attr)) (tramp-tramp-file-p (car attr))) ++ (setcar attr (file-name-quote (car attr) 'top))) + ;; Set file's gid change bit. + (setcar + (nthcdr 9 attr) +-- +2.45.4 + diff --git a/SPECS/emacs/emacs.spec b/SPECS/emacs/emacs.spec index 332863e164b..2b6215fdfee 100644 --- a/SPECS/emacs/emacs.spec +++ b/SPECS/emacs/emacs.spec @@ -1,7 +1,7 @@ Summary: GNU Emacs text editor Name: emacs Version: 29.4 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv3+ AND CC0-1.0 Vendor: Microsoft Corporation Distribution: Azure Linux @@ -13,6 +13,7 @@ Source2: default.el Patch0: CVE-2025-1244.patch Patch1: CVE-2024-53920.patch Patch2: CVE-2026-6861.patch +Patch3: CVE-2026-79992.patch BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: gnutls-devel @@ -131,6 +132,9 @@ rm -f *-filelist {common,el}-*-files %dir %{_datadir}/emacs/site-lisp/site-start.d %changelog +* Sun Aug 30 2026 Azure Linux Security Servicing Account - 29.4-5 +- Patch for CVE-2026-79992 + * Wed Apr 29 2026 Azure Linux Security Servicing Account - 29.4-4 - Patch for CVE-2026-6861