@ -272,31 +272,76 @@ static int send_status(int sockfd, struct iovec *iovec, int status)
/*
* from man 7 capabilities , section
* Effect of User ID Changes on Capabilities :
* 4. If the file system user ID is changed from 0 to nonzero ( see setfsuid ( 2 ) )
* then the following capabilities are cleared from the effective set :
* CAP_CHOWN , CAP_DAC_OVERRIDE , CAP_DAC_READ_SEARCH , CAP_FOWNER , CAP_FSETID ,
* CAP_LINUX_IMMUTABLE ( since Linux 2.2 .30 ) , CAP_MAC_OVERRIDE , and CAP_MKNOD
* ( since Linux 2.2 .30 ) . If the file system UID is changed from nonzero to 0 ,
* then any of these capabilities that are enabled in the permitted set
* are enabled in the effective set .
* If the effective user ID is changed from nonzero to 0 , then the permitted
* set is copied to the effective set . If the effective user ID is changed
* from 0 to nonzero , then all capabilities are are cleared from the effective
* set .
*
* The setfsuid / setfsgid man pages warn that changing the effective user ID may
* expose the program to unwanted signals , but this is not true anymore : for an
* unprivileged ( without CAP_KILL ) program to send a signal , the real or
* effective user ID of the sending process must equal the real or saved user
* ID of the target process . Even when dropping privileges , it is enough to
* keep the saved UID to a " privileged " value and virtfs - proxy - helper won ' t
* be exposed to signals . So just use setresuid / setresgid .
*/
static int setfsugid ( int uid , int gid )
static int setugid ( int uid , int gid , int * suid , int * s gid)
{
int retval ;
/*
* We still need DAC_OVERRIDE because we don ' t change
* We still need DAC_OVERRIDE because we don ' t change
* supplementary group ids , and hence may be subjected DAC rules
*/
cap_value_t cap_list [ ] = {
CAP_DAC_OVERRIDE ,
} ;
setfsgid ( gid ) ;
setfsuid ( uid ) ;
* suid = geteuid ( ) ;
* sgid = getegid ( ) ;
if ( setresgid ( - 1 , gid , * sgid ) = = - 1 ) {
retval = - errno ;
goto err_out ;
}
if ( setresuid ( - 1 , uid , * suid ) = = - 1 ) {
retval = - errno ;
goto err_sgid ;
}
if ( uid ! = 0 | | gid ! = 0 ) {
return do_cap_set ( cap_list , ARRAY_SIZE ( cap_list ) , 0 ) ;
if ( do_cap_set ( cap_list , ARRAY_SIZE ( cap_list ) , 0 ) < 0 ) {
retval = - errno ;
goto err_suid ;
}
}
return 0 ;
err_suid :
if ( setresuid ( - 1 , * suid , * suid ) = = - 1 ) {
abort ( ) ;
}
err_sgid :
if ( setresgid ( - 1 , * sgid , * sgid ) = = - 1 ) {
abort ( ) ;
}
err_out :
return retval ;
}
/*
* This is used to reset the ugid back with the saved values
* There is nothing much we can do checking error values here .
*/
static void resetugid ( int suid , int sgid )
{
if ( setresgid ( - 1 , sgid , sgid ) = = - 1 ) {
abort ( ) ;
}
if ( setresuid ( - 1 , suid , suid ) = = - 1 ) {
abort ( ) ;
}
}
/*
@ -578,18 +623,15 @@ static int do_create_others(int type, struct iovec *iovec)
v9fs_string_init ( & path ) ;
v9fs_string_init ( & oldpath ) ;
cur_uid = geteuid ( ) ;
cur_gid = getegid ( ) ;
retval = proxy_unmarshal ( iovec , offset , " dd " , & uid , & gid ) ;
if ( retval < 0 ) {
return retval ;
}
offset + = retval ;
retval = setfs ugid ( uid , gid ) ;
retval = setugid ( uid , gid , & cur_uid , & cur_ gid) ;
if ( retval < 0 ) {
retval = - errno ;
goto err_out ;
goto unmarshal_err_out ;
}
switch ( type ) {
case T_MKNOD :
@ -619,9 +661,10 @@ static int do_create_others(int type, struct iovec *iovec)
}
err_out :
resetugid ( cur_uid , cur_gid ) ;
unmarshal_err_out :
v9fs_string_free ( & path ) ;
v9fs_string_free ( & oldpath ) ;
setfsugid ( cur_uid , cur_gid ) ;
return retval ;
}
@ -641,24 +684,16 @@ static int do_create(struct iovec *iovec)
if ( ret < 0 ) {
goto unmarshal_err_out ;
}
cur_uid = geteuid ( ) ;
cur_gid = getegid ( ) ;
ret = setfsugid ( uid , gid ) ;
ret = setugid ( uid , gid , & cur_uid , & cur_gid ) ;
if ( ret < 0 ) {
/*
* On failure reset back to the
* old uid / gid
*/
ret = - errno ;
goto err_out ;
goto unmarshal_err_out ;
}
ret = open ( path . data , flags , mode ) ;
if ( ret < 0 ) {
ret = - errno ;
}
err_out :
setfsugid ( cur_uid , cur_gid ) ;
resetugid ( cur_uid , cur_gid ) ;
unmarshal_err_out :
v9fs_string_free ( & path ) ;
return ret ;