aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2012-07-03 13:28:42 +0800
committerChong Yidong2012-07-03 13:28:42 +0800
commita76e6535dc91d65de27f194861a5aa21e9b26365 (patch)
tree0ab4f191fd1a5e6ed1e2582be7f86aa57638440b
parent36429c89cbd7282a7614a358e5edb4d37f4a3f47 (diff)
downloademacs-a76e6535dc91d65de27f194861a5aa21e9b26365.tar.gz
emacs-a76e6535dc91d65de27f194861a5aa21e9b26365.zip
* xml.el: Protect parser against XML bombs.
(xml-entity-expansion-limit): New variable. (xml-parse-string, xml-substitute-special): Use it. (xml-parse-dtd): Avoid infloop if the DTD is not terminated. * test/automated/xml-parse-tests.el: Update testcases.
-rw-r--r--lisp/ChangeLog7
-rw-r--r--lisp/xml.el37
-rw-r--r--test/ChangeLog4
-rw-r--r--test/automated/xml-parse-tests.el19
4 files changed, 59 insertions, 8 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 58cb7e69688..dd136f5b053 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,10 @@
12012-07-03 Chong Yidong <cyd@gnu.org>
2
3 * xml.el: Protect parser against XML bombs.
4 (xml-entity-expansion-limit): New variable.
5 (xml-parse-string, xml-substitute-special): Use it.
6 (xml-parse-dtd): Avoid infloop if the DTD is not terminated.
7
12012-07-03 Glenn Morris <rgm@gnu.org> 82012-07-03 Glenn Morris <rgm@gnu.org>
2 9
3 * progmodes/bug-reference.el (bug-reference-bug-regexp): 10 * progmodes/bug-reference.el (bug-reference-bug-regexp):
diff --git a/lisp/xml.el b/lisp/xml.el
index a3e279b41bd..2595fd572f4 100644
--- a/lisp/xml.el
+++ b/lisp/xml.el
@@ -98,6 +98,13 @@
98 ("amp" . "&#38;")) 98 ("amp" . "&#38;"))
99 "Alist mapping XML entities to their replacement text.") 99 "Alist mapping XML entities to their replacement text.")
100 100
101(defvar xml-entity-expansion-limit 20000
102 "The maximum size of entity reference expansions.
103If the size of the buffer increases by this many characters while
104expanding entity references in a segment of character data, the
105XML parser signals an error. Setting this to nil removes the
106limit (making the parser vulnerable to XML bombs).")
107
101(defvar xml-parameter-entity-alist nil 108(defvar xml-parameter-entity-alist nil
102 "Alist of defined XML parametric entities.") 109 "Alist of defined XML parametric entities.")
103 110
@@ -471,7 +478,7 @@ Return one of:
471 (while (not (looking-at end)) 478 (while (not (looking-at end))
472 (cond 479 (cond
473 ((eobp) 480 ((eobp)
474 (error "XML: (Not Well-Formed) End of buffer while reading element `%s'" 481 (error "XML: (Not Well-Formed) End of document while reading element `%s'"
475 node-name)) 482 node-name))
476 ((looking-at "</") 483 ((looking-at "</")
477 (forward-char 2) 484 (forward-char 2)
@@ -517,6 +524,8 @@ Leave point at the start of the next thing to parse. This
517function can modify the buffer by expanding entity and character 524function can modify the buffer by expanding entity and character
518references." 525references."
519 (let ((start (point)) 526 (let ((start (point))
527 ;; Keep track of the size of the rest of the buffer:
528 (old-remaining-size (- (buffer-size) (point)))
520 ref val) 529 ref val)
521 (while (and (not (eobp)) 530 (while (and (not (eobp))
522 (not (looking-at "<"))) 531 (not (looking-at "<")))
@@ -557,7 +566,13 @@ references."
557 xml-validating-parser 566 xml-validating-parser
558 (error "XML: (Validity) Undefined entity `%s'" ref)) 567 (error "XML: (Validity) Undefined entity `%s'" ref))
559 (replace-match (cdr val) t t) 568 (replace-match (cdr val) t t)
560 (goto-char (match-beginning 0)))))) 569 (goto-char (match-beginning 0))))
570 ;; Check for XML bombs.
571 (and xml-entity-expansion-limit
572 (> (- (buffer-size) (point))
573 (+ old-remaining-size xml-entity-expansion-limit))
574 (error "XML: Entity reference expansion \
575surpassed `xml-entity-expansion-limit'"))))
561 ;; [2.11] Clean up line breaks. 576 ;; [2.11] Clean up line breaks.
562 (let ((end-marker (point-marker))) 577 (let ((end-marker (point-marker)))
563 (goto-char start) 578 (goto-char start)
@@ -689,6 +704,8 @@ This follows the rule [28] in the XML specifications."
689 (while (not (looking-at "\\s-*\\]")) 704 (while (not (looking-at "\\s-*\\]"))
690 (skip-syntax-forward " ") 705 (skip-syntax-forward " ")
691 (cond 706 (cond
707 ((eobp)
708 (error "XML: (Well-Formed) End of document while reading DTD"))
692 ;; Element declaration [45]: 709 ;; Element declaration [45]:
693 ((and (looking-at (eval-when-compile 710 ((and (looking-at (eval-when-compile
694 (concat "<!ELEMENT\\s-+\\(" xml-name-re 711 (concat "<!ELEMENT\\s-+\\(" xml-name-re
@@ -797,9 +814,11 @@ This follows the rule [28] in the XML specifications."
797 (if (re-search-forward parameter-entity-re nil t) 814 (if (re-search-forward parameter-entity-re nil t)
798 (match-beginning 0))))) 815 (match-beginning 0)))))
799 816
800 ;; Anything else: 817 ;; Anything else is garbage (ignored if not validating).
801 (xml-validating-parser 818 (xml-validating-parser
802 (error "XML: (Validity) Invalid DTD item")))) 819 (error "XML: (Validity) Invalid DTD item"))
820 (t
821 (skip-chars-forward "^]"))))
803 822
804 (if (looking-at "\\s-*]>") 823 (if (looking-at "\\s-*]>")
805 (goto-char (match-end 0)))) 824 (goto-char (match-end 0))))
@@ -876,6 +895,7 @@ STRING is assumed to occur in an XML attribute value."
876 (let ((ref-re (eval-when-compile 895 (let ((ref-re (eval-when-compile
877 (concat "&\\(?:#\\(x\\)?\\([0-9]+\\)\\|\\(" 896 (concat "&\\(?:#\\(x\\)?\\([0-9]+\\)\\|\\("
878 xml-name-re "\\)\\);"))) 897 xml-name-re "\\)\\);")))
898 (strlen (length string))
879 children) 899 children)
880 (while (string-match ref-re string) 900 (while (string-match ref-re string)
881 (push (substring string 0 (match-beginning 0)) children) 901 (push (substring string 0 (match-beginning 0)) children)
@@ -891,7 +911,8 @@ STRING is assumed to occur in an XML attribute value."
891 (error "XML: (Validity) Undefined character `x%s'" ref)) 911 (error "XML: (Validity) Undefined character `x%s'" ref))
892 (t xml-undefined-entity)) 912 (t xml-undefined-entity))
893 children) 913 children)
894 (setq string remainder)) 914 (setq string remainder
915 strlen (length string)))
895 ;; [4.4.5] Entity references are "included in literal". 916 ;; [4.4.5] Entity references are "included in literal".
896 ;; Note that we don't need do anything special to treat 917 ;; Note that we don't need do anything special to treat
897 ;; quotes as normal data characters. 918 ;; quotes as normal data characters.
@@ -900,7 +921,11 @@ STRING is assumed to occur in an XML attribute value."
900 (if xml-validating-parser 921 (if xml-validating-parser
901 (error "XML: (Validity) Undefined entity `%s'" ref) 922 (error "XML: (Validity) Undefined entity `%s'" ref)
902 xml-undefined-entity)))) 923 xml-undefined-entity))))
903 (setq string (concat val remainder)))))) 924 (setq string (concat val remainder)))
925 (and xml-entity-expansion-limit
926 (> (length string) (+ strlen xml-entity-expansion-limit))
927 (error "XML: Passed `xml-entity-expansion-limit' while expanding `&%s;'"
928 ref)))))
904 (mapconcat 'identity (nreverse (cons string children)) ""))) 929 (mapconcat 'identity (nreverse (cons string children)) "")))
905 930
906(defun xml-substitute-numeric-entities (string) 931(defun xml-substitute-numeric-entities (string)
diff --git a/test/ChangeLog b/test/ChangeLog
index 3ff7124893a..1e77f972965 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,7 @@
12012-07-03 Chong Yidong <cyd@gnu.org>
2
3 * automated/xml-parse-tests.el (xml-parse-tests--bad-data): New.
4
12012-07-02 Chong Yidong <cyd@gnu.org> 52012-07-02 Chong Yidong <cyd@gnu.org>
2 6
3 * automated/xml-parse-tests.el (xml-parse-tests--data): More 7 * automated/xml-parse-tests.el (xml-parse-tests--data): More
diff --git a/test/automated/xml-parse-tests.el b/test/automated/xml-parse-tests.el
index ec3d7ca3065..ada9bbd4074 100644
--- a/test/automated/xml-parse-tests.el
+++ b/test/automated/xml-parse-tests.el
@@ -55,14 +55,29 @@
55 ("<foo>&#38;amp;</foo>" . ((foo () "&amp;")))) 55 ("<foo>&#38;amp;</foo>" . ((foo () "&amp;"))))
56 "Alist of XML strings and their expected parse trees.") 56 "Alist of XML strings and their expected parse trees.")
57 57
58(defvar xml-parse-tests--bad-data
59 '(;; XML bomb in content
60 "<!DOCTYPE foo [<!ENTITY lol \"lol\"><!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\"><!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">]><foo>&lol2;</foo>"
61 ;; XML bomb in attribute value
62 "<!DOCTYPE foo [<!ENTITY lol \"lol\"><!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\"><!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">]><foo a=\"&lol2;\">!</foo>"
63 ;; Non-terminating DTD
64 "<!DOCTYPE foo [ <!ENTITY b \"B\"><!ENTITY abc \"a&b;c\">"
65 "<!DOCTYPE foo [ <!ENTITY b \"B\"><!ENTITY abc \"a&b;c\">asdf"
66 "<!DOCTYPE foo [ <!ENTITY b \"B\"><!ENTITY abc \"a&b;c\">asdf&abc;")
67 "List of XML strings that should signal an error in the parser")
68
58(ert-deftest xml-parse-tests () 69(ert-deftest xml-parse-tests ()
59 "Test XML parsing." 70 "Test XML parsing."
60 (with-temp-buffer 71 (with-temp-buffer
61 (dolist (test xml-parse-tests--data) 72 (dolist (test xml-parse-tests--data)
62 (erase-buffer) 73 (erase-buffer)
63 (insert (car test)) 74 (insert (car test))
64 (should (equal (cdr test) 75 (should (equal (cdr test) (xml-parse-region))))
65 (xml-parse-region (point-min) (point-max))))))) 76 (let ((xml-entity-expansion-limit 50))
77 (dolist (test xml-parse-tests--bad-data)
78 (erase-buffer)
79 (insert test)
80 (should-error (xml-parse-region))))))
66 81
67;; Local Variables: 82;; Local Variables:
68;; no-byte-compile: t 83;; no-byte-compile: t