Commit a103dbe3 authored by Eli Zaretskii's avatar Eli Zaretskii
Browse files

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.
parent 6d6dc246
......@@ -2398,6 +2398,23 @@ these special properties from the text in the region.
The @code{invisible} and @code{intangible} properties are not saved.
@vindex enriched-allow-eval-in-display-props
@cindex security, when displaying enriched text
Enriched mode also supports saving and restoring @code{display}
properties (@pxref{Display Property,,,elisp, the Emacs Lisp Reference
Manual}), which affect how text is displayed on the screen, and also
allow displaying images and strings that come from sources other than
buffer text. The @code{display} properties also support execution of
arbitrary Lisp forms as part of processing the property for display,
thus providing a means to dynamically tailor the display to some
conditions that can only be known at display time. Since execution of
arbitrary Lisp opens Emacs to potential attacks, especially when the
source of enriched text is outside of Emacs or even outside of your
system (e.g., if it was received in an email message), such execution
is by default disabled in Enriched mode. You can enable it by
customizing the variable @code{enriched-allow-eval-in-display-props}
to a non-@code{nil} value.
@node Text Based Tables
@section Editing Text-based Tables
@cindex table mode
......
......@@ -4486,6 +4486,17 @@ for the @code{display} property, only one of the values takes effect,
following the rules of @code{get-char-property}. @xref{Examining
Properties}.
@cindex display property, unsafe evaluation
@cindex security, and display specifications
Some of the display specifications allow inclusion of Lisp forms,
which are evaluated at display time. This could be unsafe in certain
situations, e.g., when the display specification was generated by some
external program/agent. Wrapping a display specification in a list
that begins with the special symbol @code{disable-eval}, as in
@w{@code{('disable-eval @var{spec})}}, will disable evaluation of any
Lisp in @var{spec}, while still supporting all the other display
property features.
The rest of this section describes several kinds of
display specifications and what they mean.
......
......@@ -117,6 +117,28 @@ The effect is similar to that of "toolBar" resource on the tool bar.
* Changes in Emacs 26.1
** Security vulnerability related to Enriched Text mode is removed.
+++
*** Enriched Text mode does not evaluate Lisp in 'display' properties.
This feature allows saving 'display' properties as part of text.
Emacs 'display' properties support evaluation of arbitrary Lisp forms
as part of processing the property for display, so displaying Enriched
Text could be vulnerable to executing arbitrary malicious Lisp code
included in the text (e.g., sent as part of an email message).
Therefore, execution of arbitrary Lisp forms in 'display' properties
decoded by Enriched Text mode is now disabled by default. Customize
the new option 'enriched-allow-eval-in-display-props' to a non-nil
value to allow Lisp evaluation in decoded 'display' properties.
This vulnerability was introduced in Emacs 21.1. To work around that
in Emacs versions before 25.3, append the following to your ~/.emacs
init file:
(eval-after-load "enriched"
'(defun enriched-decode-display-prop (start end &optional param)
(list start end)))
+++
** Functions in 'write-contents-functions' can fully short-circuit the
'save-buffer' process. Previously, saving a buffer that was not
......
......@@ -362,12 +362,10 @@
(goto-char (point-max))))
(save-restriction
(narrow-to-region b (point))
;; Disabled in Emacs 25.3 to avoid execution of arbitrary Lisp
;; forms in display properties supported by enriched.el.
;; (when (member type '("enriched" "richtext"))
;; (set-text-properties (point-min) (point-max) nil)
;; (ignore-errors
;; (enriched-decode (point-min) (point-max))))
(when (member type '("enriched" "richtext"))
(set-text-properties (point-min) (point-max) nil)
(ignore-errors
(enriched-decode (point-min) (point-max))))
(mm-handle-set-undisplayer
handle
`(lambda ()
......
......@@ -147,6 +147,22 @@ them and their old values to `enriched-old-bindings'."
:type 'hook
:group 'enriched)
(defcustom enriched-allow-eval-in-display-props nil
"If non-nil allow to evaluate arbitrary forms in display properties.
Enriched mode recognizes display properties of text stored using
an extension command to the text/enriched format, \"x-display\".
These properties must not, by default, include evaluation of
Lisp forms, otherwise they are not applied. Customize this option
to t to turn off this safety feature, and allow Enriched mode to
apply display properties which evaluate arbitrary Lisp forms.
Note, however, that applying unsafe display properties could
execute malicious Lisp code, if that code came from an external source."
:risky t
:type 'boolean
:version "26.1"
:group 'enriched)
(defvar enriched-old-bindings nil
"Store old variable values that we change when entering mode.
The 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."
(error nil)))))
(unless prop
(message "Warning: invalid <x-display> parameter %s" param))
;; Disabled in Emacs 25.3 to avoid execution of arbitrary Lisp
;; forms in display properties stored within enriched text.
;; (list start end 'display prop)))
(list start end)))
(if enriched-allow-eval-in-display-props
(list start end 'display prop)
(list start end 'display (list 'disable-eval prop)))))
;;; enriched.el ends here
......@@ -876,9 +876,9 @@ static int face_before_or_after_it_pos (struct it *, bool);
static ptrdiff_t next_overlay_change (ptrdiff_t);
static int handle_display_spec (struct it *, Lisp_Object, Lisp_Object,
Lisp_Object, struct text_pos *, ptrdiff_t, bool);
static int handle_single_display_spec (struct it *, Lisp_Object,
Lisp_Object, Lisp_Object,
struct text_pos *, ptrdiff_t, int, bool);
static int handle_single_display_spec (struct it *, Lisp_Object, Lisp_Object,
Lisp_Object, struct text_pos *,
ptrdiff_t, int, bool, bool);
static int underlying_face_id (struct it *);
 
#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,
ptrdiff_t bufpos, bool frame_window_p)
{
int replacing = 0;
bool enable_eval = true;
/* Support (disable-eval PROP) which is used by enriched.el. */
if (CONSP (spec) && EQ (XCAR (spec), Qdisable_eval))
{
enable_eval = false;
spec = XCAR (XCDR (spec));
}
 
if (CONSP (spec)
/* Simple specifications. */
......@@ -4771,7 +4779,8 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
{
int rv = handle_single_display_spec (it, XCAR (spec), object,
overlay, position, bufpos,
replacing, frame_window_p);
replacing, frame_window_p,
enable_eval);
if (rv != 0)
{
replacing = rv;
......@@ -4789,7 +4798,8 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
{
int rv = handle_single_display_spec (it, AREF (spec, i), object,
overlay, position, bufpos,
replacing, frame_window_p);
replacing, frame_window_p,
enable_eval);
if (rv != 0)
{
replacing = rv;
......@@ -4802,7 +4812,8 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
}
else
replacing = handle_single_display_spec (it, spec, object, overlay, position,
bufpos, 0, frame_window_p);
bufpos, 0, frame_window_p,
enable_eval);
return replacing;
}
 
......@@ -4847,6 +4858,8 @@ display_prop_end (struct it *it, Lisp_Object object, struct text_pos start_pos)
don't set up IT. In that case, FRAME_WINDOW_P means SPEC
is intended to be displayed in a window on a GUI frame.
 
Enable evaluation of Lisp forms only if ENABLE_EVAL_P is true.
Value is non-zero if something was found which replaces the display
of buffer or string text. */
 
......@@ -4854,7 +4867,7 @@ static int
handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
Lisp_Object overlay, struct text_pos *position,
ptrdiff_t bufpos, int display_replaced,
bool frame_window_p)
bool frame_window_p, bool enable_eval_p)
{
Lisp_Object form;
Lisp_Object location, value;
......@@ -4872,6 +4885,8 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
spec = XCDR (spec);
}
 
if (!NILP (form) && !EQ (form, Qt) && !enable_eval_p)
form = Qnil;
if (!NILP (form) && !EQ (form, Qt))
{
ptrdiff_t count = SPECPDL_INDEX ();
......@@ -4920,7 +4935,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
steps = - steps;
it->face_id = smaller_face (it->f, it->face_id, steps);
}
else if (FUNCTIONP (it->font_height))
else if (FUNCTIONP (it->font_height) && enable_eval_p)
{
/* Call function with current height as argument.
Value is the new height. */
......@@ -4941,7 +4956,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
new_height = (XFLOATINT (it->font_height)
* XINT (f->lface[LFACE_HEIGHT_INDEX]));
}
else
else if (enable_eval_p)
{
/* Evaluate IT->font_height with `height' bound to the
current specified height to get the new height. */
......@@ -32204,6 +32219,10 @@ They are still logged to the *Messages* buffer. */);
DEFSYM (Qfontified, "fontified");
DEFSYM (Qfontification_functions, "fontification-functions");
 
/* Name of the symbol which disables Lisp evaluation in 'display'
properties. This is used by enriched.el. */
DEFSYM (Qdisable_eval, "disable-eval");
/* Name of the face used to highlight trailing whitespace. */
DEFSYM (Qtrailing_whitespace, "trailing-whitespace");
 
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment