@ -481,6 +481,46 @@ int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>&
return 0 ;
}
static int sane_readlinkat ( int dirfd , const char * path , char * buf , size_t bufsiz ) {
ssize_t len = readlinkat ( dirfd , path , buf , bufsiz ) ;
if ( len < 0 ) {
return - 1 ;
} else if ( len = = ( ssize_t ) bufsiz ) {
return - 1 ;
} else {
buf [ len ] = ' \0 ' ;
return 0 ;
}
}
static int unmount_tree ( const char * path ) {
size_t path_len = strlen ( path ) ;
FILE * fp = setmntent ( " /proc/mounts " , " r " ) ;
if ( fp = = NULL ) {
ALOGE ( " Error opening /proc/mounts: %s " , strerror ( errno ) ) ;
return - errno ;
}
// Some volumes can be stacked on each other, so force unmount in
// reverse order to give us the best chance of success.
std : : list < std : : string > toUnmount ;
mntent * mentry ;
while ( ( mentry = getmntent ( fp ) ) ! = NULL ) {
if ( strncmp ( mentry - > mnt_dir , path , path_len ) = = 0 ) {
toUnmount . push_front ( std : : string ( mentry - > mnt_dir ) ) ;
}
}
endmntent ( fp ) ;
for ( auto path : toUnmount ) {
if ( umount2 ( path . c_str ( ) , MNT_DETACH ) ) {
ALOGW ( " Failed to unmount %s: %s " , path . c_str ( ) , strerror ( errno ) ) ;
}
}
return 0 ;
}
int VolumeManager : : remountUid ( uid_t uid , const std : : string & mode ) {
LOG ( DEBUG ) < < " Remounting " < < uid < < " as mode " < < mode ;
@ -499,7 +539,7 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
}
// Figure out root namespace to compare against below
if ( readlinkat( dirfd ( dir ) , " 1/ns/mnt " , rootName , PATH_MAX ) = = - 1 ) {
if ( sane_ readlinkat( dirfd ( dir ) , " 1/ns/mnt " , rootName , PATH_MAX ) = = - 1 ) {
PLOG ( ERROR ) < < " Failed to readlink " ;
closedir ( dir ) ;
return - 1 ;
@ -524,7 +564,7 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
// Matches so far, but refuse to touch if in root namespace
LOG ( DEBUG ) < < " Found matching PID " < < de - > d_name ;
if ( readlinkat( pidFd , " ns/mnt " , pidName , PATH_MAX ) = = - 1 ) {
if ( sane_ readlinkat( pidFd , " ns/mnt " , pidName , PATH_MAX ) = = - 1 ) {
PLOG ( WARNING ) < < " Failed to read namespace for " < < de - > d_name ;
goto next ;
}
@ -536,18 +576,17 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
// We purposefully leave the namespace open across the fork
nsFd = openat ( pidFd , " ns/mnt " , O_RDONLY ) ;
if ( nsFd < 0 ) {
PLOG ( WARNING ) < < " Failed to open namespace " ;
PLOG ( WARNING ) < < " Failed to open namespace for " < < de - > d_name ;
goto next ;
}
if ( ! ( child = fork ( ) ) ) {
if ( setns ( nsFd , CLONE_NEWNS ) ! = 0 ) {
PLOG ( ERROR ) < < " Failed to setns " ;
PLOG ( ERROR ) < < " Failed to setns for " < < de - > d_name ;
_exit ( 1 ) ;
}
// Unmount current view and replace with requested view
umount2 ( " /storage " , MNT_FORCE ) ;
unmount_tree ( " /storage " ) ;
std : : string storageSource ;
if ( mode = = " default " ) {
@ -562,9 +601,21 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
}
if ( TEMP_FAILURE_RETRY ( mount ( storageSource . c_str ( ) , " /storage " ,
NULL , MS_BIND | MS_REC | MS_SLAVE , NULL ) ) = = - 1 ) {
PLOG ( WARNING ) < < " Failed to mount " < < storageSource ;
return false ;
PLOG ( ERROR ) < < " Failed to mount " < < storageSource < < " for "
< < de - > d_name ;
_exit ( 1 ) ;
}
// Mount user-specific symlink helper into place
userid_t user_id = multiuser_get_user_id ( uid ) ;
std : : string userSource ( StringPrintf ( " /mnt/user/%d " , user_id ) ) ;
if ( TEMP_FAILURE_RETRY ( mount ( userSource . c_str ( ) , " /storage/self " ,
NULL , MS_BIND , NULL ) ) = = - 1 ) {
PLOG ( ERROR ) < < " Failed to mount " < < userSource < < " for "
< < de - > d_name ;
_exit ( 1 ) ;
}
_exit ( 0 ) ;
}