1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.security.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assume.assumeTrue;
22 
23 import com.android.compatibility.common.util.MetricsReportLog;
24 import com.android.compatibility.common.util.ResultType;
25 import com.android.compatibility.common.util.ResultUnit;
26 import com.android.ddmlib.CollectingOutputReceiver;
27 import com.android.ddmlib.IShellOutputReceiver;
28 import com.android.ddmlib.NullOutputReceiver;
29 import com.android.sts.common.tradefed.testtype.SecurityTestCase;
30 import com.android.sts.common.util.TombstoneUtils;
31 import com.android.tradefed.device.DeviceNotAvailableException;
32 import com.android.tradefed.device.ITestDevice;
33 import com.android.tradefed.log.LogUtil.CLog;
34 
35 import java.io.BufferedOutputStream;
36 import java.io.File;
37 import java.io.FileOutputStream;
38 import java.io.InputStream;
39 import java.io.OutputStream;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.concurrent.TimeUnit;
46 import java.util.regex.Matcher;
47 import java.util.regex.Pattern;
48 
49 public class AdbUtils {
50 
51     final static String TMP_PATH = "/data/local/tmp/";
52     final static int TIMEOUT_SEC = 9 * 60;
53     final static String RESOURCE_ROOT = "/";
54 
55     final static String regexSpecialChars = "<([{\\^-=$!|]})?*+.>";
56     @SuppressWarnings("InvalidPatternSyntax") // the errorprone test is incorrect for the following
57     final static String regexSpecialCharsEscaped = regexSpecialChars.replaceAll(".", "\\\\$0");
58     final static Pattern regexSpecialCharsEscapedPattern =
59             Pattern.compile("[" + regexSpecialCharsEscaped + "]");
60 
61     /**
62      * @deprecated Use {@link NativePoc} instead.
63      */
64     @Deprecated
65     public static class pocConfig {
66         String binaryName;
67         String arguments;
68         Map<String, String> envVars;
69         String inputFilesDestination;
70         ITestDevice device;
71         TombstoneUtils.Config config = new TombstoneUtils.Config();
72         List<String> inputFiles = Collections.emptyList();
73 
pocConfig(String binaryName, ITestDevice device)74         pocConfig(String binaryName, ITestDevice device) {
75             this.binaryName = binaryName;
76             this.device = device;
77         }
78     }
79 
80     /**
81      * Runs a commandline on the specified device
82      *
83      * @deprecated Use {@link CommandUtil} instead.
84      * @param command the command to be ran
85      * @param device device for the command to be ran on
86      * @return the console output from running the command
87      */
88     @Deprecated
runCommandLine(String command, ITestDevice device)89     public static String runCommandLine(String command, ITestDevice device) throws Exception {
90         if ("reboot".equals(command)) {
91             throw new IllegalArgumentException(
92                     "You called a forbidden command! Please fix your tests.");
93         }
94         return device.executeShellCommand(command);
95     }
96 
97     /**
98      * Pushes and runs a binary to the selected device
99      *
100      * @deprecated Use {@link NativePoc} instead.
101      * @param pocName name of the poc binary
102      * @param device device to be ran on
103      * @return the console output from the binary
104      */
105     @Deprecated
runPoc(String pocName, ITestDevice device)106     public static String runPoc(String pocName, ITestDevice device) throws Exception {
107         return runPoc(pocName, device, SecurityTestCase.TIMEOUT_NONDETERMINISTIC);
108     }
109 
110     /**
111      * Pushes and runs a binary to the selected device
112      *
113      * @deprecated Use {@link NativePoc} instead.
114      * @param pocName name of the poc binary
115      * @param device device to be ran on
116      * @param timeout time to wait for output in seconds
117      * @return the console output from the binary
118      */
119     @Deprecated
runPoc(String pocName, ITestDevice device, int timeout)120     public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception {
121         return runPoc(pocName, device, timeout, null);
122     }
123 
124     /**
125      * Pushes and runs a binary to the selected device
126      *
127      * @deprecated Use {@link NativePoc} instead.
128      * @param pocName name of the poc binary
129      * @param device device to be ran on
130      * @param timeout time to wait for output in seconds
131      * @param arguments the input arguments for the poc
132      * @return the console output from the binary
133      */
134     @Deprecated
runPoc(String pocName, ITestDevice device, int timeout, String arguments)135     public static String runPoc(String pocName, ITestDevice device, int timeout, String arguments)
136             throws Exception {
137         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
138         runPoc(pocName, device, timeout, arguments, receiver);
139         return receiver.getOutput();
140     }
141 
142     /**
143      * Pushes and runs a binary to the selected device and ignores any of its output.
144      *
145      * @deprecated Use {@link NativePoc} instead.
146      * @param pocName name of the poc binary
147      * @param device device to be ran on
148      * @param timeout time to wait for output in seconds
149      */
150     @Deprecated
runPocNoOutput(String pocName, ITestDevice device, int timeout)151     public static void runPocNoOutput(String pocName, ITestDevice device, int timeout)
152             throws Exception {
153         runPocNoOutput(pocName, device, timeout, null);
154     }
155 
156     /**
157      * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
158      *
159      * @deprecated Use {@link NativePoc} instead.
160      * @param pocName name of the poc binary
161      * @param device device to be ran on
162      * @param timeout time to wait for output in seconds
163      * @param arguments input arguments for the poc
164      */
165     @Deprecated
runPocNoOutput( String pocName, ITestDevice device, int timeout, String arguments)166     public static void runPocNoOutput(
167             String pocName, ITestDevice device, int timeout, String arguments) throws Exception {
168         runPoc(pocName, device, timeout, arguments, null);
169     }
170 
171     /**
172      * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
173      *
174      * @deprecated Use {@link NativePoc} instead.
175      * @param pocName name of the poc binary
176      * @param device device to be ran on
177      * @param timeout time to wait for output in seconds
178      * @param arguments input arguments for the poc
179      * @param receiver the type of receiver to run against
180      */
181     @Deprecated
runPoc( String pocName, ITestDevice device, int timeout, String arguments, IShellOutputReceiver receiver)182     public static int runPoc(
183             String pocName,
184             ITestDevice device,
185             int timeout,
186             String arguments,
187             IShellOutputReceiver receiver)
188             throws Exception {
189               return runPoc(pocName, device, timeout, arguments, null, receiver);
190     }
191 
192     /**
193      * Pushes and runs a binary with arguments to the selected device and ignores any of its output.
194      *
195      * @deprecated Use {@link NativePoc} instead.
196      * @param pocName name of the poc binary
197      * @param device device to be ran on
198      * @param timeout time to wait for output in seconds
199      * @param arguments input arguments for the poc
200      * @param envVars run the poc with environment variables
201      * @param receiver the type of receiver to run against
202      */
203     @Deprecated
runPoc( String pocName, ITestDevice device, int timeout, String arguments, Map<String, String> envVars, IShellOutputReceiver receiver)204     public static int runPoc(
205             String pocName,
206             ITestDevice device,
207             int timeout,
208             String arguments,
209             Map<String, String> envVars,
210             IShellOutputReceiver receiver)
211             throws Exception {
212         String remoteFile = String.format("%s%s", TMP_PATH, pocName);
213         SecurityTestCase.getPocPusher(device).pushFile(pocName + "_sts", remoteFile);
214 
215         assertPocExecutable(pocName, device);
216         if (receiver == null) {
217             receiver = new NullOutputReceiver();
218         }
219         if (arguments == null) {
220             arguments = "";
221         }
222 
223         String env = "";
224         if (envVars != null) {
225             StringBuilder sb = new StringBuilder();
226             for (Map.Entry<String, String> entry : envVars.entrySet()) {
227                 sb
228                     .append(entry.getKey().trim())
229                     .append('=')
230                     .append(entry.getValue().trim())
231                     .append(' ');
232             }
233             env = sb.toString();
234             CLog.i("Running poc '%s' with env variables '%s'", pocName, env);
235         }
236 
237         // since we have to return the exit status AND the poc stdout+stderr we redirect the exit
238         // status to a file temporarily
239         String exitStatusFilepath = TMP_PATH + "exit_status";
240         runCommandLine("rm " + exitStatusFilepath, device); // remove any old exit status
241         device.executeShellCommand(
242                 env + TMP_PATH + pocName + " " + arguments +
243                 "; echo $? > " + exitStatusFilepath, // echo exit status to file
244                 receiver, timeout, TimeUnit.SECONDS, 0);
245 
246         // cat the exit status
247         String exitStatusString = runCommandLine("cat " + exitStatusFilepath, device).trim();
248 
249         MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
250         reportLog.addValue("poc_name", pocName, ResultType.NEUTRAL, ResultUnit.NONE);
251         int exitStatus = -1;
252         try {
253             exitStatus = Integer.parseInt(exitStatusString);
254             reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
255         } catch (NumberFormatException e) {
256             // Getting the exit status is a bonus. We can continue without it.
257             CLog.w("Could not parse exit status to int: %s", exitStatusString);
258         }
259         reportLog.submit();
260 
261         runCommandLine("rm " + exitStatusFilepath, device);
262         return exitStatus;
263     }
264 
265     /**
266      * Assert the poc is executable
267      *
268      * @deprecated Use {@link NativePoc} instead.
269      * @param pocName name of the poc binary
270      * @param device device to be ran on
271      */
272     @Deprecated
assertPocExecutable(String pocName, ITestDevice device)273     private static void assertPocExecutable(String pocName, ITestDevice device) throws Exception {
274         String fullPocPath = TMP_PATH + pocName;
275         device.executeShellCommand("chmod 777 " + fullPocPath);
276         assertEquals("'" + pocName + "' must exist and be readable.", 0,
277                 runCommandGetExitCode("test -r " + fullPocPath, device));
278         assertEquals("'" + pocName + "'poc must exist and be writable.", 0,
279                 runCommandGetExitCode("test -w " + fullPocPath, device));
280         assertEquals("'" + pocName + "'poc must exist and be executable.", 0,
281                 runCommandGetExitCode("test -x " + fullPocPath, device));
282     }
283 
284     /**
285      * Pushes and installs an apk to the selected device
286      *
287      * @param pathToApk a string path to apk from the /res folder
288      * @param device device to be ran on
289      * @return the output from attempting to install the apk
290      */
installApk(String pathToApk, ITestDevice device)291     public static String installApk(String pathToApk, ITestDevice device) throws Exception {
292 
293         String fullResourceName = pathToApk;
294         File apkFile = File.createTempFile("apkFile", ".apk");
295         try {
296             apkFile = extractResource(fullResourceName, apkFile);
297             return device.installPackage(apkFile, true);
298         } finally {
299             apkFile.delete();
300         }
301     }
302 
303     /**
304      * Extracts a resource and pushes it to the device
305      *
306      * @param fullResourceName a string path to resource from the res folder
307      * @param deviceFilePath the remote destination absolute file path
308      * @param device device to be ran on
309      */
pushResource(String fullResourceName, String deviceFilePath, ITestDevice device)310     public static void pushResource(String fullResourceName, String deviceFilePath,
311                                     ITestDevice device) throws Exception {
312         File resFile = File.createTempFile("CTSResource", "");
313         try {
314             resFile = extractResource(fullResourceName, resFile);
315             device.pushFile(resFile, deviceFilePath);
316         } finally {
317             resFile.delete();
318         }
319     }
320 
321     /**
322      * Pushes the specified files to the specified destination directory
323      *
324      * @param inputFiles files required as input
325      * @param inputFilesDestination destination directory to which input files are
326      *        pushed
327      * @param device device to be run on
328      */
pushResources(String[] inputFiles, String inputFilesDestination, ITestDevice device)329     public static void pushResources(String[] inputFiles, String inputFilesDestination,
330             ITestDevice device) throws Exception {
331         if (inputFiles == null || inputFilesDestination == null) {
332             throw new IllegalArgumentException(
333                     "Can't push resources: input files or destination is null");
334         }
335         for (String tempFile : inputFiles) {
336             pushResource(RESOURCE_ROOT + tempFile, inputFilesDestination + tempFile, device);
337         }
338     }
339 
340     /**
341      * Removes the specified files from the specified destination directory
342      *
343      * @param inputFiles files required as input
344      * @param inputFilesDestination destination directory where input files are
345      *        present
346      * @param device device to be run on
347      */
removeResources(String[] inputFiles, String inputFilesDestination, ITestDevice device)348     public static void removeResources(String[] inputFiles, String inputFilesDestination,
349             ITestDevice device) throws Exception {
350         if (inputFiles == null || inputFilesDestination == null) {
351             throw new IllegalArgumentException(
352                     "Can't remove resources: input files or destination is null");
353         }
354         for (String tempFile : inputFiles) {
355             runCommandLine("rm " + inputFilesDestination + tempFile, device);
356         }
357     }
358 
359    /**
360      * Extracts the binary data from a resource and writes it to a temp file
361      */
extractResource(String fullResourceName, File file)362     private static File extractResource(String fullResourceName, File file) throws Exception {
363         try (InputStream in = AdbUtils.class.getResourceAsStream(fullResourceName);
364             OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
365             if (in == null) {
366                 throw new IllegalArgumentException("Resource not found: " + fullResourceName);
367             }
368             byte[] buf = new byte[65536];
369             int chunkSize;
370             while ((chunkSize = in.read(buf)) != -1) {
371                 out.write(buf, 0, chunkSize);
372             }
373             return file;
374         }
375 
376     }
377     /**
378      * Utility function to help check the exit code of a shell command
379      *
380      * @deprecated Use {@link CommandUtil} instead.
381      */
382     @Deprecated
runCommandGetExitCode(String cmd, ITestDevice device)383     public static int runCommandGetExitCode(String cmd, ITestDevice device) throws Exception {
384         long time = System.currentTimeMillis();
385         String exitStatusString = runCommandLine(
386                 "(" + cmd + ") > /dev/null 2>&1; echo $?", device).trim();
387         time = System.currentTimeMillis() - time;
388 
389         try {
390             int exitStatus = Integer.parseInt(exitStatusString);
391             MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
392             reportLog.addValue("command", cmd, ResultType.NEUTRAL, ResultUnit.NONE);
393             reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
394             reportLog.submit();
395             return exitStatus;
396         } catch (NumberFormatException e) {
397             throw new IllegalArgumentException(String.format(
398                     "Could not get the exit status (%s) for '%s' (%d ms).",
399                     exitStatusString, cmd, time));
400         }
401     }
402 
403     /**
404      * Pushes and runs a binary to the selected device and checks exit code Return code 113 is used
405      * to indicate the vulnerability
406      *
407      * @deprecated Use {@link NativePoc} instead.
408      * @param pocName a string path to poc from the /res folder
409      * @param device device to be ran on
410      * @param timeout time to wait for output in seconds
411      */
412     @Deprecated
runPocCheckExitCode(String pocName, ITestDevice device, int timeout)413     public static boolean runPocCheckExitCode(String pocName, ITestDevice device, int timeout)
414             throws Exception {
415 
416        //Refer to go/asdl-sts-guide Test section for knowing the significance of 113 code
417        return runPocGetExitStatus(pocName, device, timeout) == 113;
418     }
419 
420     /**
421      * Pushes and runs a binary to the device and returns the exit status.
422      *
423      * @deprecated Use {@link NativePoc} instead.
424      * @param pocName a string path to poc from the /res folder
425      * @param device device to be ran on
426      * @param timeout time to wait for output in seconds
427      */
428     @Deprecated
runPocGetExitStatus(String pocName, ITestDevice device, int timeout)429     public static int runPocGetExitStatus(String pocName, ITestDevice device, int timeout)
430             throws Exception {
431        return runPocGetExitStatus(pocName, null, device, timeout);
432     }
433 
434     /**
435      * Pushes and runs a binary to the device and returns the exit status.
436      *
437      * @deprecated Use {@link NativePoc} instead.
438      * @param pocName a string path to poc from the /res folder
439      * @param arguments input arguments for the poc
440      * @param device device to be ran on
441      * @param timeout time to wait for output in seconds
442      */
443     @Deprecated
runPocGetExitStatus( String pocName, String arguments, ITestDevice device, int timeout)444     public static int runPocGetExitStatus(
445             String pocName, String arguments, ITestDevice device, int timeout) throws Exception {
446               return runPocGetExitStatus(pocName, arguments, null, device, timeout);
447     }
448 
449     /**
450      * Pushes and runs a binary to the device and returns the exit status.
451      *
452      * @deprecated Use {@link NativePoc} instead.
453      * @param pocName name of the poc binary
454      * @param arguments input arguments for the poc
455      * @param envVars run the poc with environment variables
456      * @param device device to be run on
457      * @param timeout time to wait for output in seconds
458      */
459     @Deprecated
runPocGetExitStatus( String pocName, String arguments, Map<String, String> envVars, ITestDevice device, int timeout)460     public static int runPocGetExitStatus(
461             String pocName,
462             String arguments,
463             Map<String, String> envVars,
464             ITestDevice device,
465             int timeout)
466             throws Exception {
467         return runPoc(pocName, device, timeout, arguments, envVars, null);
468     }
469 
470     /**
471      * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
472      *
473      * @deprecated Use {@link NativePoc} instead.
474      * @param pocName a string path to poc from the /res folder
475      * @param device device to be ran on
476      * @param timeout time to wait for output in seconds
477      */
478     @Deprecated
runPocAssertExitStatusNotVulnerable( String pocName, ITestDevice device, int timeout)479     public static void runPocAssertExitStatusNotVulnerable(
480             String pocName, ITestDevice device, int timeout) throws Exception {
481         runPocAssertExitStatusNotVulnerable(pocName, null, device, timeout);
482     }
483 
484     /**
485      * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
486      *
487      * @deprecated Use {@link NativePoc} instead.
488      * @param pocName a string path to poc from the /res folder
489      * @param arguments input arguments for the poc
490      * @param device device to be ran on
491      * @param timeout time to wait for output in seconds
492      */
493     @Deprecated
runPocAssertExitStatusNotVulnerable( String pocName, String arguments, ITestDevice device, int timeout)494     public static void runPocAssertExitStatusNotVulnerable(
495             String pocName, String arguments, ITestDevice device, int timeout) throws Exception {
496         runPocAssertExitStatusNotVulnerable(pocName, arguments, null, device, timeout);
497     }
498 
499     /**
500      * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
501      *
502      * @deprecated Use {@link NativePoc} instead.
503      * @param pocName name of the poc binary
504      * @param arguments input arguments for the poc
505      * @param envVars run the poc with environment variables
506      * @param device device to be ran on
507      * @param timeout time to wait for output in seconds
508      */
509     @Deprecated
runPocAssertExitStatusNotVulnerable( String pocName, String arguments, Map<String, String> envVars, ITestDevice device, int timeout)510     public static void runPocAssertExitStatusNotVulnerable(
511             String pocName,
512             String arguments,
513             Map<String, String> envVars,
514             ITestDevice device,
515             int timeout)
516             throws Exception {
517         assertTrue("PoC returned exit status 113: vulnerable",
518                 runPocGetExitStatus(pocName, arguments, envVars, device, timeout) != 113);
519     }
520 
521     /**
522      * Runs the poc binary and asserts that there are no security crashes that match the expected
523      * process pattern.
524      *
525      * @deprecated Use {@link NativePoc} instead.
526      * @param pocName a string path to poc from the /res folder
527      * @param device device to be ran on
528      * @param processPatternStrings a Pattern string to match the crash tombstone process
529      */
530     @Deprecated
runPocAssertNoCrashes( String pocName, ITestDevice device, String... processPatternStrings)531     public static void runPocAssertNoCrashes(
532             String pocName, ITestDevice device, String... processPatternStrings) throws Exception {
533         runPocAssertNoCrashes(pocName, device,
534                 new TombstoneUtils.Config().setProcessPatterns(processPatternStrings));
535     }
536 
537     /**
538      * Runs the poc binary and asserts that there are no security crashes that match the expected
539      * process pattern.
540      *
541      * @deprecated Use {@link NativePoc} instead.
542      * @param pocName a string path to poc from the /res folder
543      * @param device device to be ran on
544      * @param config a crash parser configuration
545      */
546     @Deprecated
runPocAssertNoCrashes( String pocName, ITestDevice device, TombstoneUtils.Config config)547     public static void runPocAssertNoCrashes(
548             String pocName, ITestDevice device, TombstoneUtils.Config config) throws Exception {
549         runPocAssertNoCrashes(pocName, device, null, config);
550     }
551 
552     /**
553      * Runs the poc binary and asserts that there are no security crashes that match the expected
554      * process pattern, including arguments when running.
555      *
556      * @deprecated Use {@link NativePoc} instead.
557      * @param pocName a string path to poc from the /res folder
558      * @param device device to be ran on
559      * @param arguments input arguments for the poc
560      * @param config a crash parser configuration
561      */
562     @Deprecated
runPocAssertNoCrashes( String pocName, ITestDevice device, String arguments, TombstoneUtils.Config config)563     public static void runPocAssertNoCrashes(
564             String pocName, ITestDevice device, String arguments, TombstoneUtils.Config config)
565             throws Exception {
566         try (AutoCloseable a = TombstoneUtils.withAssertNoSecurityCrashes(device, config)) {
567             AdbUtils.runPocNoOutput(pocName, device,
568                     SecurityTestCase.TIMEOUT_NONDETERMINISTIC, arguments);
569         }
570     }
571 
572     /**
573      * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
574      * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
575      * condition).
576      *
577      * @deprecated Use {@link NativePoc} instead.
578      * @param binaryName name of the binary
579      * @param arguments arguments for running the binary
580      * @param device device to be run on
581      */
582     @Deprecated
runPocAssertNoCrashesNotVulnerable( String binaryName, String arguments, ITestDevice device)583     public static void runPocAssertNoCrashesNotVulnerable(
584             String binaryName, String arguments, ITestDevice device) throws Exception {
585         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device, null);
586     }
587 
588     /**
589      * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
590      * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
591      * condition).
592      *
593      * @deprecated Use {@link NativePoc} instead.
594      * @param binaryName name of the binary
595      * @param arguments arguments for running the binary
596      * @param device device to be run on
597      * @param processPatternStrings a Pattern string to match the crash tombstone process
598      */
599     @Deprecated
runPocAssertNoCrashesNotVulnerable( String binaryName, String arguments, ITestDevice device, String processPatternStrings[])600     public static void runPocAssertNoCrashesNotVulnerable(
601             String binaryName, String arguments, ITestDevice device, String processPatternStrings[])
602             throws Exception {
603         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device,
604                 processPatternStrings);
605     }
606 
607     /**
608      * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in
609      * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability
610      * condition).
611      *
612      * @deprecated Use {@link NativePoc} instead.
613      * @param binaryName name of the binary
614      * @param arguments arguments for running the binary
615      * @param inputFiles files required as input
616      * @param inputFilesDestination destination directory to which input files are pushed
617      * @param device device to be run on
618      */
619     @Deprecated
runPocAssertNoCrashesNotVulnerable( String binaryName, String arguments, String inputFiles[], String inputFilesDestination, ITestDevice device)620     public static void runPocAssertNoCrashesNotVulnerable(
621             String binaryName,
622             String arguments,
623             String inputFiles[],
624             String inputFilesDestination,
625             ITestDevice device)
626             throws Exception {
627         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, inputFiles, inputFilesDestination,
628                 device, null);
629     }
630 
631     /**
632      * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in
633      * the binary. 2. There are no security crashes that match the expected process pattern. 3. The
634      * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
635      *
636      * @deprecated Use {@link NativePoc} instead.
637      * @param binaryName name of the binary
638      * @param arguments arguments for running the binary
639      * @param inputFiles files required as input
640      * @param inputFilesDestination destination directory to which input files are pushed
641      * @param device device to be run on
642      * @param processPatternStrings a Pattern string to match the crash tombstone process
643      */
644     @Deprecated
runPocAssertNoCrashesNotVulnerable( String binaryName, String arguments, String inputFiles[], String inputFilesDestination, ITestDevice device, String processPatternStrings[])645     public static void runPocAssertNoCrashesNotVulnerable(
646             String binaryName,
647             String arguments,
648             String inputFiles[],
649             String inputFilesDestination,
650             ITestDevice device,
651             String processPatternStrings[])
652             throws Exception {
653         runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null,
654                 inputFiles, inputFilesDestination, device, processPatternStrings);
655     }
656 
657     /**
658      * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in
659      * the binary. 2. There are no security crashes that match the expected process pattern. 3. The
660      * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
661      *
662      * @deprecated Use {@link NativePoc} instead.
663      * @param binaryName name of the binary
664      * @param arguments arguments for running the binary
665      * @param envVars run the poc with environment variables
666      * @param inputFiles files required as input
667      * @param inputFilesDestination destination directory to which input files are pushed
668      * @param device device to be run on
669      * @param processPatternStrings a Pattern string (other than binary name) to match the crash
670      *     tombstone process
671      */
672     @Deprecated
runPocAssertNoCrashesNotVulnerable( String binaryName, String arguments, Map<String, String> envVars, String inputFiles[], String inputFilesDestination, ITestDevice device, String... processPatternStrings)673     public static void runPocAssertNoCrashesNotVulnerable(
674             String binaryName,
675             String arguments,
676             Map<String, String> envVars,
677             String inputFiles[],
678             String inputFilesDestination,
679             ITestDevice device,
680             String... processPatternStrings)
681             throws Exception {
682         pocConfig testConfig = new pocConfig(binaryName, device);
683         testConfig.arguments = arguments;
684         testConfig.envVars = envVars;
685 
686         if (inputFiles != null) {
687             testConfig.inputFiles = Arrays.asList(inputFiles);
688             testConfig.inputFilesDestination = inputFilesDestination;
689         }
690 
691         List<String> processPatternList = new ArrayList<>();
692         if (processPatternStrings != null) {
693             processPatternList.addAll(Arrays.asList(processPatternStrings));
694         }
695         processPatternList.add(binaryName);
696         String[] processPatternStringsWithSelf = new String[processPatternList.size()];
697         processPatternList.toArray(processPatternStringsWithSelf);
698         testConfig.config =
699                 new TombstoneUtils.Config().setProcessPatterns(processPatternStringsWithSelf);
700 
701         runPocAssertNoCrashesNotVulnerable(testConfig);
702     }
703 
704     /**
705      * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in
706      * the binary. 2. There are no security crashes that match the expected process pattern. 3. The
707      * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
708      *
709      * @deprecated Use {@link NativePoc} instead.
710      * @param testConfig test configuration
711      */
712     @Deprecated
runPocAssertNoCrashesNotVulnerable(pocConfig testConfig)713     public static void runPocAssertNoCrashesNotVulnerable(pocConfig testConfig) throws Exception {
714         String[] inputFiles = null;
715         if(!testConfig.inputFiles.isEmpty()) {
716             inputFiles = testConfig.inputFiles.toArray(new String[testConfig.inputFiles.size()]);
717             pushResources(inputFiles, testConfig.inputFilesDestination, testConfig.device);
718         }
719         try (AutoCloseable a =
720                 TombstoneUtils.withAssertNoSecurityCrashes(testConfig.device, testConfig.config)) {
721             runPocAssertExitStatusNotVulnerable(testConfig.binaryName, testConfig.arguments,
722                     testConfig.envVars, testConfig.device, TIMEOUT_SEC);
723         } catch (IllegalArgumentException e) {
724             /*
725              * Since 'runPocGetExitStatus' method raises IllegalArgumentException upon
726              * hang/timeout, catching the exception here and ignoring it. Hangs are of
727              * Moderate severity and hence patches may not be ported. This piece of code can
728              * be removed once 'runPocGetExitStatus' is updated to handle hangs.
729              */
730             CLog.w("Ignoring IllegalArgumentException: " + e);
731         } finally {
732             if (!testConfig.inputFiles.isEmpty()) {
733                 removeResources(inputFiles, testConfig.inputFilesDestination, testConfig.device);
734             }
735         }
736     }
737 
assumeHasNfc(ITestDevice device)738     public static void assumeHasNfc(ITestDevice device) throws DeviceNotAvailableException {
739         assumeTrue("nfc not available on device", device.hasFeature("android.hardware.nfc"));
740     }
741 
742     /**
743      * Escapes regex special characters in the given string
744      *
745      * @param testString string for which special characters need to be escaped
746      *
747      * @return string with escaped special charcters
748      */
escapeRegexSpecialChars(String testString)749     public static String escapeRegexSpecialChars(String testString) {
750         Matcher m = regexSpecialCharsEscapedPattern.matcher(testString);
751         return m.replaceAll("\\\\$0");
752     }
753 }
754