pkg/60648: editors/emacs20: LP64 Lisp_Object truncation breaks Japanese input, plus two unbackported CVEs

"[email protected] via gnats" <[email protected]>
Newsgroups gmane.os.netbsd.devel.pkgsrc.bugs
Message-ID <[email protected]>
>Number:         60648
>Category:       pkg
>Synopsis:       editors/emacs20: LP64 Lisp_Object truncation breaks Japanese input, plus two unbackported CVEs
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Aug 26 17:05:00 +0000 2026
>Originator:     Showta Ishizaki
>Release:        NetBSD 11.0, pkgsrc CVS as of 2026-08-27
>Organization:
>Environment:
System: NetBSD 11.0 amd64
Architecture: x86_64
Machine: amd64
>Description:
	On any LP64 platform, emacs20 cannot set up a CJK language
	environment:

	  $ emacs -batch -q --eval '(set-language-environment "Japanese")'
	  Wrong type argument: stringp, 8510432

	Chinese-GB and Korean fail the same way.  Greek, Latin-1 and
	English are fine.  Because it happens in set-language-environment,
	an init file that does

	  (set-language-environment "Japanese")
	  (load-library "anthy")

	dies before the input method is ever reached, so emacs20 is
	unusable for Japanese input on amd64.  On i386 none of this
	happens.

	The value printed is not really an integer.  Under gdb the object
	handed to CHECK_STRING is 0x81dbb8, and at that address there is a
	perfectly good struct Lisp_String:

	  (gdb) x/6gx $rsi
	  0x81dbb8:	0x0000000000000051	0xffffffffffffffff
	  0x81dbc8:	0x0000000000000000	0x6d6f682f7273752f
	  (gdb) x/s $rsi+24
	  0x81dbd0:	"/usr/home/techne/zakinko/w/..."

	size 0x51, size_byte -1, and the expanded file name in the data
	field.  What is missing is the type tag.  A Lisp_String on this
	build should be (3 << 60) | address; the value has the address
	only, so XTYPE reads it as Lisp_Int.

	The backtrace says where:

	  #0  wrong_type_argument ()
	  #1  Ffind_file_name_handler ()
	  #2  openp ()
	  #3  Fload ()

	and the disassembly says why:

	  0x4b36f3 <openp+1176>:	call   <code_convert_string_norecord>
	  0x4b36f8 <openp+1181>:	movslq %eax,%r8

	The return value is being sign-extended from 32 bits.
	code_convert_string_norecord returns a Lisp_Object, but nothing
	declares it.  It is only ever reached through the ENCODE_FILE and
	DECODE_FILE macros in src/coding.h, and coding.h declares
	code_convert_region, decode_coding, encode_coding,
	setup_coding_system and the rest -- but not this one.  So every
	caller compiles it as an implicit int, and on LP64 the top 32 bits,
	tag included, are thrown away.

	Six files use those macros: callproc.c, dired.c, fileio.c,
	filelock.c, lread.c and process.c.  Most of them survive by luck.
	They pass the result straight to XSTRING, and XPNTR masks the tag
	off again, so a truncated-but-positive pointer still yields the
	right address.  openp is the one that does not: it passes the value
	to Ffind_file_name_handler, whose CHECK_STRING looks at the type.

	openp does not use ENCODE_FILE in stock Emacs 20.7.  It gets it
	from emacs-20.7-mule-4.1b.patch, which this package applies:

	  filename = ENCODE_FILE (filename);

	The effect is broad.  Once Vdefault_file_name_coding_system is
	non-nil, every relative load fails -- (load "subr") included:

	  $ emacs -batch -q --eval '(progn
	      (setq default-file-name-coding-system (quote japanese-iso-8bit))
	      (load "subr"))'
	  Wrong type argument: stringp, 8510424

	An absolute path works, because openp only calls
	Ffind_file_name_handler when the name is not already absolute.

	set-language-environment sets that variable through
	prefer-coding-system, which is why the failure follows the language
	rather than the coding system: "Japanese", "Chinese-GB" and
	"Korean" have a `features' entry and load one more file, and that
	load is the one that dies.  "Greek" and "Latin-1" load nothing
	further and come through unharmed.

	src/lisp.h has the same omission four more times.  These are also
	Lisp_Object-returning functions called with no declaration in
	scope:

	  Fcurrent_message	keyboard.c:2360
	  Fcurrent_time		frame.c:1476, window.c:1968
	  Fset_buffer_multibyte	coding.c:4992, buffer.c:3981
	  Fwindow_end		xdisp.c:2259

	Two of them matter.  keyboard.c:2360 is

	  Vinput_method_previous_message = echo_area_message
	    = Fcurrent_message ();

	which sits in read_char and is reached whenever
	input-method-function is set -- that is, exactly when a Japanese
	input method is in use.  window.c:1968 stores a truncated list into
	the buffer's display_time.  The other two survive today: one caller
	discards the result and the other feeds it to XINT, which masks the
	tag off.  All four are the same mistake and all four are declared
	here.

	The fix is not invented.  Emacs 21 declares all five, and these are
	its lines, in its places:

	  src/ChangeLog
	  2000-06-05  Dave Love  <[email protected]>
		  * coding.h: Declare code_convert_string_norecord.

	Emacs 20.7 was released on 2000-06-13, eight days later, from a
	branch that never got it.  lisp.h's section layout is close enough
	between 20.7 and 21.1 that the four EXFUN lines go in the same
	places as well.

	Unrelated to the LP64 bug above, this package also carries two
	CVEs that were fixed upstream but never reached the emacs-20
	branch (the oldest branch on the mirror is emacs-23), plus a
	gets() cleanup.

	CVE-2022-45939 / CVE-2022-48337 -- etags/ctags paste file names
	into shell commands run through system(3) without quoting.  Both
	call sites are live in 20.7: the -u update loop walks
	argbuffer[] by current_arg, and "sort %s -o %s" over the -o
	output file is reached directly.

	    ctags -u -o 'tags;touch /tmp/pwned' file.c

	ran the injected command before the fix and does nothing after
	it; a normal "-o out.tags" still works.  (20.7's etags has no
	decompressor, so it lacks the third, popen, site that later
	versions have.)  Backport of upstream 01a4035c8 "Fix etags local
	command injection vulnerability" (Bug#59817) and 8a098f651 "Fix
	quoting of file names in 'ctags'"; the upstream
	escape_shell_arg_string() is brought to the old K&R source as
	shell_quote().

	CVE-2017-1000383 -- copy-file creates the destination with
	creat(...,0666) and only chmods it afterwards, so a copy of a
	private file is briefly world-readable and a backup inherits the
	source's setuid/setgid bits.  A 04755 source produced a 04755
	backup before the fix and a 0755 one after.  Modern Emacs closes
	this with with-file-modes ?\700 in backup-buffer-copy (files.el)
	and O_CREAT|O_EXCL plus ~06000 in Fcopy_file; this does the same
	at the C level: create 0600 and mask the chmod with 01777.

	patch-src_xrdb.c replaces gets() with fgets() in the [TESTRM]
	test driver, backporting upstream e90a457c46ca.  gets() is not
	compiled into the shipped binary (no gets symbol in it), so this
	changes nothing that runs; it is here to match upstream and to
	keep the source compiling with newer toolchains.
>How-To-Repeat:
	On amd64 (or any other LP64 platform):

	  cd /usr/pkgsrc/editors/emacs20
	  make install
	  emacs -batch -q --eval '(set-language-environment "Japanese")'

	  Wrong type argument: stringp, 8510432

	Or, more directly:

	  emacs -batch -q --eval '(progn
	      (setq default-file-name-coding-system (quote japanese-iso-8bit))
	      (load "subr"))'

	Both succeed on i386.

	For the etags injection, on any platform:

	    printf 'int main(void){return 0;}\n' > file.c
	    ctags -u -o 'tags;touch /tmp/pwned' file.c
	    test -f /tmp/pwned && echo vulnerable

	For copy-file, with backup-by-copying:

	    printf secret > src; chmod 4755 src; umask 077
	    emacs -batch -q --eval '(copy-file "src" "dst" t)'
	    ls -l dst        # setuid, world-readable backup before the fix
>Fix:
	Seven files.  The LP64 fix is two patches: patch-src_coding.h is
	new and declares code_convert_string_norecord; patch-bj gains four
	EXFUN lines, five lines of declaration in total.  The three
	CVE/cleanup patches are new: patch-CVE-2022-45939,
	patch-CVE-2017-1000383 and patch-src_xrdb.c.  PKGREVISION goes
	to 27.

	Built and run on NetBSD 11.0/amd64.  With the patch,
	emacs20-20.7nb27 sets up all six language environments that were
	tried:

	                    without the patch          with the patch
	  Japanese          Wrong type argument        ok
	  Chinese-GB        Wrong type argument        ok
	  Korean            Wrong type argument        ok
	  Greek             ok                         ok
	  Latin-1           ok                         ok
	  English           ok                         ok

	and inputmethod/anthy-elisp then converts: driving anthy.el from
	batch, "nihongo" becomes 日本語 and the buffer written out in
	EUC-JP contains it.  Without the patch the same script dies in
	set-language-environment.

	With the CVE patches the two exploits above are closed and
	ordinary etags and copy-file use is unchanged.

	On i386 the patch changes nothing, and that is worth showing
	rather than asserting.  ILP32 makes int and Lisp_Object the same
	width, so the value never leaves %eax:

	  i386   mov    %eax,-0x10c(%ebp)
	  amd64  movslq %eax,%r8

	Building emacs20-20.7nb27 on NetBSD 10.1/i386 and comparing it
	with the official emacs20-20.7nb26 binary package, the generated
	code is identical at every site the patch touches:

	  openp                     264 instructions
	  Ffind_file_name_handler    91
	  read_char                1862
	  Fset_window_buffer        151
	  Fset_buffer_multibyte     279

	The unpatched i386 package also sets up all six language
	environments, so the bug simply does not exist there.


Index: editors/emacs20/Makefile
===================================================================
RCS file: /cvsroot/pkgsrc/editors/emacs20/Makefile,v
retrieving revision 1.67
diff -u -r1.67 Makefile
--- editors/emacs20/Makefile
+++ editors/emacs20/Makefile
@@ -2,7 +2,7 @@
 
 DISTNAME=	emacs-20.7
 PKGNAME=	${DISTNAME:S/emacs/emacs20/}
-PKGREVISION=	26
+PKGREVISION=	27
 CATEGORIES=	editors
 MASTER_SITES=	http://ftp.gnu.org/pub/old-gnu/emacs/
 MASTER_SITES+=	ftp://ftp.gnu.org/pub/old-gnu/emacs
Index: editors/emacs20/distinfo
===================================================================
RCS file: /cvsroot/pkgsrc/editors/emacs20/distinfo,v
retrieving revision 1.42
diff -u -r1.42 distinfo
--- editors/emacs20/distinfo
+++ editors/emacs20/distinfo
@@ -15,6 +15,8 @@
 BLAKE2s (emacs20-xim-20000713.diff) = 22ddc9c54b5c3535bf9788af7c00dd3eea65fcbb2360aeed54feb5d800672b3c
 SHA512 (emacs20-xim-20000713.diff) = d6d3fb483db830ddcf07f6325901fb7faca1e112129f27036328eb4a6a53851a53318a31830a751525b9e0898256c6c9bfe5c3c333401d44a6dcbad44ba3c7a8
 Size (emacs20-xim-20000713.diff) = 21296 bytes
+SHA1 (patch-CVE-2017-1000383) = 943dfbef56b7347ae25a0cc59b15ac2849d3961e
+SHA1 (patch-CVE-2022-45939) = f9850749a0414e1d88902257e5ca46e40a105a50
 SHA1 (patch-aa) = 3b3fd76c058a0a46e0458338ce4c2327a238fb3d
 SHA1 (patch-ab) = 16c236c232649cc89ed89131a793e201bccef5f0
 SHA1 (patch-ac) = abf5971279a8d875504be4c17b8d36cb8cc24885
@@ -40,7 +42,7 @@
 SHA1 (patch-bg) = b98608214ea7c1c48905029728ddd7424bc12391
 SHA1 (patch-bh) = f59b14cc43d5977a5d80d5d1ab4e246df394d86a
 SHA1 (patch-bi) = c0e237bd46de0f9ef137997e59231f119d5f791e
-SHA1 (patch-bj) = 6dba88723ee632b67fcf6a2dd2918e69034837e2
+SHA1 (patch-bj) = 30dfffe2fa4a66bc01919f332d5c2c86979e69d3
 SHA1 (patch-bl) = f2cd03713d7cdb6cb41119569031249d7d708b13
 SHA1 (patch-bm) = 2f00f63120a90477c6f5c63ac6ca23fc508b9e54
 SHA1 (patch-bp) = 7b9ad94ac9d09fbb2173fdd3efd04faa0a668a91
@@ -54,4 +56,6 @@
 SHA1 (patch-ce) = df4d2a5639a72d2c719662496f17db35686f4ac2
 SHA1 (patch-cf) = 1b5b83eb02872414fd7ca29c344c0560feaf1b7e
 SHA1 (patch-cg) = b2bd4cbff399922e44ad54459255ffb1d61e1bd4
+SHA1 (patch-src_coding.h) = 25e759b5484fdf21076807fb47ebfacb6906d97c
 SHA1 (patch-src_m_aarch64.h) = 861757ce6568303ea55cb9c9f290abc6100d3dc2
+SHA1 (patch-src_xrdb.c) = 34b87fca7d84f286a283a6defea62954eafca2d0
Index: editors/emacs20/patches/patch-bj
===================================================================
RCS file: /cvsroot/pkgsrc/editors/emacs20/patches/patch-bj,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 patch-bj
--- editors/emacs20/patches/patch-bj
+++ editors/emacs20/patches/patch-bj
@@ -1,5 +1,24 @@
 $NetBSD: patch-bj,v 1.1.1.1 2003/04/11 00:31:45 uebayasi Exp $
 
+Make Lisp_Object 64 bits wide on LP64, and declare four Lisp functions
+that return one.
+
+Nothing declares them, so the implicit int return truncates the value to
+32 bits and the type tag (bits 60-62) goes with it.  Two of the four are
+reached in practice:
+
+	keyboard.c:2360   Vinput_method_previous_message = echo_area_message
+			  = Fcurrent_message ();
+	window.c:1968     XBUFFER (buffer)->display_time = Fcurrent_time ();
+
+The first is on the input method path, taken whenever
+input-method-function is set, which is what Japanese input runs into.
+Fset_buffer_multibyte and Fwindow_end survive today, one because its
+caller discards the result and the other because XINT masks the tag off
+again, but they are the same mistake.
+
+Emacs 21 declares all four; these are its lines, in its places.
+
 --- ./src/lisp.h.orig	Sun Jan  3 08:31:23 1999
 +++ ./src/lisp.h	Tue Sep 26 09:48:10 2000
 @@ -123,25 +123,25 @@
@@ -102,3 +121,35 @@
  
  extern Lisp_Object make_number ();
  
+@@ -1997,6 +1997,7 @@
+ extern void syms_of_eval P_ ((void));
+ 
+ /* Defined in editfns.c */
++EXFUN (Fcurrent_message, 0);
+ EXFUN (Fgoto_char, 1);
+ EXFUN (Fpoint_min_marker, 0);
+ EXFUN (Fpoint_max_marker, 0);
+@@ -2035,6 +2036,7 @@
+ EXFUN (Fwiden, 0);
+ EXFUN (Fuser_login_name, 1);
+ EXFUN (Fsystem_name, 0);
++EXFUN (Fcurrent_time, 0);
+ extern int clip_to_bounds P_ ((int, int, int));
+ extern Lisp_Object make_buffer_string P_ ((int, int, int));
+ extern Lisp_Object make_buffer_string_both P_ ((int, int, int, int, int));
+@@ -2043,6 +2045,7 @@
+ 
+ /* defined in buffer.c */
+ extern void nsberror P_ ((Lisp_Object));
++EXFUN (Fset_buffer_multibyte, 1);
+ EXFUN (Foverlay_start, 1);
+ EXFUN (Foverlay_end, 1);
+ extern void adjust_overlays_for_insert P_ ((int, int));
+@@ -2256,6 +2259,7 @@
+ 
+ /* defined in window.c */
+ extern Lisp_Object Qwindowp, Qwindow_live_p;
++EXFUN (Fwindow_end, 2);
+ EXFUN (Fselected_window, 0);
+ EXFUN (Fnext_window, 3);
+ EXFUN (Fdelete_window, 1);
Index: editors/emacs20/patches/patch-src_coding.h
===================================================================
RCS file: editors/emacs20/patches/patch-src_coding.h
diff -N editors/emacs20/patches/patch-src_coding.h
--- /dev/null
+++ editors/emacs20/patches/patch-src_coding.h
@@ -0,0 +1,37 @@
+$NetBSD$
+
+Declare code_convert_string_norecord, which returns a Lisp_Object.
+
+ENCODE_FILE and DECODE_FILE call it and nothing declares it, so on LP64
+the implicit int return truncates the 64-bit Lisp_Object to 32 bits and
+the type tag (bits 60-62) is lost.  Most callers hand the result straight
+to XSTRING, which masks the tag off anyway, so they survive; the one in
+openp does not.
+
+openp gets ENCODE_FILE from the Mule 4.1b distribution patch:
+
+	filename = ENCODE_FILE (filename);
+
+and then passes filename to Ffind_file_name_handler, whose CHECK_STRING
+sees an untagged pointer as an integer:
+
+	Wrong type argument: stringp, 8510432
+
+So every relative load fails as soon as a non-nil file name coding system
+is in force.  set-language-environment sets one through
+prefer-coding-system, which is why "Japanese", "Chinese-GB" and "Korean"
+die while "Greek" and "Latin-1", which pull in no extra features, do not.
+
+Emacs 21 declares it; this is its line, in its place.
+
+--- src/coding.h.orig	2026-08-26 04:33:33.562475397 +0000
++++ src/coding.h
+@@ -563,6 +563,8 @@
+ extern char *get_conversion_buffer P_ ((int));
+ extern int setup_coding_system P_ ((Lisp_Object, struct coding_system *));
+ extern void setup_raw_text_coding_system P_ ((struct coding_system *));
++extern Lisp_Object code_convert_string_norecord P_ ((Lisp_Object, Lisp_Object,
++						     int));
+ extern Lisp_Object Qcoding_system, Qeol_type, Qcoding_category_index;
+ extern Lisp_Object Qraw_text, Qemacs_mule;
+ extern Lisp_Object Qbuffer_file_coding_system;
Index: editors/emacs20/patches/patch-CVE-2022-45939
===================================================================
RCS file: editors/emacs20/patches/patch-CVE-2022-45939
diff -N editors/emacs20/patches/patch-CVE-2022-45939
--- /dev/null
+++ editors/emacs20/patches/patch-CVE-2022-45939
+$NetBSD$
+
+CVE-2022-45939 and CVE-2022-48337: etags/ctags paste strings into shell
+commands and hand them to system(3) without quoting.  Backport of
+
+  From 01a4035c869b91c153af9a9132c87adb7669ea1c Mon Sep 17 00:00:00 2001
+  From: lu4nx <[email protected]>
+  Date: Tue, 6 Dec 2022
+  Subject: Fix etags local command injection vulnerability  (Bug#59817)
+
+  From 8a098f6517157ebe2364f08008b44ab49c2d1115 Mon Sep 17 00:00:00 2001
+  From: Eli Zaretskii <[email protected]>
+  Date: Fri, 1 Jul 2022
+  Subject: Fix quoting of file names in 'ctags'
+
+Upstream added escape_shell_arg_string() and quotes every file name it
+passes to the shell.  20.7 predates that by twenty years; this brings the
+same fix to the old K&R source, as shell_quote().
+
+Both call sites are live here.  The per-file update loop walks argbuffer[]
+by current_arg (not optind..argc, which is what makes the same loop dead in
+mule), and the "sort %s -o %s" over the -o output file is reached directly.
+On NetBSD 11.0/amd64:
+
+    ctags -u -o 'tags;touch /tmp/pwned' file.c
+
+ran the injected command before the fix and does nothing after it; a normal
+"-o out.tags" still works.  (20.7's etags has no decompressor, so it lacks
+the third, popen, site that 21.4 has.)
+
+--- lib-src/etags.c.orig
++++ lib-src/etags.c
+@@ -221,6 +221,7 @@
+ void error ();
+ void suggest_asking_for_help ();
+ void fatal (), pfatal ();
++char *shell_quote ();
+ void find_entries ();
+ void free_tree ();
+ void getit ();
+@@ -763,6 +764,41 @@
+ #endif /* VMS */
+ 
+ 
++/* Return a copy of STR wrapped in single quotes so that a shell passes it
++   through unchanged.  An embedded single quote is closed, escaped and
++   reopened.
++
++   Without this a string reaches the shell as written, and one that contains
++   shell metacharacters runs whatever it likes.  CVE-2022-45939 and
++   CVE-2022-48337.  */
++
++char *
++shell_quote (str)
++     char *str;
++{
++  char *p, *q, *out;
++  int n = 0;
++
++  for (p = str; *p != '\0'; p++)
++    n += (*p == '\'') ? 4 : 1;
++  out = xnew (n + 3, char);
++  q = out;
++  *q++ = '\'';
++  for (p = str; *p != '\0'; p++)
++    if (*p == '\'')
++      {
++	*q++ = '\'';
++	*q++ = '\\';
++	*q++ = '\'';
++	*q++ = '\'';
++      }
++    else
++      *q++ = *p;
++  *q++ = '\'';
++  *q = '\0';
++  return out;
++}
++
+ int
+ main (argc, argv)
+      int argc;
+@@ -1028,16 +1064,25 @@
+ 
+   if (update)
+     {
+-      char cmd[BUFSIZ];
+       for (i = 0; i < current_arg; ++i)
+ 	{
++	  char *pattern, *qpattern, *qtagfile, *cmd;
++
+ 	  if (argbuffer[i].arg_type != at_filename)
+ 	    continue;
+-	  sprintf (cmd,
+-		   "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
+-		   tagfile, argbuffer[i].what, tagfile);
++	  pattern = xnew (strlen (argbuffer[i].what) + 3, char);
++	  sprintf (pattern, "\t%s\t", argbuffer[i].what);
++	  qpattern = shell_quote (pattern);
++	  qtagfile = shell_quote (tagfile);
++	  cmd = xnew (2 * strlen (qtagfile) + strlen (qpattern) + 32, char);
++	  sprintf (cmd, "mv %s OTAGS;fgrep -v %s OTAGS >%s;rm OTAGS",
++		   qtagfile, qpattern, qtagfile);
+ 	  if (system (cmd) != GOOD)
+ 	    fatal ("failed to execute shell command", (char *)NULL);
++	  free (pattern);
++	  free (qpattern);
++	  free (qtagfile);
++	  free (cmd);
+ 	}
+       append_to_tagfile = TRUE;
+     }
+@@ -1050,9 +1095,15 @@
+ 
+   if (update)
+     {
+-      char cmd[BUFSIZ];
+-      sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
+-      exit (system (cmd));
++      char *qtagfile = shell_quote (tagfile);
++      char *cmd = xnew (2 * strlen (qtagfile) + 16, char);
++      int rc;
++
++      sprintf (cmd, "sort %s -o %s", qtagfile, qtagfile);
++      rc = system (cmd);
++      free (qtagfile);
++      free (cmd);
++      exit (rc);
+     }
+   return GOOD;
+ }
Index: editors/emacs20/patches/patch-CVE-2017-1000383
===================================================================
RCS file: editors/emacs20/patches/patch-CVE-2017-1000383
diff -N editors/emacs20/patches/patch-CVE-2017-1000383
--- /dev/null
+++ editors/emacs20/patches/patch-CVE-2017-1000383
+$NetBSD$
+
+CVE-2017-1000383: copy-file, which backup-buffer uses to make backups when
+backup-by-copying is in effect, creates the destination with creat(...,0666)
+and only chmods it to the wanted mode afterwards.  A copy of a private file
+is briefly world-readable, and a backup inherits the source's setuid/setgid
+bits.
+
+Upstream closes this in two places that 20.7/21.4 predate: lisp/files.el's
+backup-buffer-copy wraps the copy in (with-file-modes ?\700 ...) -- the
+with-file-modes macro is
+
+  From d63d883a97e32aa5f0983b6577f7cbef8b6c3a3d Mon Sep 17 00:00:00 2001
+  Date: Wed, 14 May 2014
+  Subject: Add with-file-modes macro, and use it
+
+-- and modern src/fileio.c creates the copy with O_CREAT|O_EXCL and strips
+the setuid/setgid bits (preserved_permissions &= ~06000).  This backport
+does the same at the C level for the old source: create 0600 so the file is
+never group/other-readable while it is being written, and mask the trailing
+chmod with 01777 (keeping the sticky and rwx bits, dropping setuid/setgid --
+the same effect as #o1777 in backup-buffer-copy).
+
+Reproduced on NetBSD 11.0/amd64 with emacs -batch and backup-by-copying: a
+04755 source produced a 04755 (setuid) backup before the fix and a 0755 one
+after.  This is the same change already carried in zakinko/mule.
+
+--- src/fileio.c.orig
++++ src/fileio.c
+@@ -2345,7 +2345,11 @@
+   /* System's default file type was set to binary by _fmode in emacs.c.  */
+   ofd = creat (XSTRING (encoded_newname)->data, S_IREAD | S_IWRITE);
+ #else /* not MSDOS */
+-  ofd = creat (XSTRING (encoded_newname)->data, 0666);
++  /* Create the copy owner-readable/writable only.  The final chmod below
++     widens it to the intended mode once the data is in place; creating it
++     0666 (masked only by umask) meant a copy of a private file was briefly
++     world-readable while it was being written.  CVE-2017-1000383.  */
++  ofd = creat (XSTRING (encoded_newname)->data, 0600);
+ #endif /* not MSDOS */
+ #endif /* VMS */
+   if (ofd < 0)
+@@ -2378,7 +2382,11 @@
+ 			    Fcons (newname, Qnil)));
+ 	}
+ #ifndef MSDOS
+-      chmod (XSTRING (encoded_newname)->data, st.st_mode & 07777);
++      /* Mask off the setuid and setgid bits: a copy -- above all a backup
++         file -- must never inherit them from the original.  01777 keeps the
++         sticky bit and the rwx bits, matching what a modern Emacs does with
++         #o1777.  CVE-2017-1000383.  */
++      chmod (XSTRING (encoded_newname)->data, st.st_mode & 01777);
+ #else /* MSDOS */
+ #if defined (__DJGPP__) && __DJGPP__ > 1
+       /* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
Index: editors/emacs20/patches/patch-src_xrdb.c
===================================================================
RCS file: editors/emacs20/patches/patch-src_xrdb.c
diff -N editors/emacs20/patches/patch-src_xrdb.c
--- /dev/null
+++ editors/emacs20/patches/patch-src_xrdb.c
+$NetBSD$
+
+Replace gets() in the [TESTRM] test driver with fgets(), backporting
+
+  From e90a457c46ca4c6a231a422b9b30f5e0d0f9d1c1 Mon Sep 17 00:00:00 2001
+  From: Eli Zaretskii <[email protected]>
+  Date: Thu, 8 Sep 2022
+  Subject: * src/xrdb.c (main) [TESTRM]: Replace gets with fgets.
+
+gets() has no bound and cannot be used safely; it was removed from C11.
+The call is inside the TESTRM stand-alone driver, which is not compiled
+into Emacs (the built binary has no gets symbol), so this changes no
+shipped code -- it is here to match upstream and to keep the source
+clean, since gets() is a hard error with newer toolchains.
+
+--- src/xrdb.c.orig
++++ src/xrdb.c
+@@ -718,14 +718,14 @@
+       char query_class[90];
+ 
+       printf ("Name: ");
+-      gets (query_name);
++      fgets (query_name, 90, stdin);
+ 
+       if (strlen (query_name))
+ 	{
+ 	  char *value;
+ 
+ 	  printf ("Class: ");
+-	  gets (query_class);
++	  fgets (query_class, 90, stdin);
+ 
+ 	  value = x_get_string_resource (xdb, query_name, query_class);
+
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.