Gentoo Archives: gentoo-commits

From: "Ulrich Mueller (ulm)" <ulm@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo commit in src/patchsets/emacs/23.3: 08_all_ede_security_fix.patch
Date: Mon, 09 Jan 2012 09:38:28
Message-Id: 20120109093818.78C5E2004B@flycatcher.gentoo.org
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."