1 |
ulm 12/01/09 09:38:18 |
2 |
|
3 |
Added: 08_all_ede_security_fix.patch |
4 |
Log: |
5 |
Security fix for EDE, bug 398227. |
6 |
|
7 |
Revision Changes Path |
8 |
1.1 src/patchsets/emacs/23.3/08_all_ede_security_fix.patch |
9 |
|
10 |
file : http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/emacs/23.3/08_all_ede_security_fix.patch?rev=1.1&view=markup |
11 |
plain: http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/emacs/23.3/08_all_ede_security_fix.patch?rev=1.1&content-type=text/plain |
12 |
|
13 |
Index: 08_all_ede_security_fix.patch |
14 |
=================================================================== |
15 |
http://lists.gnu.org/archive/html/emacs-devel/2012-01/msg00387.html |
16 |
https://bugs.gentoo.org/398227 |
17 |
|
18 |
Hiroshi Oota has found a security flaw in EDE (part of CEDET), a |
19 |
development tool included in Emacs. EDE can store various information |
20 |
about a project, such as how to build the project, in a file named |
21 |
Project.ede in the project directory tree. When the minor mode |
22 |
`global-ede-mode' is enabled, visiting a file causes Emacs to look for |
23 |
Project.ede in the file's directory or one of its parent directories. |
24 |
If Project.ede is present, Emacs automatically reads and evaluates the |
25 |
first Lisp expression in it. |
26 |
|
27 |
This design exposes EDE users to the danger of loading malicious code |
28 |
from one file (Project.ede), simply by visiting another file in the same |
29 |
directory tree. |
30 |
|
31 |
A patch to fix this problem, for the Emacs 23.3 release, is attached. |
32 |
It prevents EDE from loading Project.ede files, except in directories |
33 |
explicitly designated as "safe" by the user via the new list variable |
34 |
`ede-project-directories'. The value of this variable is initially the |
35 |
empty list; Emacs offers to add to it when the user invokes the `M-x |
36 |
ede' or `M-x ede-new' command. EDE project types that do not use |
37 |
Project.ede (e.g. those that scan makefiles for build information) are |
38 |
unaffected, since they do not involve loading Lisp code. |
39 |
|
40 |
--- emacs-23.3-orig/lisp/cedet/ede/auto.el |
41 |
+++ emacs-23.3/lisp/cedet/ede/auto.el |
42 |
@@ -58,6 +58,13 @@ |
43 |
:initform t |
44 |
:documentation |
45 |
"Non-nil if this is an option when a user creates a project.") |
46 |
+ (safe-p :initarg :safe-p |
47 |
+ :initform t |
48 |
+ :documentation |
49 |
+ "Non-nil if the project load files are \"safe\". |
50 |
+An unsafe project is one that loads project variables via Emacs |
51 |
+Lisp code. A safe project is one that loads project variables by |
52 |
+scanning files without loading Lisp code from them.") |
53 |
) |
54 |
"Class representing minimal knowledge set to run preliminary EDE functions. |
55 |
When more advanced functionality is needed from a project type, that projects |
56 |
@@ -69,13 +76,15 @@ |
57 |
:name "Make" :file 'ede/proj |
58 |
:proj-file "Project.ede" |
59 |
:load-type 'ede-proj-load |
60 |
- :class-sym 'ede-proj-project) |
61 |
+ :class-sym 'ede-proj-project |
62 |
+ :safe-p nil) |
63 |
(ede-project-autoload "edeproject-automake" |
64 |
:name "Automake" :file 'ede/proj |
65 |
:proj-file "Project.ede" |
66 |
:initializers '(:makefile-type Makefile.am) |
67 |
:load-type 'ede-proj-load |
68 |
- :class-sym 'ede-proj-project) |
69 |
+ :class-sym 'ede-proj-project |
70 |
+ :safe-p nil) |
71 |
(ede-project-autoload "automake" |
72 |
:name "automake" :file 'ede/project-am |
73 |
:proj-file "Makefile.am" |
74 |
@@ -84,6 +93,8 @@ |
75 |
:new-p nil)) |
76 |
"List of vectors defining how to determine what type of projects exist.") |
77 |
|
78 |
+(put 'ede-project-class-files 'risky-local-variable t) |
79 |
+ |
80 |
;;; EDE project-autoload methods |
81 |
;; |
82 |
(defmethod ede-project-root ((this ede-project-autoload)) |
83 |
@@ -122,6 +133,19 @@ |
84 |
(when (and f (file-exists-p f)) |
85 |
f))) |
86 |
|
87 |
+(defmethod ede-auto-load-project ((this ede-project-autoload) dir) |
88 |
+ "Load in the project associated with THIS project autoload description. |
89 |
+THIS project description should be valid for DIR, where the project will |
90 |
+be loaded." |
91 |
+ ;; Last line of defense: don't load unsafe projects. |
92 |
+ (when (not (or (oref this :safe-p) |
93 |
+ (ede-directory-safe-p dir))) |
94 |
+ (error "Attempt to load an unsafe project (bug elsewhere in EDE)")) |
95 |
+ ;; Things are good - so load the project. |
96 |
+ (let ((o (funcall (oref this load-type) dir))) |
97 |
+ (when (not o) |
98 |
+ (error "Project type error: :load-type failed to create a project")) |
99 |
+ (ede-add-project-to-global-list o))) |
100 |
|
101 |
(provide 'ede/auto) |
102 |
|
103 |
--- emacs-23.3-orig/lisp/cedet/ede/simple.el |
104 |
+++ emacs-23.3/lisp/cedet/ede/simple.el |
105 |
@@ -50,7 +50,8 @@ |
106 |
:name "Simple" :file 'ede/simple |
107 |
:proj-file 'ede-simple-projectfile-for-dir |
108 |
:load-type 'ede-simple-load |
109 |
- :class-sym 'ede-simple-project) |
110 |
+ :class-sym 'ede-simple-project |
111 |
+ :safe-p nil) |
112 |
t) |
113 |
|
114 |
(defcustom ede-simple-save-directory "~/.ede" |
115 |
--- emacs-23.3-orig/lisp/cedet/ede.el |
116 |
+++ emacs-23.3/lisp/cedet/ede.el |
117 |
@@ -94,6 +94,42 @@ |
118 |
:group 'ede |
119 |
:type 'sexp) ; make this be a list of options some day |
120 |
|
121 |
+(defcustom ede-project-directories nil |
122 |
+ "Directories in which EDE may search for project files. |
123 |
+If the value is t, EDE may search in any directory. |
124 |
+ |
125 |
+If the value is a function, EDE calls that function with one |
126 |
+argument, the directory name; the function should return t iff |
127 |
+EDE should look for project files in the directory. |
128 |
+ |
129 |
+Otherwise, the value should be a list of fully-expanded directory |
130 |
+names. EDE searches for project files only in those directories. |
131 |
+If you invoke the commands \\[ede] or \\[ede-new] on a directory |
132 |
+that is not listed, Emacs will offer to add it to the list. |
133 |
+ |
134 |
+Any other value disables searching for EDE project files." |
135 |
+ :group 'ede |
136 |
+ :type '(choice (const :tag "Any directory" t) |
137 |
+ (repeat :tag "List of directories" |
138 |
+ (directory)) |
139 |
+ (function :tag "Predicate")) |
140 |
+ :version "23.4" |
141 |
+ :risky t) |
142 |
+ |
143 |
+(defun ede-directory-safe-p (dir) |
144 |
+ "Return non-nil if DIR is a safe directory to load projects from. |
145 |
+Projects that do not load a project definition as Emacs Lisp code |
146 |
+are safe, and can be loaded automatically. Other project types, |
147 |
+such as those created with Project.ede files, are safe only if |
148 |
+specified by `ede-project-directories'." |
149 |
+ (setq dir (directory-file-name (expand-file-name dir))) |
150 |
+ ;; Load only if allowed by `ede-project-directories'. |
151 |
+ (or (eq ede-project-directories t) |
152 |
+ (and (functionp ede-project-directories) |
153 |
+ (funcall ede-project-directories dir)) |
154 |
+ (and (listp ede-project-directories) |
155 |
+ (member dir ede-project-directories)))) |
156 |
+ |
157 |
|
158 |
;;; Management variables |
159 |
|
160 |
@@ -419,24 +455,42 @@ |
161 |
Sets buffer local variables for EDE." |
162 |
(let* ((ROOT nil) |
163 |
(proj (ede-directory-get-open-project default-directory |
164 |
- 'ROOT))) |
165 |
+ 'ROOT)) |
166 |
+ (projauto nil)) |
167 |
+ |
168 |
(when (or proj ROOT |
169 |
- (ede-directory-project-p default-directory t)) |
170 |
+ ;; If there is no open project, look up the project |
171 |
+ ;; autoloader to see if we should initialize. |
172 |
+ (setq projauto (ede-directory-project-p default-directory t))) |
173 |
+ |
174 |
+ (when (and (not proj) projauto) |
175 |
+ |
176 |
+ ;; No project was loaded, but we have a project description |
177 |
+ ;; object. This means that we can check if it is a safe |
178 |
+ ;; project to load before requesting it to be loaded. |
179 |
+ |
180 |
+ (when (or (oref projauto safe-p) |
181 |
+ ;; The project style is not safe, so check if it is |
182 |
+ ;; in `ede-project-directories'. |
183 |
+ (let ((top (ede-toplevel-project default-directory))) |
184 |
+ (ede-directory-safe-p top))) |
185 |
|
186 |
- (when (not proj) |
187 |
- ;; @todo - this could be wasteful. |
188 |
- (setq proj (ede-load-project-file default-directory 'ROOT))) |
189 |
+ ;; The project is safe, so load it in. |
190 |
+ (setq proj (ede-load-project-file default-directory 'ROOT)))) |
191 |
|
192 |
- (setq ede-object (ede-buffer-object (current-buffer) |
193 |
+ ;; Only initialize EDE state in this buffer if we found a project. |
194 |
+ (when proj |
195 |
+ |
196 |
+ (setq ede-object (ede-buffer-object (current-buffer) |
197 |
'ede-object-project)) |
198 |
|
199 |
- (setq ede-object-root-project |
200 |
- (or ROOT (ede-project-root ede-object-project))) |
201 |
+ (setq ede-object-root-project |
202 |
+ (or ROOT (ede-project-root ede-object-project))) |
203 |
|
204 |
- (if (and (not ede-object) ede-object-project) |
205 |
- (ede-auto-add-to-target)) |
206 |
+ (if (and (not ede-object) ede-object-project) |
207 |
+ (ede-auto-add-to-target)) |
208 |
|
209 |
- (ede-apply-target-options)))) |
210 |
+ (ede-apply-target-options))))) |
211 |
|
212 |
(defun ede-reset-all-buffers (onoff) |
213 |
"Reset all the buffers due to change in EDE. |
214 |
@@ -555,13 +609,73 @@ |
215 |
|
216 |
;;; Interactive method invocations |
217 |
;; |
218 |
-(defun ede (file) |
219 |
- "Start up EDE on something. |
220 |
-Argument FILE is the file or directory to load a project from." |
221 |
- (interactive "fProject File: ") |
222 |
- (if (not (file-exists-p file)) |
223 |
- (ede-new file) |
224 |
- (ede-load-project-file (file-name-directory file)))) |
225 |
+(defun ede (dir) |
226 |
+ "Start up EDE for directory DIR. |
227 |
+If DIR has an existing project file, load it. |
228 |
+Otherwise, create a new project for DIR." |
229 |
+ (interactive |
230 |
+ ;; When choosing a directory to turn on, and we see some directory here, |
231 |
+ ;; provide that as the default. |
232 |
+ (let* ((top (ede-toplevel-project default-directory)) |
233 |
+ (promptdflt (or top default-directory))) |
234 |
+ (list (read-directory-name "Project directory: " |
235 |
+ promptdflt promptdflt t)))) |
236 |
+ (unless (file-directory-p dir) |
237 |
+ (error "%s is not a directory" dir)) |
238 |
+ (when (ede-directory-get-open-project dir) |
239 |
+ (error "%s already has an open project associated with it" dir)) |
240 |
+ |
241 |
+ ;; Check if the directory has been added to the list of safe |
242 |
+ ;; directories. It can also add the directory to the safe list if |
243 |
+ ;; the user chooses. |
244 |
+ (if (ede-check-project-directory dir) |
245 |
+ (progn |
246 |
+ ;; If there is a project in DIR, load it, otherwise do |
247 |
+ ;; nothing. |
248 |
+ (ede-load-project-file dir) |
249 |
+ |
250 |
+ ;; Check if we loaded anything on the previous line. |
251 |
+ (if (ede-current-project dir) |
252 |
+ |
253 |
+ ;; We successfully opened an existing project. Some open |
254 |
+ ;; buffers may also be referring to this project. |
255 |
+ ;; Resetting all the buffers will get them to also point |
256 |
+ ;; at this new open project. |
257 |
+ (ede-reset-all-buffers 1) |
258 |
+ |
259 |
+ ;; ELSE |
260 |
+ ;; There was no project, so switch to `ede-new' which is how |
261 |
+ ;; a user can select a new kind of project to create. |
262 |
+ (let ((default-directory (expand-file-name dir))) |
263 |
+ (call-interactively 'ede-new)))) |
264 |
+ |
265 |
+ ;; If the proposed directory isn't safe, then say so. |
266 |
+ (error "%s is not an allowed project directory in `ede-project-directories'" |
267 |
+ dir))) |
268 |
+ |
269 |
+(defun ede-check-project-directory (dir) |
270 |
+ "Check if DIR should be in `ede-project-directories'. |
271 |
+If it is not, try asking the user if it should be added; if so, |
272 |
+add it and save `ede-project-directories' via Customize. |
273 |
+Return nil iff DIR should not be in `ede-project-directories'." |
274 |
+ (setq dir (directory-file-name (expand-file-name dir))) ; strip trailing / |
275 |
+ (or (eq ede-project-directories t) |
276 |
+ (and (functionp ede-project-directories) |
277 |
+ (funcall ede-project-directories dir)) |
278 |
+ ;; If `ede-project-directories' is a list, maybe add it. |
279 |
+ (when (listp ede-project-directories) |
280 |
+ (or (member dir ede-project-directories) |
281 |
+ (when (y-or-n-p (format "`%s' is not listed in `ede-project-directories'. |
282 |
+Add it to the list of allowed project directories? " |
283 |
+ dir)) |
284 |
+ (push dir ede-project-directories) |
285 |
+ ;; If possible, save `ede-project-directories'. |
286 |
+ (if (or custom-file user-init-file) |
287 |
+ (let ((coding-system-for-read nil)) |
288 |
+ (customize-save-variable |
289 |
+ 'ede-project-directories |
290 |
+ ede-project-directories))) |
291 |
+ t))))) |
292 |
|
293 |
(defun ede-new (type &optional name) |
294 |
"Create a new project starting of project type TYPE. |
295 |
@@ -596,6 +710,11 @@ |
296 |
(error "Cannot create project in non-existent directory %s" default-directory)) |
297 |
(when (not (file-writable-p default-directory)) |
298 |
(error "No write permissions for %s" default-directory)) |
299 |
+ (unless (ede-check-project-directory default-directory) |
300 |
+ (error "%s is not an allowed project directory in `ede-project-directories'" |
301 |
+ default-directory)) |
302 |
+ ;; Make sure the project directory is loadable in the future. |
303 |
+ (ede-check-project-directory default-directory) |
304 |
;; Create the project |
305 |
(let* ((obj (object-assoc type 'name ede-project-class-files)) |
306 |
(nobj (let ((f (oref obj file)) |
307 |
@@ -629,6 +748,10 @@ |
308 |
(ede-add-subproject pp nobj) |
309 |
(ede-commit-project pp))) |
310 |
(ede-commit-project nobj)) |
311 |
+ ;; Once the project is created, load it again. This used to happen |
312 |
+ ;; lazily, but with project loading occurring less often and with |
313 |
+ ;; security in mind, this is now the safe time to reload. |
314 |
+ (ede-load-project-file default-directory) |
315 |
;; Have the menu appear |
316 |
(setq ede-minor-mode t) |
317 |
;; Allert the user |
318 |
@@ -651,11 +774,16 @@ |
319 |
(defun ede-rescan-toplevel () |
320 |
"Rescan all project files." |
321 |
(interactive) |
322 |
- (let ((toppath (ede-toplevel-project default-directory)) |
323 |
- (ede-deep-rescan t)) |
324 |
- (project-rescan (ede-load-project-file toppath)) |
325 |
- (ede-reset-all-buffers 1) |
326 |
- )) |
327 |
+ (if (not (ede-directory-get-open-project default-directory)) |
328 |
+ ;; This directory isn't open. Can't rescan. |
329 |
+ (error "Attempt to rescan a project that isn't open") |
330 |
+ |
331 |
+ ;; Continue |
332 |
+ (let ((toppath (ede-toplevel-project default-directory)) |
333 |
+ (ede-deep-rescan t)) |
334 |
+ |
335 |
+ (project-rescan (ede-load-project-file toppath)) |
336 |
+ (ede-reset-all-buffers 1)))) |
337 |
|
338 |
(defun ede-new-target (&rest args) |
339 |
"Create a new target specific to this type of project file. |
340 |
@@ -891,7 +1019,7 @@ |
341 |
;; Do the load |
342 |
;;(message "EDE LOAD : %S" file) |
343 |
(let* ((file dir) |
344 |
- (path (expand-file-name (file-name-directory file))) |
345 |
+ (path (file-name-as-directory (expand-file-name dir))) |
346 |
(pfc (ede-directory-project-p path)) |
347 |
(toppath nil) |
348 |
(o nil)) |
349 |
@@ -920,13 +1048,11 @@ |
350 |
;; See if it's been loaded before |
351 |
(setq o (object-assoc (ede-dir-to-projectfile pfc toppath) 'file |
352 |
ede-projects)) |
353 |
- (if (not o) |
354 |
- ;; If not, get it now. |
355 |
- (let ((ede-constructing pfc)) |
356 |
- (setq o (funcall (oref pfc load-type) toppath)) |
357 |
- (when (not o) |
358 |
- (error "Project type error: :load-type failed to create a project")) |
359 |
- (ede-add-project-to-global-list o))) |
360 |
+ |
361 |
+ ;; If not open yet, load it. |
362 |
+ (unless o |
363 |
+ (let ((ede-constructing pfc)) |
364 |
+ (setq o (ede-auto-load-project pfc toppath)))) |
365 |
|
366 |
;; Return the found root project. |
367 |
(when rootreturn (set rootreturn o)) |
368 |
@@ -980,13 +1106,7 @@ |
369 |
(and root |
370 |
(ede-find-subproject-for-directory root updir)) |
371 |
;; Try the all structure based search. |
372 |
- (ede-directory-get-open-project updir) |
373 |
- ;; Load up the project file as a last resort. |
374 |
- ;; Last resort since it uses file-truename, and other |
375 |
- ;; slow features. |
376 |
- (and (ede-directory-project-p updir) |
377 |
- (ede-load-project-file |
378 |
- (file-name-as-directory updir)))))))))) |
379 |
+ (ede-directory-get-open-project updir)))))))) |
380 |
|
381 |
(defun ede-current-project (&optional dir) |
382 |
"Return the current project file. |
383 |
@@ -1000,11 +1120,7 @@ |
384 |
;; No current project. |
385 |
(when (not ans) |
386 |
(let* ((ldir (or dir default-directory))) |
387 |
- (setq ans (ede-directory-get-open-project ldir)) |
388 |
- (or ans |
389 |
- ;; No open project, if this dir pass project-p, then load. |
390 |
- (when (ede-directory-project-p ldir) |
391 |
- (setq ans (ede-load-project-file ldir)))))) |
392 |
+ (setq ans (ede-directory-get-open-project ldir)))) |
393 |
;; Return what we found. |
394 |
ans)) |
395 |
|
396 |
@@ -1059,12 +1175,13 @@ |
397 |
"Return the project which is the parent of TARGET. |
398 |
It is recommended you track the project a different way as this function |
399 |
could become slow in time." |
400 |
- ;; @todo - use ede-object-project as a starting point. |
401 |
- (let ((ans nil) (projs ede-projects)) |
402 |
- (while (and (not ans) projs) |
403 |
- (setq ans (ede-target-in-project-p (car projs) target) |
404 |
- projs (cdr projs))) |
405 |
- ans)) |
406 |
+ (or ede-object-project |
407 |
+ ;; If not cached, derive it from the current directory of the target. |
408 |
+ (let ((ans nil) (projs ede-projects)) |
409 |
+ (while (and (not ans) projs) |
410 |
+ (setq ans (ede-target-in-project-p (car projs) target) |
411 |
+ projs (cdr projs))) |
412 |
+ ans))) |
413 |
|
414 |
(defmethod ede-find-target ((proj ede-project) buffer) |
415 |
"Fetch the target in PROJ belonging to BUFFER or nil." |