aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric M. Ludlam2012-01-13 21:19:25 +0800
committerChong Yidong2012-01-13 21:19:25 +0800
commit6e9ddbb313cf7db66550f93a74cbba12e39e93c0 (patch)
tree75980dee1d1a454da12d6fdd4b377a0e915dad61
parente517eda4d0d6da5d4b8f12be1608fb5e17c455ff (diff)
parenta62d5ee188dcb532088a15b0a2f066d3305b2eda (diff)
downloademacs-6e9ddbb313cf7db66550f93a74cbba12e39e93c0.tar.gz
emacs-6e9ddbb313cf7db66550f93a74cbba12e39e93c0.zip
Fix EDE security flaw involving loading arbitrary Lisp from Project.ede.
* lisp/ede.el (ede-project-directories): New option. (ede-directory-safe-p): Check it. (ede-initialize-state-current-buffer, ede, ede-new) (ede-check-project-directory, ede-rescan-toplevel) (ede-load-project-file, ede-parent-project, ede-current-project): (ede-target-parent): Avoid loading in a project unless it is safe, since it may involve malicious code. This security flaw was pointed out by Hiroshi Oota. * lisp/ede/auto.el (ede-project-autoload): Add safe-p slot. (ede-project-class-files): Projects using Project.ede are unsafe. (ede-auto-load-project): New method. * lisp/ede/simple.el (ede-project-class-files): Mark as unsafe.
-rw-r--r--lisp/cedet/ChangeLog17
-rw-r--r--lisp/cedet/ede.el215
-rw-r--r--lisp/cedet/ede/auto.el28
-rw-r--r--lisp/cedet/ede/simple.el3
4 files changed, 211 insertions, 52 deletions
diff --git a/lisp/cedet/ChangeLog b/lisp/cedet/ChangeLog
index 7d6f9f570ec..f9a546ec894 100644
--- a/lisp/cedet/ChangeLog
+++ b/lisp/cedet/ChangeLog
@@ -1,3 +1,20 @@
12012-01-09 Eric Ludlam <zappo@gnu.org>
2
3 * ede.el (ede-project-directories): New option.
4 (ede-directory-safe-p): Check it.
5 (ede-initialize-state-current-buffer, ede, ede-new)
6 (ede-check-project-directory, ede-rescan-toplevel)
7 (ede-load-project-file, ede-parent-project, ede-current-project):
8 (ede-target-parent): Avoid loading in a project unless it is safe,
9 since it may involve malicious code. This security flaw was
10 pointed out by Hiroshi Oota.
11
12 * ede/auto.el (ede-project-autoload): Add safe-p slot.
13 (ede-project-class-files): Projects using Project.ede are unsafe.
14 (ede-auto-load-project): New method.
15
16 * ede/simple.el (ede-project-class-files): Mark as unsafe.
17
12011-12-19 Sam Steingold <sds@gnu.org> 182011-12-19 Sam Steingold <sds@gnu.org>
2 19
3 * semantic/edit.el (semantic-edits-incremental-parser): Add the 20 * semantic/edit.el (semantic-edits-incremental-parser): Add the
diff --git a/lisp/cedet/ede.el b/lisp/cedet/ede.el
index 5f336df5514..cc8b6f53242 100644
--- a/lisp/cedet/ede.el
+++ b/lisp/cedet/ede.el
@@ -94,6 +94,42 @@ target willing to take the file. 'never means never perform the check."
94 :group 'ede 94 :group 'ede
95 :type 'sexp) ; make this be a list of options some day 95 :type 'sexp) ; make this be a list of options some day
96 96
97(defcustom ede-project-directories nil
98 "Directories in which EDE may search for project files.
99If the value is t, EDE may search in any directory.
100
101If the value is a function, EDE calls that function with one
102argument, the directory name; the function should return t iff
103EDE should look for project files in the directory.
104
105Otherwise, the value should be a list of fully-expanded directory
106names. EDE searches for project files only in those directories.
107If you invoke the commands \\[ede] or \\[ede-new] on a directory
108that is not listed, Emacs will offer to add it to the list.
109
110Any other value disables searching for EDE project files."
111 :group 'ede
112 :type '(choice (const :tag "Any directory" t)
113 (repeat :tag "List of directories"
114 (directory))
115 (function :tag "Predicate"))
116 :version "23.4"
117 :risky t)
118
119(defun ede-directory-safe-p (dir)
120 "Return non-nil if DIR is a safe directory to load projects from.
121Projects that do not load a project definition as Emacs Lisp code
122are safe, and can be loaded automatically. Other project types,
123such as those created with Project.ede files, are safe only if
124specified by `ede-project-directories'."
125 (setq dir (directory-file-name (expand-file-name dir)))
126 ;; Load only if allowed by `ede-project-directories'.
127 (or (eq ede-project-directories t)
128 (and (functionp ede-project-directories)
129 (funcall ede-project-directories dir))
130 (and (listp ede-project-directories)
131 (member dir ede-project-directories))))
132
97 133
98;;; Management variables 134;;; Management variables
99 135
@@ -420,24 +456,42 @@ provided `global-ede-mode' is enabled."
420Sets buffer local variables for EDE." 456Sets buffer local variables for EDE."
421 (let* ((ROOT nil) 457 (let* ((ROOT nil)
422 (proj (ede-directory-get-open-project default-directory 458 (proj (ede-directory-get-open-project default-directory
423 'ROOT))) 459 'ROOT))
460 (projauto nil))
461
424 (when (or proj ROOT 462 (when (or proj ROOT
425 (ede-directory-project-p default-directory t)) 463 ;; If there is no open project, look up the project
464 ;; autoloader to see if we should initialize.
465 (setq projauto (ede-directory-project-p default-directory t)))
466
467 (when (and (not proj) projauto)
468
469 ;; No project was loaded, but we have a project description
470 ;; object. This means that we can check if it is a safe
471 ;; project to load before requesting it to be loaded.
426 472
427 (when (not proj) 473 (when (or (oref projauto safe-p)
428 ;; @todo - this could be wasteful. 474 ;; The project style is not safe, so check if it is
429 (setq proj (ede-load-project-file default-directory 'ROOT))) 475 ;; in `ede-project-directories'.
476 (let ((top (ede-toplevel-project default-directory)))
477 (ede-directory-safe-p top)))
430 478
431 (setq ede-object (ede-buffer-object (current-buffer) 479 ;; The project is safe, so load it in.
480 (setq proj (ede-load-project-file default-directory 'ROOT))))
481
482 ;; Only initialize EDE state in this buffer if we found a project.
483 (when proj
484
485 (setq ede-object (ede-buffer-object (current-buffer)
432 'ede-object-project)) 486 'ede-object-project))
433 487
434 (setq ede-object-root-project 488 (setq ede-object-root-project
435 (or ROOT (ede-project-root ede-object-project))) 489 (or ROOT (ede-project-root ede-object-project)))
436 490
437 (if (and (not ede-object) ede-object-project) 491 (if (and (not ede-object) ede-object-project)
438 (ede-auto-add-to-target)) 492 (ede-auto-add-to-target))
439 493
440 (ede-apply-target-options)))) 494 (ede-apply-target-options)))))
441 495
442(defun ede-reset-all-buffers (onoff) 496(defun ede-reset-all-buffers (onoff)
443 "Reset all the buffers due to change in EDE. 497 "Reset all the buffers due to change in EDE.
@@ -557,13 +611,73 @@ of objects with the `ede-want-file-p' method."
557 611
558;;; Interactive method invocations 612;;; Interactive method invocations
559;; 613;;
560(defun ede (file) 614(defun ede (dir)
561 "Start up EDE on something. 615 "Start up EDE for directory DIR.
562Argument FILE is the file or directory to load a project from." 616If DIR has an existing project file, load it.
563 (interactive "fProject File: ") 617Otherwise, create a new project for DIR."
564 (if (not (file-exists-p file)) 618 (interactive
565 (ede-new file) 619 ;; When choosing a directory to turn on, and we see some directory here,
566 (ede-load-project-file (file-name-directory file)))) 620 ;; provide that as the default.
621 (let* ((top (ede-toplevel-project default-directory))
622 (promptdflt (or top default-directory)))
623 (list (read-directory-name "Project directory: "
624 promptdflt promptdflt t))))
625 (unless (file-directory-p dir)
626 (error "%s is not a directory" dir))
627 (when (ede-directory-get-open-project dir)
628 (error "%s already has an open project associated with it" dir))
629
630 ;; Check if the directory has been added to the list of safe
631 ;; directories. It can also add the directory to the safe list if
632 ;; the user chooses.
633 (if (ede-check-project-directory dir)
634 (progn
635 ;; If there is a project in DIR, load it, otherwise do
636 ;; nothing.
637 (ede-load-project-file dir)
638
639 ;; Check if we loaded anything on the previous line.
640 (if (ede-current-project dir)
641
642 ;; We successfully opened an existing project. Some open
643 ;; buffers may also be referring to this project.
644 ;; Resetting all the buffers will get them to also point
645 ;; at this new open project.
646 (ede-reset-all-buffers 1)
647
648 ;; ELSE
649 ;; There was no project, so switch to `ede-new' which is how
650 ;; a user can select a new kind of project to create.
651 (let ((default-directory (expand-file-name dir)))
652 (call-interactively 'ede-new))))
653
654 ;; If the proposed directory isn't safe, then say so.
655 (error "%s is not an allowed project directory in `ede-project-directories'"
656 dir)))
657
658(defun ede-check-project-directory (dir)
659 "Check if DIR should be in `ede-project-directories'.
660If it is not, try asking the user if it should be added; if so,
661add it and save `ede-project-directories' via Customize.
662Return nil iff DIR should not be in `ede-project-directories'."
663 (setq dir (directory-file-name (expand-file-name dir))) ; strip trailing /
664 (or (eq ede-project-directories t)
665 (and (functionp ede-project-directories)
666 (funcall ede-project-directories dir))
667 ;; If `ede-project-directories' is a list, maybe add it.
668 (when (listp ede-project-directories)
669 (or (member dir ede-project-directories)
670 (when (y-or-n-p (format "`%s' is not listed in `ede-project-directories'.
671Add it to the list of allowed project directories? "
672 dir))
673 (push dir ede-project-directories)
674 ;; If possible, save `ede-project-directories'.
675 (if (or custom-file user-init-file)
676 (let ((coding-system-for-read nil))
677 (customize-save-variable
678 'ede-project-directories
679 ede-project-directories)))
680 t)))))
567 681
568(defun ede-new (type &optional name) 682(defun ede-new (type &optional name)
569 "Create a new project starting from project type TYPE. 683 "Create a new project starting from project type TYPE.
@@ -598,6 +712,11 @@ Optional argument NAME is the name to give this project."
598 (error "Cannot create project in non-existent directory %s" default-directory)) 712 (error "Cannot create project in non-existent directory %s" default-directory))
599 (when (not (file-writable-p default-directory)) 713 (when (not (file-writable-p default-directory))
600 (error "No write permissions for %s" default-directory)) 714 (error "No write permissions for %s" default-directory))
715 (unless (ede-check-project-directory default-directory)
716 (error "%s is not an allowed project directory in `ede-project-directories'"
717 default-directory))
718 ;; Make sure the project directory is loadable in the future.
719 (ede-check-project-directory default-directory)
601 ;; Create the project 720 ;; Create the project
602 (let* ((obj (object-assoc type 'name ede-project-class-files)) 721 (let* ((obj (object-assoc type 'name ede-project-class-files))
603 (nobj (let ((f (oref obj file)) 722 (nobj (let ((f (oref obj file))
@@ -631,6 +750,10 @@ Optional argument NAME is the name to give this project."
631 (ede-add-subproject pp nobj) 750 (ede-add-subproject pp nobj)
632 (ede-commit-project pp))) 751 (ede-commit-project pp)))
633 (ede-commit-project nobj)) 752 (ede-commit-project nobj))
753 ;; Once the project is created, load it again. This used to happen
754 ;; lazily, but with project loading occurring less often and with
755 ;; security in mind, this is now the safe time to reload.
756 (ede-load-project-file default-directory)
634 ;; Have the menu appear 757 ;; Have the menu appear
635 (setq ede-minor-mode t) 758 (setq ede-minor-mode t)
636 ;; Allert the user 759 ;; Allert the user
@@ -653,11 +776,16 @@ ARGS are additional arguments to pass to method SYM."
653(defun ede-rescan-toplevel () 776(defun ede-rescan-toplevel ()
654 "Rescan all project files." 777 "Rescan all project files."
655 (interactive) 778 (interactive)
656 (let ((toppath (ede-toplevel-project default-directory)) 779 (if (not (ede-directory-get-open-project default-directory))
657 (ede-deep-rescan t)) 780 ;; This directory isn't open. Can't rescan.
658 (project-rescan (ede-load-project-file toppath)) 781 (error "Attempt to rescan a project that isn't open")
659 (ede-reset-all-buffers 1) 782
660 )) 783 ;; Continue
784 (let ((toppath (ede-toplevel-project default-directory))
785 (ede-deep-rescan t))
786
787 (project-rescan (ede-load-project-file toppath))
788 (ede-reset-all-buffers 1))))
661 789
662(defun ede-new-target (&rest args) 790(defun ede-new-target (&rest args)
663 "Create a new target specific to this type of project file. 791 "Create a new target specific to this type of project file.
@@ -893,7 +1021,7 @@ Optional ROOTRETURN will return the root project for DIR."
893 ;; Do the load 1021 ;; Do the load
894 ;;(message "EDE LOAD : %S" file) 1022 ;;(message "EDE LOAD : %S" file)
895 (let* ((file dir) 1023 (let* ((file dir)
896 (path (expand-file-name (file-name-directory file))) 1024 (path (file-name-as-directory (expand-file-name dir)))
897 (pfc (ede-directory-project-p path)) 1025 (pfc (ede-directory-project-p path))
898 (toppath nil) 1026 (toppath nil)
899 (o nil)) 1027 (o nil))
@@ -922,13 +1050,11 @@ Optional ROOTRETURN will return the root project for DIR."
922 ;; See if it's been loaded before 1050 ;; See if it's been loaded before
923 (setq o (object-assoc (ede-dir-to-projectfile pfc toppath) 'file 1051 (setq o (object-assoc (ede-dir-to-projectfile pfc toppath) 'file
924 ede-projects)) 1052 ede-projects))
925 (if (not o) 1053
926 ;; If not, get it now. 1054 ;; If not open yet, load it.
927 (let ((ede-constructing pfc)) 1055 (unless o
928 (setq o (funcall (oref pfc load-type) toppath)) 1056 (let ((ede-constructing pfc))
929 (when (not o) 1057 (setq o (ede-auto-load-project pfc toppath))))
930 (error "Project type error: :load-type failed to create a project"))
931 (ede-add-project-to-global-list o)))
932 1058
933 ;; Return the found root project. 1059 ;; Return the found root project.
934 (when rootreturn (set rootreturn o)) 1060 (when rootreturn (set rootreturn o))
@@ -982,13 +1108,7 @@ Optional argument OBJ is an object to find the parent of."
982 (and root 1108 (and root
983 (ede-find-subproject-for-directory root updir)) 1109 (ede-find-subproject-for-directory root updir))
984 ;; Try the all structure based search. 1110 ;; Try the all structure based search.
985 (ede-directory-get-open-project updir) 1111 (ede-directory-get-open-project updir))))))))
986 ;; Load up the project file as a last resort.
987 ;; Last resort since it uses file-truename, and other
988 ;; slow features.
989 (and (ede-directory-project-p updir)
990 (ede-load-project-file
991 (file-name-as-directory updir))))))))))
992 1112
993(defun ede-current-project (&optional dir) 1113(defun ede-current-project (&optional dir)
994 "Return the current project file. 1114 "Return the current project file.
@@ -1002,11 +1122,7 @@ If optional DIR is provided, get the project for DIR instead."
1002 ;; No current project. 1122 ;; No current project.
1003 (when (not ans) 1123 (when (not ans)
1004 (let* ((ldir (or dir default-directory))) 1124 (let* ((ldir (or dir default-directory)))
1005 (setq ans (ede-directory-get-open-project ldir)) 1125 (setq ans (ede-directory-get-open-project ldir))))
1006 (or ans
1007 ;; No open project, if this dir pass project-p, then load.
1008 (when (ede-directory-project-p ldir)
1009 (setq ans (ede-load-project-file ldir))))))
1010 ;; Return what we found. 1126 ;; Return what we found.
1011 ans)) 1127 ans))
1012 1128
@@ -1061,12 +1177,13 @@ If TARGET belongs to a subproject, return that project file."
1061 "Return the project which is the parent of TARGET. 1177 "Return the project which is the parent of TARGET.
1062It is recommended you track the project a different way as this function 1178It is recommended you track the project a different way as this function
1063could become slow in time." 1179could become slow in time."
1064 ;; @todo - use ede-object-project as a starting point. 1180 (or ede-object-project
1065 (let ((ans nil) (projs ede-projects)) 1181 ;; If not cached, derive it from the current directory of the target.
1066 (while (and (not ans) projs) 1182 (let ((ans nil) (projs ede-projects))
1067 (setq ans (ede-target-in-project-p (car projs) target) 1183 (while (and (not ans) projs)
1068 projs (cdr projs))) 1184 (setq ans (ede-target-in-project-p (car projs) target)
1069 ans)) 1185 projs (cdr projs)))
1186 ans)))
1070 1187
1071(defmethod ede-find-target ((proj ede-project) buffer) 1188(defmethod ede-find-target ((proj ede-project) buffer)
1072 "Fetch the target in PROJ belonging to BUFFER or nil." 1189 "Fetch the target in PROJ belonging to BUFFER or nil."
diff --git a/lisp/cedet/ede/auto.el b/lisp/cedet/ede/auto.el
index 7ff291d3675..b458cc246f0 100644
--- a/lisp/cedet/ede/auto.el
+++ b/lisp/cedet/ede/auto.el
@@ -58,6 +58,13 @@ associated with a single object class, based on the initializers used.")
58 :initform t 58 :initform t
59 :documentation 59 :documentation
60 "Non-nil if this is an option when a user creates a project.") 60 "Non-nil if this is an option when a user creates a project.")
61 (safe-p :initarg :safe-p
62 :initform t
63 :documentation
64 "Non-nil if the project load files are \"safe\".
65An unsafe project is one that loads project variables via Emacs
66Lisp code. A safe project is one that loads project variables by
67scanning files without loading Lisp code from them.")
61 ) 68 )
62 "Class representing minimal knowledge set to run preliminary EDE functions. 69 "Class representing minimal knowledge set to run preliminary EDE functions.
63When more advanced functionality is needed from a project type, that projects 70When more advanced functionality is needed from a project type, that projects
@@ -69,13 +76,15 @@ type is required and the load function used.")
69 :name "Make" :file 'ede/proj 76 :name "Make" :file 'ede/proj
70 :proj-file "Project.ede" 77 :proj-file "Project.ede"
71 :load-type 'ede-proj-load 78 :load-type 'ede-proj-load
72 :class-sym 'ede-proj-project) 79 :class-sym 'ede-proj-project
80 :safe-p nil)
73 (ede-project-autoload "edeproject-automake" 81 (ede-project-autoload "edeproject-automake"
74 :name "Automake" :file 'ede/proj 82 :name "Automake" :file 'ede/proj
75 :proj-file "Project.ede" 83 :proj-file "Project.ede"
76 :initializers '(:makefile-type Makefile.am) 84 :initializers '(:makefile-type Makefile.am)
77 :load-type 'ede-proj-load 85 :load-type 'ede-proj-load
78 :class-sym 'ede-proj-project) 86 :class-sym 'ede-proj-project
87 :safe-p nil)
79 (ede-project-autoload "automake" 88 (ede-project-autoload "automake"
80 :name "automake" :file 'ede/project-am 89 :name "automake" :file 'ede/project-am
81 :proj-file "Makefile.am" 90 :proj-file "Makefile.am"
@@ -84,6 +93,8 @@ type is required and the load function used.")
84 :new-p nil)) 93 :new-p nil))
85 "List of vectors defining how to determine what type of projects exist.") 94 "List of vectors defining how to determine what type of projects exist.")
86 95
96(put 'ede-project-class-files 'risky-local-variable t)
97
87;;; EDE project-autoload methods 98;;; EDE project-autoload methods
88;; 99;;
89(defmethod ede-project-root ((this ede-project-autoload)) 100(defmethod ede-project-root ((this ede-project-autoload))
@@ -122,6 +133,19 @@ Return nil if the project file does not exist."
122 (when (and f (file-exists-p f)) 133 (when (and f (file-exists-p f))
123 f))) 134 f)))
124 135
136(defmethod ede-auto-load-project ((this ede-project-autoload) dir)
137 "Load in the project associated with THIS project autoload description.
138THIS project description should be valid for DIR, where the project will
139be loaded."
140 ;; Last line of defense: don't load unsafe projects.
141 (when (not (or (oref this :safe-p)
142 (ede-directory-safe-p dir)))
143 (error "Attempt to load an unsafe project (bug elsewhere in EDE)"))
144 ;; Things are good - so load the project.
145 (let ((o (funcall (oref this load-type) dir)))
146 (when (not o)
147 (error "Project type error: :load-type failed to create a project"))
148 (ede-add-project-to-global-list o)))
125 149
126(provide 'ede/auto) 150(provide 'ede/auto)
127 151
diff --git a/lisp/cedet/ede/simple.el b/lisp/cedet/ede/simple.el
index 028c126e9e4..5cfa750c63f 100644
--- a/lisp/cedet/ede/simple.el
+++ b/lisp/cedet/ede/simple.el
@@ -50,7 +50,8 @@
50 :name "Simple" :file 'ede/simple 50 :name "Simple" :file 'ede/simple
51 :proj-file 'ede-simple-projectfile-for-dir 51 :proj-file 'ede-simple-projectfile-for-dir
52 :load-type 'ede-simple-load 52 :load-type 'ede-simple-load
53 :class-sym 'ede-simple-project) 53 :class-sym 'ede-simple-project
54 :safe-p nil)
54 t) 55 t)
55 56
56(defcustom ede-simple-save-directory "~/.ede" 57(defcustom ede-simple-save-directory "~/.ede"