/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.security.cts;

import android.content.Context;
import android.content.pm.PackageManager;
import android.net.cts.NetlinkSocket;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.storage.StorageManager;
import android.test.AndroidTestCase;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

public class VoldExploitTest extends AndroidTestCase {

    /**
     * Validate that this device isn't vulnerable to the "ZergRush"
     * vold vulnerability (CVE-2011-3874).
     *
     * https://github.com/revolutionary/zergRush/blob/master/zergRush.c
     *
     * Note: If the ZergRush vulnerability is present, the call to
     * {@link StorageManager#getMountedObbPath(String)} below hangs until CTS
     * kills the testsuite (10 minutes). A timeout, while not desirable,
     * is the typical failure for this test.
     */
    public void testZergRushCrash() throws Exception {
        int pid = findVold();

        StorageManager sm = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
        try {
            sm.getMountedObbPath("AAAA AAAA AAAA AAAA "
                    + "AAAA AAAA AAAA AAAA "
                    + "AAAA AAAA AAAA AAAA "
                    + "AAAA AAAA AAAA AAAA"
                    + "AAAA AAAA AAAA AAAA"
                    + "AAAA AAAA AAAA AAAA"
                    + "AAAA AAAA AAAA AAAA"
                    + "AAAA AAAA AAAA AAAA");
        } catch (IllegalStateException e) {
            // expected
        }

        Thread.sleep(2000);  // give vold some time to crash

        // Check to see if vold is still alive.
        assertTrue(
                "PID=" + pid + " crashed due to a malformed mount message."
                        + " Detected unpatched ZergRush vulnerability (CVE-2011-3874).",
                new File("/proc/" + pid + "/cmdline").exists());
    }

    /**
     * Validate that this device isn't vulnerable to the "ZergRush"
     * vold vulnerability (CVE-2011-3874).
     *
     * https://github.com/revolutionary/zergRush/blob/master/zergRush.c
     *
     * Note: If the ZergRush vulnerability is present, the call to
     * {@link IBinder#transact(int, android.os.Parcel, android.os.Parcel, int)}}
     * below hangs until CTS kills the testsuite (10 minutes). A timeout,
     * while not desirable, is the typical failure for this test.
     *
     * This test accomplishes the same thing as {@link #testZergRushCrash()}
     */
    public void testZergRushUsingRelection() throws Exception {
        // This test assumes we have the MOUNT_UNMOUNT_FILESYSTEMS permission
        // Check it first so we know we're reaching the vulnerable code.
        assertEquals(PackageManager.PERMISSION_GRANTED,
                getContext().checkCallingOrSelfPermission(
                        android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS));

        int pid = findVold();

        try {
            Object iBinderObj = Class.forName("android.os.ServiceManager")
                    .getDeclaredMethod("getService", String.class)
                    .invoke(null, "mount");
            if (!(iBinderObj instanceof IBinder)) {
                // unexpected return value, return.  Assume not exploitable.
                return;
            }

            String[] names = new String[] {
                    "IMountService",                   // Android 2.3
                    "android.os.storage.IMountService" // Android 2.2
            };

            for (String name : names) {
                IBinder iBinder = (IBinder) iBinderObj;
                Parcel data = Parcel.obtain();
                data.writeInterfaceToken(name);
                data.writeString("AAAA AAAA AAAA AAAA "
                        + "AAAA AAAA AAAA AAAA "
                        + "AAAA AAAA AAAA AAAA "
                        + "AAAA AAAA AAAA AAAA"
                        + "AAAA AAAA AAAA AAAA"
                        + "AAAA AAAA AAAA AAAA"
                        + "AAAA AAAA AAAA AAAA"
                        + "AAAA AAAA AAAA AAAA");

                // If vold crashes, this next line will hang forever.
                iBinder.transact(6, data, null, 0);
            }
        } catch (ClassNotFoundException e) {
            // class doesn't exist. Assume not exploitable.
        } catch (NoSuchMethodException e) {
            // no such method exists. Assume not exploitable.
        } catch (InvocationTargetException e) {
            // can't invoke.  Assume not exploitable.
        } catch (IllegalAccessException e) {
            // can't access.  Assume not exploitable.
        } catch (RemoteException e) {
            // remote failure. Assume not exploitable.
        }

        Thread.sleep(2000);  // give vold some time to crash

        // Check to see if vold is still alive.
        assertTrue(
                "PID=" + pid + " crashed due to a malformed mount message."
                        + " Detected unpatched ZergRush vulnerability (CVE-2011-3874).",
                new File("/proc/" + pid + "/cmdline").exists());
    }

    /**
     * Try to crash the vold program using CVE-2011-1823.
     *
     * This test attempts to send an invalid netlink messages to
     * any process which is listening for the messages.  If we detect
     * that any process crashed as a result of our message, then
     * we know that we found a bug.
     *
     * If this test fails, it's due to CVE-2011-1823
     *
     * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-1823
     */
    public void testTryToCrashVold() throws IOException {
        Set<Integer> pids = getPids();
        assertTrue(pids.size() > 1);  // at least vold and netd should exist

        Set<String> devices = new HashSet<String>();
        devices.addAll(getSysFsPath("/etc/vold.fstab"));
        devices.addAll(getSysFsPath("/system/etc/vold.fstab"));
        if (devices.isEmpty()) {
          // This vulnerability is not exploitable if there's
          // no entry in vold.fstab
          return;
        }

        NetlinkSocket ns = NetlinkSocket.create();
        for (int i : pids) {
            for (String j : devices) {
                doAttack(ns, i, j);
            }
        }

        // Check to see if all the processes are still alive.  If
        // any of them have died, we found an exploitable bug.
        for (int i : pids) {
            assertTrue(
                    "PID=" + i + " crashed due to a malformed netlink message."
                    + " Detected unpatched vulnerability CVE-2011-1823.",
                    new File("/proc/" + i + "/cmdline").exists());
        }
    }

    /**
     * Try to actually crash the program, by first sending a fake
     * request to add a new disk, followed by a fake request to add
     * a partition.
     */
    private static void doAttack(NetlinkSocket ns, int pid, String path)
            throws IOException {
        try {
            ns.sendmsg(pid, getDiskAddedMessage(path));
            confirmNetlinkMsgReceived();

            for (int i = -1000; i > -5000; i-=1000) {
                ns.sendmsg(pid, getPartitionAddedMessage(path, i));
                confirmNetlinkMsgReceived();
            }
        } catch (IOException e) {
            // Ignore the exception.  The process either:
            //
            // 1) Crashed
            // 2) Closed the netlink socket and refused further messages
            //
            // If #1 occurs, our PID check in testTryToCrashVold() will
            // detect the process crashed and trigger an error.
            //
            // #2 is not a security bug.  It's perfectly acceptable to
            // refuse messages from someone trying to send you
            // malicious content.
        }
    }

    /**
     * Parse the fstab.vold file, and extract out the "sysfs_path" field.
     */
    private static Set<String> getSysFsPath(String file) throws IOException {
        Set<String> retval = new HashSet<String>();
        File netlink = new File(file);
        if (!netlink.canRead()) {
            return retval;
        }
        Scanner scanner = null;
        try {
            scanner = new Scanner(netlink);
            while(scanner.hasNextLine()) {
                String line = scanner.nextLine().trim();
                if (!line.startsWith("dev_mount")) {
                    continue;
                }

                String[] fields = line.split("\\s+");
                assertTrue(fields.length >= 5);
                // Column 5 and beyond is "sysfs_path"
                retval.addAll(Arrays.asList(fields).subList(4, fields.length));
            }
        } finally {
            if (scanner != null) {
                scanner.close();
            }
        }
        return retval;
    }

    /**
     * Poll /proc/net/netlink until all the "Rmem" fields contain
     * "0" or approximately 10 seconds have passed.
     *
     * This indicates that either the netlink message was received,
     * or the process took too long to process the incoming netlink
     * message.
     *
     * See http://code.google.com/p/android/issues/detail?id=25099
     * for information on why the timeout is needed.
     */
    private static void confirmNetlinkMsgReceived() {
        try {
            for (int ct = 0; ct < 200; ct++) {
                boolean foundAllZeros = true;
                for (List<String> i : parseNetlink()) {
                    // Column 5 is the "Rmem" field, which is the
                    // amount of kernel memory for received netlink messages.
                    if (!i.get(4).equals("0")) {
                        foundAllZeros = false;
                    }
                }
                if (foundAllZeros) {
                    return;
                }
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static int findVold() throws IOException {
        File f = new File("/proc");
        for (File d : f.listFiles()) {
            String cmdLineString = d.getAbsolutePath() + "/cmdline";
            File cmdLine = new File(cmdLineString);
            if (cmdLine.exists()) {
                BufferedReader in = null;
                try {
                    in = new BufferedReader(new FileReader(cmdLine));
                    String line = in.readLine();
                    if ((line != null) && line.startsWith("/system/bin/vold")) {
                        return Integer.decode(d.getName());
                    }
                } finally {
                    if (in != null) {
                        in.close();
                    }
                }
            }
        }
        throw new RuntimeException("should never get here");
    }

    /**
     * Extract all the PIDs listening for netlink messages.
     */
    private static Set<Integer> getPids() {
        List<List<String>> netlink = parseNetlink();
        Set<Integer> retval = new HashSet<Integer>();
        for (List<String> i : netlink) {
            // The PID is in column 3
            int pid = Integer.decode(i.get(2));
            if (new File("/proc/" + pid + "/cmdline").exists()) {
                retval.add(pid);
            }
        }
        return retval;
    }

    /**
     * Parse /proc/net/netlink and return a List of lines
     * (excluding the first line)
     */
    private static List<List<String>> parseNetlink() {
        List<List<String>> retval = new ArrayList<List<String>>();
        File netlink = new File("/proc/net/netlink");
        Scanner scanner = null;
        try {
            scanner = new Scanner(netlink);
            while(scanner.hasNextLine()) {
                String line = scanner.nextLine().trim();
                if (line.startsWith("sk")) {
                    continue;
                }

                List<String> lineList = Arrays.asList(line.split("\\s+"));
                retval.add(lineList);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (scanner != null) {
                scanner.close();
            }
        }
        return retval;
    }

    private static byte[] getDiskAddedMessage(String path) {
        try {
            return ("@/foo\0ACTION=add\0SUBSYSTEM=block\0"
                    + "DEVPATH=" + path + "\0MAJOR=179\0MINOR=12345"
                    + "\0DEVTYPE=disk\0").getBytes("ASCII");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    private static byte[] getPartitionAddedMessage(
            String path, int partitionNum) {
        try {
            return ("@/foo\0ACTION=add\0SUBSYSTEM=block\0"
                    + "DEVPATH=" + path + "\0MAJOR=179\0MINOR=12345"
                    + "\0DEVTYPE=blah\0PARTN=" + partitionNum + "\0")
                    .getBytes("ASCII");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
}
