@ -65,6 +65,7 @@ static struct namespace_file {
{ . type = CLONE_NEWNET , . name = " ns/net " } ,
{ . type = CLONE_NEWPID , . name = " ns/pid " } ,
{ . type = CLONE_NEWNS , . name = " ns/mnt " } ,
{ . type = CLONE_NEWTIME , . name = " ns/time " } ,
{ . name = NULL }
} ;
@ -213,6 +214,23 @@ static ino_t get_mnt_ino(pid_t pid)
return st . st_ino ;
}
static void settime ( time_t offset , clockid_t clk_id )
{
char buf [ sizeof ( stringify_value ( ULONG_MAX ) ) * 3 ] ;
int fd , len ;
len = snprintf ( buf , sizeof ( buf ) , " %d %ld 0 " , clk_id , offset ) ;
fd = open ( " /proc/self/timens_offsets " , O_WRONLY ) ;
if ( fd < 0 )
err ( EXIT_FAILURE , _ ( " failed to open /proc/self/timens_offsets " ) ) ;
if ( write ( fd , buf , len ) ! = len )
err ( EXIT_FAILURE , _ ( " failed to write to /proc/self/timens_offsets " ) ) ;
close ( fd ) ;
}
static void bind_ns_files_from_child ( pid_t * child , int fds [ 2 ] )
{
char ch ;
@ -267,6 +285,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs ( _ ( " -p, --pid[=<file>] unshare pid namespace \n " ) , out ) ;
fputs ( _ ( " -U, --user[=<file>] unshare user namespace \n " ) , out ) ;
fputs ( _ ( " -C, --cgroup[=<file>] unshare cgroup namespace \n " ) , out ) ;
fputs ( _ ( " -t, --time[=<file>] unshare time namespace \n " ) , out ) ;
fputs ( USAGE_SEPARATOR , out ) ;
fputs ( _ ( " -f, --fork fork before launching <program> \n " ) , out ) ;
fputs ( _ ( " -r, --map-root-user map current user to root (implies --user) \n " ) , out ) ;
@ -284,6 +303,8 @@ static void __attribute__((__noreturn__)) usage(void)
fputs ( _ ( " -w, --wd=<dir> change working directory to <dir> \n " ) , out ) ;
fputs ( _ ( " -S, --setuid <uid> set uid in entered namespace \n " ) , out ) ;
fputs ( _ ( " -G, --setgid <gid> set gid in entered namespace \n " ) , out ) ;
fputs ( _ ( " --monotonic <offset> set clock monotonic offset (seconds) in time namespaces \n " ) , out ) ;
fputs ( _ ( " --boottime <offset> set clock boottime offset (seconds) in time namespaces \n " ) , out ) ;
fputs ( USAGE_SEPARATOR , out ) ;
printf ( USAGE_HELP_OPTIONS ( 27 ) ) ;
@ -300,6 +321,8 @@ int main(int argc, char *argv[])
OPT_SETGROUPS ,
OPT_KILLCHILD ,
OPT_KEEPCAPS ,
OPT_MONOTONIC ,
OPT_BOOTTIME ,
} ;
static const struct option longopts [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
@ -312,6 +335,7 @@ int main(int argc, char *argv[])
{ " pid " , optional_argument , NULL , ' p ' } ,
{ " user " , optional_argument , NULL , ' U ' } ,
{ " cgroup " , optional_argument , NULL , ' C ' } ,
{ " time " , optional_argument , NULL , ' t ' } ,
{ " fork " , no_argument , NULL , ' f ' } ,
{ " kill-child " , optional_argument , NULL , OPT_KILLCHILD } ,
@ -325,6 +349,8 @@ int main(int argc, char *argv[])
{ " setgid " , required_argument , NULL , ' G ' } ,
{ " root " , required_argument , NULL , ' R ' } ,
{ " wd " , required_argument , NULL , ' w ' } ,
{ " monotonic " , required_argument , NULL , OPT_MONOTONIC } ,
{ " boottime " , required_argument , NULL , OPT_BOOTTIME } ,
{ NULL , 0 , NULL , 0 }
} ;
@ -343,13 +369,17 @@ int main(int argc, char *argv[])
uid_t uid = 0 , real_euid = geteuid ( ) ;
gid_t gid = 0 , real_egid = getegid ( ) ;
int keepcaps = 0 ;
time_t monotonic = 0 ;
time_t boottime = 0 ;
int force_monotonic = 0 ;
int force_boottime = 0 ;
setlocale ( LC_ALL , " " ) ;
bindtextdomain ( PACKAGE , LOCALEDIR ) ;
textdomain ( PACKAGE ) ;
close_stdout_atexit ( ) ;
while ( ( c = getopt_long ( argc , argv , " +fhVmuinpCUrR:w:S:G:c " , longopts , NULL ) ) ! = - 1 ) {
while ( ( c = getopt_long ( argc , argv , " +fhVmuinpCt UrR:w:S:G:c " , longopts , NULL ) ) ! = - 1 ) {
switch ( c ) {
case ' f ' :
forkit = 1 ;
@ -389,6 +419,11 @@ int main(int argc, char *argv[])
if ( optarg )
set_ns_target ( CLONE_NEWCGROUP , optarg ) ;
break ;
case ' t ' :
unshare_flags | = CLONE_NEWTIME ;
if ( optarg )
set_ns_target ( CLONE_NEWTIME , optarg ) ;
break ;
case OPT_MOUNTPROC :
unshare_flags | = CLONE_NEWNS ;
procmnt = optarg ? optarg : " /proc " ;
@ -443,6 +478,14 @@ int main(int argc, char *argv[])
case ' w ' :
newdir = optarg ;
break ;
case OPT_MONOTONIC :
monotonic = strtoul_or_err ( optarg , _ ( " failed to parse monotonic offset " ) ) ;
force_monotonic = 1 ;
break ;
case OPT_BOOTTIME :
boottime = strtoul_or_err ( optarg , _ ( " failed to parse boottime offset " ) ) ;
force_boottime = 1 ;
break ;
case ' h ' :
usage ( ) ;
@ -453,6 +496,10 @@ int main(int argc, char *argv[])
}
}
if ( ( force_monotonic | | force_boottime ) & & ! ( unshare_flags & CLONE_NEWTIME ) )
errx ( EXIT_FAILURE , _ ( " options --monotonic and --boottime require "
" unsharing of a time namespace (-t) " ) ) ;
if ( npersists & & ( unshare_flags & CLONE_NEWNS ) )
bind_ns_files_from_child ( & pid , fds ) ;
@ -486,6 +533,12 @@ int main(int argc, char *argv[])
bind_ns_files ( getpid ( ) ) ;
}
if ( force_boottime )
settime ( boottime , CLOCK_BOOTTIME ) ;
if ( force_monotonic )
settime ( monotonic , CLOCK_MONOTONIC ) ;
if ( forkit ) {
pid = fork ( ) ;