Restrict SipProfiles to profiles directory

We now check SIP profile names to ensure that they do not attempt file
traversal when being saved. They are now restricted to be children of
the profiles/ directory.

BUG: 31530456
Change-Id: I9c9bce59d852e8a1cf500be6ca59b5e303877180
(cherry picked from commit 52823033626ee55474d942d5b9ea24e0f07dbb66)
diff --git a/sip/src/com/android/services/telephony/sip/SipEditor.java b/sip/src/com/android/services/telephony/sip/SipEditor.java
index 8bc7734..1cee25b 100644
--- a/sip/src/com/android/services/telephony/sip/SipEditor.java
+++ b/sip/src/com/android/services/telephony/sip/SipEditor.java
@@ -258,7 +258,7 @@
      *
      * @param p The {@link SipProfile} to delete.
      */
-    private void deleteAndUnregisterProfile(SipProfile p) {
+    private void deleteAndUnregisterProfile(SipProfile p) throws IOException {
         if (p == null) return;
         mProfileDb.deleteProfile(p);
         mSipAccountRegistry.stopSipService(this, p.getProfileName());
diff --git a/sip/src/com/android/services/telephony/sip/SipProfileDb.java b/sip/src/com/android/services/telephony/sip/SipProfileDb.java
index e7b201b..bb1c7ec 100644
--- a/sip/src/com/android/services/telephony/sip/SipProfileDb.java
+++ b/sip/src/com/android/services/telephony/sip/SipProfileDb.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.net.sip.SipProfile;
 import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.Log;
 
 import java.io.File;
@@ -66,9 +67,13 @@
         mSipPreferences = new SipPreferences(mContext);
     }
 
-    public void deleteProfile(SipProfile p) {
+    public void deleteProfile(SipProfile p) throws IOException {
         synchronized(SipProfileDb.class) {
-            deleteProfile(new File(mProfilesDirectory + p.getProfileName()));
+            File profileFile = new File(mProfilesDirectory, p.getProfileName());
+            if (!isChild(new File(mProfilesDirectory), profileFile)) {
+                throw new IOException("Invalid Profile Credentials!");
+            }
+            deleteProfile(profileFile);
             if (mProfilesCount < 0) retrieveSipProfileListInternal();
         }
     }
@@ -93,7 +98,10 @@
     public void saveProfile(SipProfile p) throws IOException {
         synchronized(SipProfileDb.class) {
             if (mProfilesCount < 0) retrieveSipProfileListInternal();
-            File f = new File(mProfilesDirectory + p.getProfileName());
+            File f = new File(mProfilesDirectory, p.getProfileName());
+            if (!isChild(new File(mProfilesDirectory), f)) {
+                throw new IOException("Invalid Profile Credentials!");
+            }
             if (!f.exists()) f.mkdirs();
             AtomicFile atomicFile = new AtomicFile(new File(f, PROFILE_OBJ_FILE));
             FileOutputStream fos = null;
@@ -173,4 +181,19 @@
     private static void log(String msg) {
         Log.d(SipUtil.LOG_TAG, PREFIX + msg);
     }
+
+    /**
+     * Verifies that the file is a direct child of the base directory.
+     */
+    private boolean isChild(File base, File file) {
+        if (base == null || file == null) {
+            return false;
+        }
+        if (!base.equals(file.getAbsoluteFile().getParentFile())) {
+            Log.w(SipUtil.LOG_TAG, "isChild, file is not a child of the base dir.");
+            EventLog.writeEvent(0x534e4554, "31530456", -1, "");
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index 3678c46..cf03dd3 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -164,7 +164,12 @@
                 }
                 Log.i(LOG_TAG, "(Migration) Deleting SIP profile: " +
                         profileToMove.getProfileName());
-                dbDeStorage.deleteProfile(profileToMove);
+                try {
+                    dbDeStorage.deleteProfile(profileToMove);
+                } catch (IOException e) {
+                    Log.w(LOG_TAG, "Error Deleting file: " +
+                            profileToMove.getProfileName(), e);
+                }
             }
         }
         // Delete supporting structures if they exist