Introduce a restorecon JNI binding.

Label the vmdl.*\.tmp files and the final .apk file differently.
Modify the WallpaperManagerService to restorecon the wallpaper file.

Signed-off-by: rpcraig <rpcraig@tycho.ncsc.mil>

Change-Id: Idfc056e9ec0508d7e11100626a7114f341f1af70
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index 90cfa37..c05a974 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -1,5 +1,25 @@
+/*
+ * Copyright (C) 2012 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.os;
 
+import android.util.Slog;
+
+import java.io.IOException;
+import java.io.File;
 import java.io.FileDescriptor;
 
 /**
@@ -9,6 +29,8 @@
  */
 public class SELinux {
 
+    private static final String TAG = "SELinux";
+
     /**
      * Determine whether SELinux is disabled or enabled.
      * @return a boolean indicating whether SELinux is enabled.
@@ -102,4 +124,53 @@
      * @return a boolean indicating whether permission was granted.
      */
     public static final native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm);
+
+    /**
+     * Restores a file to its default SELinux security context.
+     * If the system is not compiled with SELinux, then {@code true}
+     * is automatically returned.
+     * If SELinux is compiled in, but disabled, then {@code true} is
+     * returned.
+     *
+     * @param pathname The pathname of the file to be relabeled.
+     * @return a boolean indicating whether the relabeling succeeded.
+     * @exception NullPointerException if the pathname is a null object.
+     */
+    public static boolean restorecon(String pathname) throws NullPointerException {
+        if (pathname == null) { throw new NullPointerException(); }
+        return native_restorecon(pathname);
+    }
+
+    /**
+     * Restores a file to its default SELinux security context.
+     * If the system is not compiled with SELinux, then {@code true}
+     * is automatically returned.
+     * If SELinux is compiled in, but disabled, then {@code true} is
+     * returned.
+     *
+     * @param pathname The pathname of the file to be relabeled.
+     * @return a boolean indicating whether the relabeling succeeded.
+     */
+    private static native boolean native_restorecon(String pathname);
+
+    /**
+     * Restores a file to its default SELinux security context.
+     * If the system is not compiled with SELinux, then {@code true}
+     * is automatically returned.
+     * If SELinux is compiled in, but disabled, then {@code true} is
+     * returned.
+     *
+     * @param file The File object representing the path to be relabeled.
+     * @return a boolean indicating whether the relabeling succeeded.
+     * @exception NullPointerException if the file is a null object.
+     */
+    public static boolean restorecon(File file) throws NullPointerException {
+        try {
+            return native_restorecon(file.getCanonicalPath());
+        } catch (IOException e) {
+            Slog.e(TAG, "Error getting canonical path. Restorecon failed for " +
+                   file.getPath(), e);
+            return false;
+        }
+    }
 }
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 40443ff..e813c38 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
 #define LOG_TAG "SELinuxJNI"
 #include <utils/Log.h>
 
@@ -6,6 +22,7 @@
 #include "android_runtime/AndroidRuntime.h"
 #ifdef HAVE_SELINUX
 #include "selinux/selinux.h"
+#include "selinux/android.h"
 #endif
 #include <errno.h>
 
@@ -458,6 +475,27 @@
   }
 
   /*
+   * Function: native_restorecon
+   * Purpose: restore default SELinux security context
+   * Parameters: pathname: the pathname for the file to be relabeled
+   * Returns: boolean: (true) file label successfully restored, (false) otherwise
+   * Exceptions: none
+   */
+  static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) {
+#ifdef HAVE_SELINUX
+    if (isSELinuxDisabled)
+      return true;
+
+    const char *file = const_cast<char *>(env->GetStringUTFChars(pathname, NULL));
+    int ret = selinux_android_restorecon(file);
+    env->ReleaseStringUTFChars(pathname, file);
+    return (ret == 0);
+#else
+    return true;
+#endif
+  }
+
+  /*
    * JNI registration.
    */
   static JNINativeMethod method_table[] = {
@@ -472,6 +510,7 @@
     { "getPidContext"            , "(I)Ljava/lang/String;"                        , (void*)getPidCon        },
     { "isSELinuxEnforced"        , "()Z"                                          , (void*)isSELinuxEnforced},
     { "isSELinuxEnabled"         , "()Z"                                          , (void*)isSELinuxEnabled },
+    { "native_restorecon"        , "(Ljava/lang/String;)Z"                        , (void*)native_restorecon},
     { "setBooleanValue"          , "(Ljava/lang/String;Z)Z"                       , (void*)setBooleanValue  },
     { "setFileContext"           , "(Ljava/lang/String;Ljava/lang/String;)Z"      , (void*)setFileCon       },
     { "setFSCreateContext"       , "(Ljava/lang/String;)Z"                        , (void*)setFSCreateCon   },
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index d97d335..8a08277 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -45,6 +45,7 @@
 import android.os.FileObserver;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserId;
@@ -639,8 +640,12 @@
                         FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                         -1, -1);
             }
-            ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER),
+            File file = new File(dir, WALLPAPER);
+            ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
                     MODE_CREATE|MODE_READ_WRITE);
+            if (!SELinux.restorecon(file)) {
+                return null;
+            }
             wallpaper.name = name;
             return fd;
         } catch (FileNotFoundException e) {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 3501e47..8c5a090 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -96,6 +96,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -6418,6 +6419,10 @@
                     return false;
                 }
 
+                if (!SELinux.restorecon(newCodeFile)) {
+                    return false;
+                }
+
                 return true;
             }
         }
@@ -7399,6 +7404,9 @@
             FileUtils.setPermissions(
                     tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR,
                     -1, -1);
+            if (!SELinux.restorecon(tmpPackageFile)) {
+                return null;
+            }
         } catch (IOException e) {
             Slog.e(TAG, "Trouble getting the canoncical path for a temp file.");
             return null;