1 /* 2 * Copyright (C) 2017 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 com.android.server.pm; 18 19 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo; 20 21 import android.content.Context; 22 import android.content.pm.UserInfo; 23 import android.os.Environment; 24 import android.os.FileUtils; 25 import android.os.RecoverySystem; 26 import android.os.SystemProperties; 27 import android.os.UserHandle; 28 import android.os.storage.StorageManager; 29 import android.os.storage.VolumeInfo; 30 import android.system.ErrnoException; 31 import android.system.Os; 32 import android.system.OsConstants; 33 import android.util.Log; 34 import android.util.Slog; 35 import android.util.SparseArray; 36 37 import com.android.internal.annotations.VisibleForTesting; 38 import com.android.server.utils.Slogf; 39 40 import java.io.File; 41 import java.io.IOException; 42 import java.nio.charset.StandardCharsets; 43 import java.util.ArrayList; 44 import java.util.Collections; 45 import java.util.List; 46 import java.util.Objects; 47 48 /** 49 * Helper class for preparing and destroying user storage 50 */ 51 class UserDataPreparer { 52 private static final String TAG = "UserDataPreparer"; 53 private static final String XATTR_SERIAL = "user.serial"; 54 55 private final PackageManagerTracedLock mInstallLock; 56 private final Context mContext; 57 private final Installer mInstaller; 58 UserDataPreparer(Installer installer, PackageManagerTracedLock installLock, Context context)59 UserDataPreparer(Installer installer, PackageManagerTracedLock installLock, Context context) { 60 mInstallLock = installLock; 61 mContext = context; 62 mInstaller = installer; 63 } 64 65 /** 66 * Prepare storage areas for given user on all mounted devices. 67 */ prepareUserData(UserInfo userInfo, int flags)68 void prepareUserData(UserInfo userInfo, int flags) { 69 try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) { 70 final StorageManager storage = mContext.getSystemService(StorageManager.class); 71 if (storage == null) { 72 Log.e(TAG, "prepareUserData failed due to unable get StorageManager"); 73 return; 74 } 75 /* 76 * Internal storage must be prepared before adoptable storage, since the user's volume 77 * keys are stored in their internal storage. 78 */ 79 prepareUserDataLI(null /* internal storage */, userInfo, flags, true); 80 for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { 81 final String volumeUuid = vol.getFsUuid(); 82 if (volumeUuid != null) { 83 prepareUserDataLI(volumeUuid, userInfo, flags, true); 84 } 85 } 86 } 87 } 88 prepareUserDataLI(String volumeUuid, UserInfo userInfo, int flags, boolean allowRecover)89 private void prepareUserDataLI(String volumeUuid, UserInfo userInfo, int flags, 90 boolean allowRecover) { 91 final int userId = userInfo.id; 92 final int userSerial = userInfo.serialNumber; 93 final StorageManager storage = mContext.getSystemService(StorageManager.class); 94 final boolean isNewUser = userInfo.lastLoggedInTime == 0; 95 Slogf.d(TAG, "Preparing user data; volumeUuid=%s, userId=%d, flags=0x%x, isNewUser=%s", 96 volumeUuid, userId, flags, isNewUser); 97 try { 98 // Prepare CE and/or DE storage. 99 storage.prepareUserStorage(volumeUuid, userId, flags); 100 101 // Ensure that the data directories of a removed user with the same ID are not being 102 // reused. New users must get fresh data directories, to avoid leaking data. 103 if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) { 104 enforceSerialNumber(getDataUserDeDirectory(volumeUuid, userId), userSerial); 105 if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { 106 enforceSerialNumber(getDataSystemDeDirectory(userId), userSerial); 107 } 108 } 109 if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { 110 enforceSerialNumber(getDataUserCeDirectory(volumeUuid, userId), userSerial); 111 if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { 112 enforceSerialNumber(getDataSystemCeDirectory(userId), userSerial); 113 } 114 } 115 116 // Prepare the app data directories. 117 mInstaller.createUserData(volumeUuid, userId, userSerial, flags); 118 119 // If applicable, record that the system user's CE storage has been prepared. 120 if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && 121 (userId == UserHandle.USER_SYSTEM)) { 122 String propertyName = "sys.user." + userId + ".ce_available"; 123 Slog.d(TAG, "Setting property: " + propertyName + "=true"); 124 SystemProperties.set(propertyName, "true"); 125 } 126 } catch (Exception e) { 127 // Failed to prepare user data. For new users, specifically users that haven't ever 128 // been unlocked, destroy the user data, and try again (if not already retried). This 129 // might be effective at resolving some errors, such as stale directories from a reused 130 // user ID. Don't auto-destroy data for existing users, since issues with existing 131 // users might be fixable via an OTA without having to wipe the user's data. 132 if (isNewUser) { 133 logCriticalInfo(Log.ERROR, "Destroying user " + userId + " on volume " + volumeUuid 134 + " because we failed to prepare: " + e); 135 destroyUserDataLI(volumeUuid, userId, flags); 136 } else { 137 logCriticalInfo(Log.ERROR, "Failed to prepare user " + userId + " on volume " 138 + volumeUuid + ": " + e); 139 } 140 if (allowRecover) { 141 // Try one last time; if we fail again we're really in trouble 142 prepareUserDataLI(volumeUuid, userInfo, flags | StorageManager.FLAG_STORAGE_DE, 143 false); 144 } else { 145 // If internal storage of the system user fails to prepare on first boot, then 146 // things are *really* broken, so we might as well reboot to recovery right away. 147 try { 148 Log.e(TAG, "prepareUserData failed for user " + userId, e); 149 if (isNewUser && userId == UserHandle.USER_SYSTEM && volumeUuid == null) { 150 RecoverySystem.rebootPromptAndWipeUserData(mContext, 151 "failed to prepare internal storage for system user"); 152 } 153 } catch (IOException e2) { 154 throw new RuntimeException("error rebooting into recovery", e2); 155 } 156 } 157 } 158 } 159 160 /** 161 * Destroy storage areas for given user on all mounted devices. 162 */ destroyUserData(int userId, int flags)163 void destroyUserData(int userId, int flags) { 164 try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) { 165 final StorageManager storage = mContext.getSystemService(StorageManager.class); 166 if (storage != null) { 167 /* 168 * Volume destruction order isn't really important, but to avoid any weird issues we 169 * process internal storage last, the opposite of prepareUserData. 170 */ 171 for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { 172 final String volumeUuid = vol.getFsUuid(); 173 if (volumeUuid != null) { 174 destroyUserDataLI(volumeUuid, userId, flags); 175 } 176 } 177 } 178 destroyUserDataLI(null /* internal storage */, userId, flags); 179 } 180 } 181 destroyUserDataLI(String volumeUuid, int userId, int flags)182 void destroyUserDataLI(String volumeUuid, int userId, int flags) { 183 final StorageManager storage = mContext.getSystemService(StorageManager.class); 184 try { 185 // Clean up app data, profile data, and media data 186 mInstaller.destroyUserData(volumeUuid, userId, flags); 187 188 // Clean up system data 189 if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { 190 if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) { 191 FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId)); 192 // Delete the contents of /data/system_de/$userId, but not the directory itself 193 // since vold is responsible for that and system_server isn't allowed to do it. 194 FileUtils.deleteContents(getDataSystemDeDirectory(userId)); 195 } 196 if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { 197 // Likewise, delete the contents of /data/system_ce/$userId but not the 198 // directory itself. 199 FileUtils.deleteContents(getDataSystemCeDirectory(userId)); 200 } 201 } 202 203 if (storage != null) { 204 // All the user's data directories should be empty now, so finish the job. 205 storage.destroyUserStorage(volumeUuid, userId, flags); 206 } 207 } catch (Exception e) { 208 logCriticalInfo(Log.WARN, 209 "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e); 210 } 211 } 212 213 /** 214 * Examine all users present on given mounted volume, and destroy data 215 * belonging to users that are no longer valid, or whose user ID has been 216 * recycled. 217 */ reconcileUsers(String volumeUuid, List<UserInfo> validUsersList)218 void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList) { 219 final List<File> files = new ArrayList<>(); 220 Collections.addAll(files, FileUtils 221 .listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid))); 222 Collections.addAll(files, FileUtils 223 .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid))); 224 Collections.addAll(files, FileUtils 225 .listFilesOrEmpty(Environment.getDataSystemDeDirectory())); 226 Collections.addAll(files, FileUtils 227 .listFilesOrEmpty(Environment.getDataSystemCeDirectory())); 228 Collections.addAll(files, FileUtils 229 .listFilesOrEmpty(Environment.getDataMiscCeDirectory())); 230 reconcileUsers(volumeUuid, validUsersList, files); 231 } 232 233 @VisibleForTesting reconcileUsers(String volumeUuid, List<UserInfo> validUsersList, List<File> files)234 void reconcileUsers(String volumeUuid, List<UserInfo> validUsersList, List<File> files) { 235 final int userCount = validUsersList.size(); 236 SparseArray<UserInfo> users = new SparseArray<>(userCount); 237 for (int i = 0; i < userCount; i++) { 238 UserInfo user = validUsersList.get(i); 239 users.put(user.id, user); 240 } 241 for (File file : files) { 242 if (!file.isDirectory()) { 243 continue; 244 } 245 246 final int userId; 247 final UserInfo info; 248 try { 249 userId = Integer.parseInt(file.getName()); 250 info = users.get(userId); 251 } catch (NumberFormatException e) { 252 Slog.w(TAG, "Invalid user directory " + file); 253 continue; 254 } 255 256 boolean destroyUser = false; 257 if (info == null) { 258 logCriticalInfo(Log.WARN, "Destroying user directory " + file 259 + " because no matching user was found"); 260 destroyUser = true; 261 } else { 262 try { 263 enforceSerialNumber(file, info.serialNumber); 264 } catch (IOException e) { 265 logCriticalInfo(Log.WARN, "Destroying user directory " + file 266 + " because we failed to enforce serial number: " + e); 267 destroyUser = true; 268 } 269 } 270 271 if (destroyUser) { 272 try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) { 273 destroyUserDataLI(volumeUuid, userId, 274 StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); 275 } 276 } 277 } 278 } 279 280 @VisibleForTesting getDataMiscCeDirectory(int userId)281 protected File getDataMiscCeDirectory(int userId) { 282 return Environment.getDataMiscCeDirectory(userId); 283 } 284 285 @VisibleForTesting getDataSystemCeDirectory(int userId)286 protected File getDataSystemCeDirectory(int userId) { 287 return Environment.getDataSystemCeDirectory(userId); 288 } 289 290 @VisibleForTesting getDataMiscDeDirectory(int userId)291 protected File getDataMiscDeDirectory(int userId) { 292 return Environment.getDataMiscDeDirectory(userId); 293 } 294 295 @VisibleForTesting getUserSystemDirectory(int userId)296 protected File getUserSystemDirectory(int userId) { 297 return Environment.getUserSystemDirectory(userId); 298 } 299 300 @VisibleForTesting getDataUserCeDirectory(String volumeUuid, int userId)301 protected File getDataUserCeDirectory(String volumeUuid, int userId) { 302 return Environment.getDataUserCeDirectory(volumeUuid, userId); 303 } 304 305 @VisibleForTesting getDataSystemDeDirectory(int userId)306 protected File getDataSystemDeDirectory(int userId) { 307 return Environment.getDataSystemDeDirectory(userId); 308 } 309 310 @VisibleForTesting getDataUserDeDirectory(String volumeUuid, int userId)311 protected File getDataUserDeDirectory(String volumeUuid, int userId) { 312 return Environment.getDataUserDeDirectory(volumeUuid, userId); 313 } 314 315 /** 316 * Enforce that serial number stored in user directory inode matches the 317 * given expected value. Gracefully sets the serial number if currently 318 * undefined. 319 * 320 * @throws IOException when problem extracting serial number, or serial 321 * number is mismatched. 322 */ enforceSerialNumber(File file, int serialNumber)323 void enforceSerialNumber(File file, int serialNumber) throws IOException { 324 final int foundSerial = getSerialNumber(file); 325 Slog.v(TAG, "Found " + file + " with serial number " + foundSerial); 326 327 if (foundSerial == -1) { 328 Slog.d(TAG, "Serial number missing on " + file + "; assuming current is valid"); 329 try { 330 setSerialNumber(file, serialNumber); 331 } catch (IOException e) { 332 Slog.w(TAG, "Failed to set serial number on " + file, e); 333 } 334 335 } else if (foundSerial != serialNumber) { 336 throw new IOException("Found serial number " + foundSerial 337 + " doesn't match expected " + serialNumber); 338 } 339 } 340 341 /** 342 * Set serial number stored in user directory inode. 343 * 344 * @throws IOException if serial number was already set 345 */ setSerialNumber(File file, int serialNumber)346 private static void setSerialNumber(File file, int serialNumber) throws IOException { 347 try { 348 final byte[] buf = Integer.toString(serialNumber).getBytes(StandardCharsets.UTF_8); 349 Os.setxattr(file.getAbsolutePath(), XATTR_SERIAL, buf, OsConstants.XATTR_CREATE); 350 } catch (ErrnoException e) { 351 throw e.rethrowAsIOException(); 352 } 353 } 354 355 /** 356 * Return serial number stored in user directory inode. 357 * 358 * @return parsed serial number, or -1 if not set 359 */ 360 @VisibleForTesting getSerialNumber(File file)361 static int getSerialNumber(File file) throws IOException { 362 try { 363 final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL); 364 final String serial = new String(buf); 365 try { 366 return Integer.parseInt(serial); 367 } catch (NumberFormatException e) { 368 throw new IOException("Bad serial number: " + serial); 369 } 370 } catch (ErrnoException e) { 371 if (e.errno == OsConstants.ENODATA) { 372 return -1; 373 } else { 374 throw e.rethrowAsIOException(); 375 } 376 } 377 } 378 379 } 380