aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2017-09-16 12:45:24 +0300
committerEli Zaretskii2017-09-16 12:45:24 +0300
commita103dbe36022cd2454eaeed96def1c777c049762 (patch)
treea3455f3e0ef50b9bbc1085c3199b4434851ebf35
parent6d6dc246f93486fc8370399b6e1af8a17f371e4f (diff)
downloademacs-a103dbe36022cd2454eaeed96def1c777c049762.tar.gz
emacs-a103dbe36022cd2454eaeed96def1c777c049762.zip
Disable execution of unsafe Lisp by Enriched Text mode
* src/xdisp.c (handle_display_spec): If the display property is wrapped in 'disable-eval' form, disable Lisp evaluation while processing this property. (handle_single_display_spec): Accept new argument ENABLE_EVAL_P. If that argument is false, don't evaluate Lisp while processing display properties. * lisp/textmodes/enriched.el (enriched-allow-eval-in-display-props): New defcustom. (enriched-decode-display-prop): If enriched-allow-eval-in-display-props is nil, wrap the display property with 'disable-eval' to disable Lisp evaluation when the display property is processed for display. (Bug#28350) * lisp/gnus/mm-view.el (mm-inline-text): Re-enable processing of enriched text. * doc/lispref/display.texi (Display Property): Document the 'disable-eval' wrapping of 'display' properties. * doc/emacs/text.texi (Enriched Properties): Document 'enriched-allow-eval-in-display-props'. * etc/NEWS: Describe the security issues with Enriched Text mode and their solution.
-rw-r--r--doc/emacs/text.texi17
-rw-r--r--doc/lispref/display.texi11
-rw-r--r--etc/NEWS22
-rw-r--r--lisp/gnus/mm-view.el10
-rw-r--r--lisp/textmodes/enriched.el23
-rw-r--r--src/xdisp.c37
6 files changed, 101 insertions, 19 deletions
diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi
index 3b54aa82631..496b43ce1e3 100644
--- a/doc/emacs/text.texi
+++ b/doc/emacs/text.texi
@@ -2398,6 +2398,23 @@ these special properties from the text in the region.
2398 2398
2399 The @code{invisible} and @code{intangible} properties are not saved. 2399 The @code{invisible} and @code{intangible} properties are not saved.
2400 2400
2401@vindex enriched-allow-eval-in-display-props
2402@cindex security, when displaying enriched text
2403 Enriched mode also supports saving and restoring @code{display}
2404properties (@pxref{Display Property,,,elisp, the Emacs Lisp Reference
2405Manual}), which affect how text is displayed on the screen, and also
2406allow displaying images and strings that come from sources other than
2407buffer text. The @code{display} properties also support execution of
2408arbitrary Lisp forms as part of processing the property for display,
2409thus providing a means to dynamically tailor the display to some
2410conditions that can only be known at display time. Since execution of
2411arbitrary Lisp opens Emacs to potential attacks, especially when the
2412source of enriched text is outside of Emacs or even outside of your
2413system (e.g., if it was received in an email message), such execution
2414is by default disabled in Enriched mode. You can enable it by
2415customizing the variable @code{enriched-allow-eval-in-display-props}
2416to a non-@code{nil} value.
2417
2401@node Text Based Tables 2418@node Text Based Tables
2402@section Editing Text-based Tables 2419@section Editing Text-based Tables
2403@cindex table mode 2420@cindex table mode
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 1dbc0bbb5bf..3dae984f339 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -4486,6 +4486,17 @@ for the @code{display} property, only one of the values takes effect,
4486following the rules of @code{get-char-property}. @xref{Examining 4486following the rules of @code{get-char-property}. @xref{Examining
4487Properties}. 4487Properties}.
4488 4488
4489@cindex display property, unsafe evaluation
4490@cindex security, and display specifications
4491 Some of the display specifications allow inclusion of Lisp forms,
4492which are evaluated at display time. This could be unsafe in certain
4493situations, e.g., when the display specification was generated by some
4494external program/agent. Wrapping a display specification in a list
4495that begins with the special symbol @code{disable-eval}, as in
4496@w{@code{('disable-eval @var{spec})}}, will disable evaluation of any
4497Lisp in @var{spec}, while still supporting all the other display
4498property features.
4499
4489 The rest of this section describes several kinds of 4500 The rest of this section describes several kinds of
4490display specifications and what they mean. 4501display specifications and what they mean.
4491 4502
diff --git a/etc/NEWS b/etc/NEWS
index 016868d5a34..ce828043bb7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -117,6 +117,28 @@ The effect is similar to that of "toolBar" resource on the tool bar.
117 117
118* Changes in Emacs 26.1 118* Changes in Emacs 26.1
119 119
120** Security vulnerability related to Enriched Text mode is removed.
121
122+++
123*** Enriched Text mode does not evaluate Lisp in 'display' properties.
124This feature allows saving 'display' properties as part of text.
125Emacs 'display' properties support evaluation of arbitrary Lisp forms
126as part of processing the property for display, so displaying Enriched
127Text could be vulnerable to executing arbitrary malicious Lisp code
128included in the text (e.g., sent as part of an email message).
129Therefore, execution of arbitrary Lisp forms in 'display' properties
130decoded by Enriched Text mode is now disabled by default. Customize
131the new option 'enriched-allow-eval-in-display-props' to a non-nil
132value to allow Lisp evaluation in decoded 'display' properties.
133
134This vulnerability was introduced in Emacs 21.1. To work around that
135in Emacs versions before 25.3, append the following to your ~/.emacs
136init file:
137
138 (eval-after-load "enriched"
139 '(defun enriched-decode-display-prop (start end &optional param)
140 (list start end)))
141
120+++ 142+++
121** Functions in 'write-contents-functions' can fully short-circuit the 143** Functions in 'write-contents-functions' can fully short-circuit the
122'save-buffer' process. Previously, saving a buffer that was not 144'save-buffer' process. Previously, saving a buffer that was not
diff --git a/lisp/gnus/mm-view.el b/lisp/gnus/mm-view.el
index 86e217131ac..d7a41b84930 100644
--- a/lisp/gnus/mm-view.el
+++ b/lisp/gnus/mm-view.el
@@ -362,12 +362,10 @@
362 (goto-char (point-max)))) 362 (goto-char (point-max))))
363 (save-restriction 363 (save-restriction
364 (narrow-to-region b (point)) 364 (narrow-to-region b (point))
365 ;; Disabled in Emacs 25.3 to avoid execution of arbitrary Lisp 365 (when (member type '("enriched" "richtext"))
366 ;; forms in display properties supported by enriched.el. 366 (set-text-properties (point-min) (point-max) nil)
367 ;; (when (member type '("enriched" "richtext")) 367 (ignore-errors
368 ;; (set-text-properties (point-min) (point-max) nil) 368 (enriched-decode (point-min) (point-max))))
369 ;; (ignore-errors
370 ;; (enriched-decode (point-min) (point-max))))
371 (mm-handle-set-undisplayer 369 (mm-handle-set-undisplayer
372 handle 370 handle
373 `(lambda () 371 `(lambda ()
diff --git a/lisp/textmodes/enriched.el b/lisp/textmodes/enriched.el
index d90c207575b..be5cd6b7310 100644
--- a/lisp/textmodes/enriched.el
+++ b/lisp/textmodes/enriched.el
@@ -147,6 +147,22 @@ them and their old values to `enriched-old-bindings'."
147 :type 'hook 147 :type 'hook
148 :group 'enriched) 148 :group 'enriched)
149 149
150(defcustom enriched-allow-eval-in-display-props nil
151 "If non-nil allow to evaluate arbitrary forms in display properties.
152
153Enriched mode recognizes display properties of text stored using
154an extension command to the text/enriched format, \"x-display\".
155These properties must not, by default, include evaluation of
156Lisp forms, otherwise they are not applied. Customize this option
157to t to turn off this safety feature, and allow Enriched mode to
158apply display properties which evaluate arbitrary Lisp forms.
159Note, however, that applying unsafe display properties could
160execute malicious Lisp code, if that code came from an external source."
161 :risky t
162 :type 'boolean
163 :version "26.1"
164 :group 'enriched)
165
150(defvar enriched-old-bindings nil 166(defvar enriched-old-bindings nil
151 "Store old variable values that we change when entering mode. 167 "Store old variable values that we change when entering mode.
152The value is a list of \(VAR VALUE VAR VALUE...).") 168The value is a list of \(VAR VALUE VAR VALUE...).")
@@ -503,9 +519,8 @@ the range of text to assign text property SYMBOL with value VALUE."
503 (error nil))))) 519 (error nil)))))
504 (unless prop 520 (unless prop
505 (message "Warning: invalid <x-display> parameter %s" param)) 521 (message "Warning: invalid <x-display> parameter %s" param))
506 ;; Disabled in Emacs 25.3 to avoid execution of arbitrary Lisp 522 (if enriched-allow-eval-in-display-props
507 ;; forms in display properties stored within enriched text. 523 (list start end 'display prop)
508 ;; (list start end 'display prop))) 524 (list start end 'display (list 'disable-eval prop)))))
509 (list start end)))
510 525
511;;; enriched.el ends here 526;;; enriched.el ends here
diff --git a/src/xdisp.c b/src/xdisp.c
index 8ca9037a00d..dc5dbb05762 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -876,9 +876,9 @@ static int face_before_or_after_it_pos (struct it *, bool);
876static ptrdiff_t next_overlay_change (ptrdiff_t); 876static ptrdiff_t next_overlay_change (ptrdiff_t);
877static int handle_display_spec (struct it *, Lisp_Object, Lisp_Object, 877static int handle_display_spec (struct it *, Lisp_Object, Lisp_Object,
878 Lisp_Object, struct text_pos *, ptrdiff_t, bool); 878 Lisp_Object, struct text_pos *, ptrdiff_t, bool);
879static int handle_single_display_spec (struct it *, Lisp_Object, 879static int handle_single_display_spec (struct it *, Lisp_Object, Lisp_Object,
880 Lisp_Object, Lisp_Object, 880 Lisp_Object, struct text_pos *,
881 struct text_pos *, ptrdiff_t, int, bool); 881 ptrdiff_t, int, bool, bool);
882static int underlying_face_id (struct it *); 882static int underlying_face_id (struct it *);
883 883
884#define face_before_it_pos(IT) face_before_or_after_it_pos (IT, true) 884#define face_before_it_pos(IT) face_before_or_after_it_pos (IT, true)
@@ -4748,6 +4748,14 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4748 ptrdiff_t bufpos, bool frame_window_p) 4748 ptrdiff_t bufpos, bool frame_window_p)
4749{ 4749{
4750 int replacing = 0; 4750 int replacing = 0;
4751 bool enable_eval = true;
4752
4753 /* Support (disable-eval PROP) which is used by enriched.el. */
4754 if (CONSP (spec) && EQ (XCAR (spec), Qdisable_eval))
4755 {
4756 enable_eval = false;
4757 spec = XCAR (XCDR (spec));
4758 }
4751 4759
4752 if (CONSP (spec) 4760 if (CONSP (spec)
4753 /* Simple specifications. */ 4761 /* Simple specifications. */
@@ -4771,7 +4779,8 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4771 { 4779 {
4772 int rv = handle_single_display_spec (it, XCAR (spec), object, 4780 int rv = handle_single_display_spec (it, XCAR (spec), object,
4773 overlay, position, bufpos, 4781 overlay, position, bufpos,
4774 replacing, frame_window_p); 4782 replacing, frame_window_p,
4783 enable_eval);
4775 if (rv != 0) 4784 if (rv != 0)
4776 { 4785 {
4777 replacing = rv; 4786 replacing = rv;
@@ -4789,7 +4798,8 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4789 { 4798 {
4790 int rv = handle_single_display_spec (it, AREF (spec, i), object, 4799 int rv = handle_single_display_spec (it, AREF (spec, i), object,
4791 overlay, position, bufpos, 4800 overlay, position, bufpos,
4792 replacing, frame_window_p); 4801 replacing, frame_window_p,
4802 enable_eval);
4793 if (rv != 0) 4803 if (rv != 0)
4794 { 4804 {
4795 replacing = rv; 4805 replacing = rv;
@@ -4802,7 +4812,8 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4802 } 4812 }
4803 else 4813 else
4804 replacing = handle_single_display_spec (it, spec, object, overlay, position, 4814 replacing = handle_single_display_spec (it, spec, object, overlay, position,
4805 bufpos, 0, frame_window_p); 4815 bufpos, 0, frame_window_p,
4816 enable_eval);
4806 return replacing; 4817 return replacing;
4807} 4818}
4808 4819
@@ -4847,6 +4858,8 @@ display_prop_end (struct it *it, Lisp_Object object, struct text_pos start_pos)
4847 don't set up IT. In that case, FRAME_WINDOW_P means SPEC 4858 don't set up IT. In that case, FRAME_WINDOW_P means SPEC
4848 is intended to be displayed in a window on a GUI frame. 4859 is intended to be displayed in a window on a GUI frame.
4849 4860
4861 Enable evaluation of Lisp forms only if ENABLE_EVAL_P is true.
4862
4850 Value is non-zero if something was found which replaces the display 4863 Value is non-zero if something was found which replaces the display
4851 of buffer or string text. */ 4864 of buffer or string text. */
4852 4865
@@ -4854,7 +4867,7 @@ static int
4854handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, 4867handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4855 Lisp_Object overlay, struct text_pos *position, 4868 Lisp_Object overlay, struct text_pos *position,
4856 ptrdiff_t bufpos, int display_replaced, 4869 ptrdiff_t bufpos, int display_replaced,
4857 bool frame_window_p) 4870 bool frame_window_p, bool enable_eval_p)
4858{ 4871{
4859 Lisp_Object form; 4872 Lisp_Object form;
4860 Lisp_Object location, value; 4873 Lisp_Object location, value;
@@ -4872,6 +4885,8 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4872 spec = XCDR (spec); 4885 spec = XCDR (spec);
4873 } 4886 }
4874 4887
4888 if (!NILP (form) && !EQ (form, Qt) && !enable_eval_p)
4889 form = Qnil;
4875 if (!NILP (form) && !EQ (form, Qt)) 4890 if (!NILP (form) && !EQ (form, Qt))
4876 { 4891 {
4877 ptrdiff_t count = SPECPDL_INDEX (); 4892 ptrdiff_t count = SPECPDL_INDEX ();
@@ -4920,7 +4935,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4920 steps = - steps; 4935 steps = - steps;
4921 it->face_id = smaller_face (it->f, it->face_id, steps); 4936 it->face_id = smaller_face (it->f, it->face_id, steps);
4922 } 4937 }
4923 else if (FUNCTIONP (it->font_height)) 4938 else if (FUNCTIONP (it->font_height) && enable_eval_p)
4924 { 4939 {
4925 /* Call function with current height as argument. 4940 /* Call function with current height as argument.
4926 Value is the new height. */ 4941 Value is the new height. */
@@ -4941,7 +4956,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
4941 new_height = (XFLOATINT (it->font_height) 4956 new_height = (XFLOATINT (it->font_height)
4942 * XINT (f->lface[LFACE_HEIGHT_INDEX])); 4957 * XINT (f->lface[LFACE_HEIGHT_INDEX]));
4943 } 4958 }
4944 else 4959 else if (enable_eval_p)
4945 { 4960 {
4946 /* Evaluate IT->font_height with `height' bound to the 4961 /* Evaluate IT->font_height with `height' bound to the
4947 current specified height to get the new height. */ 4962 current specified height to get the new height. */
@@ -32204,6 +32219,10 @@ They are still logged to the *Messages* buffer. */);
32204 DEFSYM (Qfontified, "fontified"); 32219 DEFSYM (Qfontified, "fontified");
32205 DEFSYM (Qfontification_functions, "fontification-functions"); 32220 DEFSYM (Qfontification_functions, "fontification-functions");
32206 32221
32222 /* Name of the symbol which disables Lisp evaluation in 'display'
32223 properties. This is used by enriched.el. */
32224 DEFSYM (Qdisable_eval, "disable-eval");
32225
32207 /* Name of the face used to highlight trailing whitespace. */ 32226 /* Name of the face used to highlight trailing whitespace. */
32208 DEFSYM (Qtrailing_whitespace, "trailing-whitespace"); 32227 DEFSYM (Qtrailing_whitespace, "trailing-whitespace");
32209 32228