forked from grails/grails-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJavadocFixTool.java
350 lines (335 loc) · 15.3 KB
/
JavadocFixTool.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/*
* Copyright (c) 2013 Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
* License Agreement
*
* PLEASE READ THE FOLLOWING LICENSE TERMS CAREFULLY BEFORE USING THE
* ACCOMPANYING PROGRAM. THESE TERMS CONSTITUTE A LEGAL AGREEMENT BETWEEN
* YOU AND US.
*
* "Oracle" refers to Oracle America, Inc., for and on behalf of itself and its
* subsidiaries and affiliates under common control. "We," "us," and "our"
* refers to Oracle and any Program contributors. "You" and "your" refers to
* the individual or entity that wishes to use the Program. "Program" refers to
* the Java API Documentation Updater Tool, Copyright (c) 2013, Oracle America,
* Inc., and updates or error corrections provided by Oracle or contributors.
*
* WARNING:
* The Program will analyze directory information on your computer
* system and may modify software components on such computer system. You
* should only use the Program on computer systems that you maintain sufficient
* rights to update software components.
*
* If your computer system is owned by a person or entity other than you,
* you should check with such person or entity before using the Program.
*
* It is possible that you may lose some software functionality, and make
* Java API Documentation pages unusable on your computer system after you use
* the Program to update software components.
*
* License Rights and Obligations
* We grant you a perpetual, nonexclusive, limited license to use, modify and
* distribute the Program in binary and/or source code form, only for the
* purpose of analyzing the directory structure of your computer system and
* updating Java API Documentation files. If you distribute the Program, in
* either or both binary or source form, including as modified by you, you
* shall include this License Agreement ("Agreement") with your distribution.
*
* All rights not expressly granted above are hereby reserved. If you want to
* use the Program for any purpose other than as permitted under this
* Agreement, you must obtain a valid license permitting such use from Oracle.
* Neither the name of Oracle nor the names of any Program contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* Ownership and Restrictions
* We retain all ownership and intellectual property rights in the Program as
* provided by us. You retain all ownership and intellectual property rights
* in your modifications.
*
* Export
* You agree to comply fully with export laws and regulations of the United
* States and any other applicable export laws ("Export Laws") to assure that
* neither the Program nor any direct products thereof are: (1) exported,
* directly or indirectly, in violation of this Agreement or Export Laws; or
* (2) used for any purposes prohibited by the Export Laws, including, without
* limitation, nuclear, chemical, or biological weapons proliferation, or
* development of missile technology.
*
* Disclaimer of Warranty and Limitation of Liability
* THE PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. USE AT YOUR
* OWN RISK. WE FURTHER DISCLAIM ALL WARRANTIES, EXPRESS AND IMPLIED,
* INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
*
* IN NO EVENT SHALL WE BE LIABLE FOR ANY INDIRECT, DIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOSS OF PROFITS,
* REVENUE, DATA OR DATA USE, INCURRED BY YOU OR ANY THIRD PARTY, WHETHER IN AN
* ACTION IN CONTRACT OR TORT, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGES. ORACLE SHALL HAVE NO LIABILITY FOR MODIFICATIONS MADE BY
* YOU OR ANY THIRD PARTY.
*
* Entire Agreement
* You agree that this Agreement is the complete agreement for the Program, and
* this Agreement supersedes all prior or contemporaneous agreements or
* representations. If any term of this Agreement is found to be invalid or
* unenforceable, the remaining provisions will remain effective. This
* Agreement is governed by the substantive and procedural laws of California.
* You and Oracle agree to submit to the exclusive jurisdiction of, and venue
* in, the courts of San Francisco or Santa Clara counties in California in
* any dispute between you and Oracle arising out of or relating to this
* Agreement.
*
* Last updated: 14 June 2013
*/
import java.io.*;
/*
* Tool for finding and addressing files related to CVE-2013-1571.
* See README file for details.
*/
public class JavadocFixTool {
// Usual suspects
private final static String[] fileNames = {"index.html",
"index.htm",
"toc.html",
"toc.htm"};
// If we locate this function but not validURL - we are in trouble
private final String patchString = "function loadFrames() {";
// Main fix - should be inserted before the loadFrames() function alongside
// the code that calls this function
private final static String[] patchData =
{" if (targetPage != \"\" && !validURL(targetPage))",
" targetPage = \"undefined\";",
" function validURL(url) {",
" var pos = url.indexOf(\".html\");",
" if (pos == -1 || pos != url.length - 5)",
" return false;",
" var allowNumber = false;",
" var allowSep = false;",
" var seenDot = false;",
" for (var i = 0; i < url.length - 5; i++) {",
" var ch = url.charAt(i);",
" if ('a' <= ch && ch <= 'z' ||",
" 'A' <= ch && ch <= 'Z' ||",
" ch == '$' ||",
" ch == '_') {",
" allowNumber = true;",
" allowSep = true;",
" } else if ('0' <= ch && ch <= '9'",
" || ch == '-') {",
" if (!allowNumber)",
" return false;",
" } else if (ch == '/' || ch == '.') {",
" if (!allowSep)",
" return false;",
" allowNumber = false;",
" allowSep = false;",
" if (ch == '.')",
" seenDot = true;",
" if (ch == '/' && seenDot)",
" return false;",
" } else {",
" return false;",
" }",
" }",
" return true;",
" }",
" function loadFrames() {"};
private final String quickFixString = "if (!(url.indexOf(\".html\") == url.length - 5))";
private final String[] quickFix = {" var pos = url.indexOf(\".html\");",
" if (pos == -1 || pos != url.length - 5)"};
private static String readme = null;
private static String version = "Java Documentation Updater Tool version 1.2 06/14/2013\n";
private static boolean doPatch = true; // By default patch file
private static boolean recursive = false; // By default only look in the folder in parameter
public static void main(String[] args) {
System.out.println(version);
if (args.length < 1) {
// No arguments - lazily initialize readme, print readme and usage
initReadme();
if (readme != null) {
System.out.println(readme);
}
printUsage(System.out);
return;
}
// Last argument should be a path to the document root
String name = args[args.length-1];
// Analyze the rest of parameters
for (int i = 0 ; i < args.length -1; i++) {
if ("-R".equalsIgnoreCase(args[i])) {
recursive = true;
} else if ("-C".equalsIgnoreCase(args[i])) {
doPatch = false;
} else {
System.err.println("Unknown option passed: "+args[i]);
printUsage(System.err);
return;
}
}
new JavadocFixTool().proceed(name);
}
/*
* Print usage information into the provided PrintStream
* @param out PrintStream to write usage information
*/
public static void printUsage(PrintStream out) {
out.println("Usage: java -jar JavadocPatchTool.jar [-R] [-C] <Path to Javadoc root>");
out.println(" -R : Proceed recursively starting from given folder");
out.println(" -C : Check only - program will find vulnerable files and print their full paths");
}
/*
* Lazily initialize the readme document, reading it from README file inside the jar
*/
public static void initReadme() {
try {
InputStream readmeStream = JavadocFixTool.class.getResourceAsStream("/README");
if (readmeStream != null) {
BufferedReader readmeReader = new BufferedReader(new InputStreamReader(readmeStream));
StringBuilder readmeBuilder = new StringBuilder();
String s;
while ((s = readmeReader.readLine()) != null) {
readmeBuilder.append(s);
readmeBuilder.append("\n");
}
readme = readmeBuilder.toString();
}
} catch (IOException ignore) {} // Ignore exception - readme not initialized
}
/*
* Main procedure - proceed with the searching and/or fixing depending on
* the command line parameters
* @param name Path to the document root
*/
public void proceed(String name) {
try {
File folder = new File(name);
if (folder.exists() && folder.isDirectory() && folder.canRead()) {
searchAndPatch(folder);
} else {
System.err.println("Invalid folder in parameter \""+name+"\"");
printUsage(System.err);
}
} catch (Exception ignored) {} // Die silently
}
/*
* Find all the files that match the list given in the fileNames array.
* If file found attempt to patch it.
* If global parameter recursive is set to true attempt to go into the enclosed subfolders
* otherwise only patch said files in the folder directly pointed in parameter.
*/
public void searchAndPatch(File folder) {
if (folder == null || !folder.isDirectory() || folder.list() == null) {
// Silently return
return;
}
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
if(recursive) {
searchAndPatch(file);
}
continue;
}
String name = file.getName();
for (String s : fileNames) {
if (s.equalsIgnoreCase(name)) {
try {
applyPatch(file, folder);
} catch (Exception ex) {
String filePath;
try {
filePath = file.getCanonicalPath();
} catch (IOException ioe) {
System.err.println("Can not resolve path to "+file.getName()+" in folder "+folder.getName());
continue;
}
System.err.println("Patch failed on: "+filePath+" due to the "+ex);
}
}
}
}
}
/*
* Try to apply patch to the single file in the specific folder
* If global parameter doPatch is false we should only print the location of the vulnerable html file
* and return
*/
public void applyPatch(File file, File currentFolder) throws Exception {
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String line;
String failedString = patchString;
String[] patch = patchData;
// Attempt to look if file is vulnerable
for (int i = 0 ; i < 80 ; i++) { // Check first 80 lines - if there is no signature it is not our file
line = br.readLine();
if (line == null) {
// File less than 80 lines long, no signature encountered
return;
}
if (line.trim().equals("function validURL(url) {")) { // Already patched
failedString = null;
patch = null;
continue;
}
if (line.trim().equals(quickFixString)) { // The patch had famous 2-letter bug, update it
failedString = quickFixString;
patch = quickFix;
continue;
}
if (line.trim().equals("function loadFrames() {")) {
fis.close(); // It should not interfere with the file renaming process
if (failedString != null) {
// Vulnerable file
if (!doPatch) { // Report and return
System.out.println("Vulnerable file found: "+file.getCanonicalPath());
} else {
replaceStringInFile(currentFolder, file, failedString, patch);
}
}
return;
}
}
}
/*
* Replace one line in the given file in the given folder with the lines given
* @param folder Folder in which file should be created
* @param file Original file to patch
* @param template Trimmed String with the pattern we are have to find
* @param replacement Array of String that has to be written in the place of first line matching the template
*/
public void replaceStringInFile(File folder, File file, String template, String[] replacement)
throws IOException {
System.out.println("Patching file: "+file.getCanonicalPath());
String name = file.getName();
File origFile = new File(folder, name+".orig");
file.renameTo(origFile);
File temporaryFile = new File(folder, name+".tmp");
if (temporaryFile.exists()) {
temporaryFile.delete();
}
temporaryFile.createNewFile();
String line;
FileInputStream fis = new FileInputStream(origFile);
PrintWriter pw = new PrintWriter(temporaryFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
while ((line = br.readLine()) != null) {
if (line.trim().equals(template)) {
for (String s : replacement) {
pw.println(s);
}
} else {
pw.println(line);
}
}
pw.flush();
pw.close();
if (!temporaryFile.renameTo(new File(folder, name))) {
throw new IOException("Unable to rename file in folder "+folder.getName()+
" from \""+temporaryFile.getName()+"\" into \""+name +
"\n Original file saved as "+origFile.getName());
}
origFile.delete();
}
}