Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
804f3e2a
Unverified
Commit
804f3e2a
authored
Jun 29, 2021
by
Christian Brauner
Committed by
GitHub
Jun 29, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3885 from tych0/dont-exec-execute
execute: don't exec init, call it
parents
f1c64634
734a677e
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
412 additions
and
482 deletions
+412
-482
lxc_init.c
src/lxc/cmd/lxc_init.c
+1
-348
conf.c
src/lxc/conf.c
+0
-83
conf.h
src/lxc/conf.h
+2
-0
execute.c
src/lxc/execute.c
+3
-49
initutils.c
src/lxc/initutils.c
+400
-0
initutils.h
src/lxc/initutils.h
+2
-0
network.c
src/lxc/network.c
+4
-0
start.h
src/lxc/start.h
+0
-2
No files found.
src/lxc/cmd/lxc_init.c
View file @
804f3e2a
...
@@ -10,13 +10,11 @@
...
@@ -10,13 +10,11 @@
#include <libgen.h>
#include <libgen.h>
#include <limits.h>
#include <limits.h>
#include <pthread.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unistd.h>
#include <lxc/lxccontainer.h>
#include <lxc/lxccontainer.h>
...
@@ -24,11 +22,9 @@
...
@@ -24,11 +22,9 @@
#include "compiler.h"
#include "compiler.h"
#include "config.h"
#include "config.h"
#include "error.h"
#include "initutils.h"
#include "initutils.h"
#include "memory_utils.h"
#include "memory_utils.h"
#include "parse.h"
#include "parse.h"
#include "process_utils.h"
#include "string_utils.h"
#include "string_utils.h"
/* option keys for long only options */
/* option keys for long only options */
...
@@ -38,14 +34,6 @@
...
@@ -38,14 +34,6 @@
#define QUOTE(macro) #macro
#define QUOTE(macro) #macro
#define QUOTEVAL(macro) QUOTE(macro)
#define QUOTEVAL(macro) QUOTE(macro)
static
sig_atomic_t
was_interrupted
;
static
void
interrupt_handler
(
int
sig
)
{
if
(
!
was_interrupted
)
was_interrupted
=
sig
;
}
static
struct
option
long_options
[]
=
{
static
struct
option
long_options
[]
=
{
{
"name"
,
required_argument
,
0
,
'n'
},
{
"name"
,
required_argument
,
0
,
'n'
},
{
"help"
,
no_argument
,
0
,
'h'
},
{
"help"
,
no_argument
,
0
,
'h'
},
...
@@ -75,119 +63,6 @@ static struct arguments my_args = {
...
@@ -75,119 +63,6 @@ static struct arguments my_args = {
.
shortopts
=
short_options
.
shortopts
=
short_options
};
};
static
void
prevent_forking
(
void
)
{
__do_free
char
*
line
=
NULL
;
__do_fclose
FILE
*
f
=
NULL
;
char
path
[
PATH_MAX
];
size_t
len
=
0
;
f
=
fopen
(
"/proc/self/cgroup"
,
"re"
);
if
(
!
f
)
return
;
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
__do_close
int
fd
=
-
EBADF
;
int
ret
;
char
*
p
,
*
p2
;
p
=
strchr
(
line
,
':'
);
if
(
!
p
)
continue
;
p
++
;
p2
=
strchr
(
p
,
':'
);
if
(
!
p2
)
continue
;
*
p2
=
'\0'
;
/* This is a cgroup v2 entry. Skip it. */
if
((
p2
-
p
)
==
0
)
continue
;
if
(
strcmp
(
p
,
"pids"
)
!=
0
)
continue
;
p2
++
;
p2
+=
lxc_char_left_gc
(
p2
,
strlen
(
p2
));
p2
[
lxc_char_right_gc
(
p2
,
strlen
(
p2
))]
=
'\0'
;
ret
=
snprintf
(
path
,
sizeof
(
path
),
"/sys/fs/cgroup/pids/%s/pids.max"
,
p2
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
sizeof
(
path
))
{
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to create string
\n
"
);
return
;
}
fd
=
open
(
path
,
O_WRONLY
|
O_CLOEXEC
);
if
(
fd
<
0
)
{
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to open
\"
%s
\"\n
"
,
path
);
return
;
}
ret
=
write
(
fd
,
"1"
,
1
);
if
(
ret
!=
1
&&
!
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to write to
\"
%s
\"\n
"
,
path
);
return
;
}
}
static
void
kill_children
(
pid_t
pid
)
{
__do_fclose
FILE
*
f
=
NULL
;
char
path
[
PATH_MAX
];
int
ret
;
ret
=
snprintf
(
path
,
sizeof
(
path
),
"/proc/%d/task/%d/children"
,
pid
,
pid
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
sizeof
(
path
))
{
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to create string
\n
"
);
return
;
}
f
=
fopen
(
path
,
"re"
);
if
(
!
f
)
{
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to open %s
\n
"
,
path
);
return
;
}
while
(
!
feof
(
f
))
{
pid_t
find_pid
;
if
(
fscanf
(
f
,
"%d "
,
&
find_pid
)
!=
1
)
{
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to retrieve pid
\n
"
);
return
;
}
(
void
)
kill_children
(
find_pid
);
(
void
)
kill
(
find_pid
,
SIGKILL
);
}
}
static
void
remove_self
(
void
)
{
int
ret
;
ssize_t
n
;
char
path
[
PATH_MAX
]
=
{
0
};
n
=
readlink
(
"/proc/self/exe"
,
path
,
sizeof
(
path
));
if
(
n
<
0
||
n
>=
PATH_MAX
)
return
;
path
[
n
]
=
'\0'
;
ret
=
umount2
(
path
,
MNT_DETACH
);
if
(
ret
<
0
)
return
;
ret
=
unlink
(
path
);
if
(
ret
<
0
)
return
;
}
__noreturn
static
void
print_usage_exit
(
const
struct
option
longopts
[])
__noreturn
static
void
print_usage_exit
(
const
struct
option
longopts
[])
{
{
...
@@ -283,12 +158,6 @@ static int arguments_parse(struct arguments *args, int argc,
...
@@ -283,12 +158,6 @@ static int arguments_parse(struct arguments *args, int argc,
int
main
(
int
argc
,
char
*
argv
[])
int
main
(
int
argc
,
char
*
argv
[])
{
{
int
i
,
logfd
,
ret
;
pid_t
pid
;
struct
sigaction
act
;
sigset_t
mask
,
omask
;
int
have_status
=
0
,
exit_with
=
1
,
shutdown
=
0
;
if
(
arguments_parse
(
&
my_args
,
argc
,
argv
))
if
(
arguments_parse
(
&
my_args
,
argc
,
argv
))
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
...
@@ -298,221 +167,5 @@ int main(int argc, char *argv[])
...
@@ -298,221 +167,5 @@ int main(int argc, char *argv[])
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
/* Mask all the signals so we are safe to install a signal handler and
lxc_container_init
(
my_args
.
argc
,
my_args
.
argv
,
my_args
.
quiet
);
* to fork.
*/
ret
=
sigfillset
(
&
mask
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
mask
,
SIGILL
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
mask
,
SIGSEGV
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
mask
,
SIGBUS
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
pthread_sigmask
(
SIG_SETMASK
,
&
mask
,
&
omask
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigfillset
(
&
act
.
sa_mask
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGILL
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGSEGV
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGBUS
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGSTOP
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGKILL
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
act
.
sa_flags
=
0
;
act
.
sa_handler
=
interrupt_handler
;
for
(
i
=
1
;
i
<
NSIG
;
i
++
)
{
/* Exclude some signals: ILL, SEGV and BUS are likely to reveal
* a bug and we want a core. STOP and KILL cannot be handled
* anyway: they're here for documentation. 32 and 33 are not
* defined.
*/
if
(
i
==
SIGILL
||
i
==
SIGSEGV
||
i
==
SIGBUS
||
i
==
SIGSTOP
||
i
==
SIGKILL
||
i
==
32
||
i
==
33
)
continue
;
ret
=
sigaction
(
i
,
&
act
,
NULL
);
if
(
ret
<
0
)
{
if
(
errno
==
EINVAL
)
continue
;
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to change signal action
\n
"
);
exit
(
EXIT_FAILURE
);
}
}
remove_self
();
pid
=
fork
();
if
(
pid
<
0
)
exit
(
EXIT_FAILURE
);
if
(
!
pid
)
{
/* restore default signal handlers */
for
(
i
=
1
;
i
<
NSIG
;
i
++
)
{
sighandler_t
sigerr
;
if
(
i
==
SIGILL
||
i
==
SIGSEGV
||
i
==
SIGBUS
||
i
==
SIGSTOP
||
i
==
SIGKILL
||
i
==
32
||
i
==
33
)
continue
;
sigerr
=
signal
(
i
,
SIG_DFL
);
if
(
sigerr
==
SIG_ERR
&&
!
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to reset to default action for signal
\"
%d
\"
: %d
\n
"
,
i
,
pid
);
}
ret
=
pthread_sigmask
(
SIG_SETMASK
,
&
omask
,
NULL
);
if
(
ret
<
0
)
{
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to set signal mask
\n
"
);
exit
(
EXIT_FAILURE
);
}
(
void
)
setsid
();
(
void
)
ioctl
(
STDIN_FILENO
,
TIOCSCTTY
,
0
);
ret
=
execvp
(
my_args
.
argv
[
0
],
my_args
.
argv
);
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to exec
\"
%s
\"\n
"
,
my_args
.
argv
[
0
]);
exit
(
ret
);
}
logfd
=
open
(
"/dev/console"
,
O_WRONLY
|
O_NOCTTY
|
O_CLOEXEC
);
if
(
logfd
>=
0
)
{
ret
=
dup3
(
logfd
,
STDERR_FILENO
,
O_CLOEXEC
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
}
(
void
)
setproctitle
(
"init"
);
/* Let's process the signals now. */
ret
=
sigdelset
(
&
omask
,
SIGALRM
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
pthread_sigmask
(
SIG_SETMASK
,
&
omask
,
NULL
);
if
(
ret
<
0
)
{
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to set signal mask
\n
"
);
exit
(
EXIT_FAILURE
);
}
/* No need of other inherited fds but stderr. */
close
(
STDIN_FILENO
);
close
(
STDOUT_FILENO
);
for
(;;)
{
int
status
;
pid_t
waited_pid
;
switch
(
was_interrupted
)
{
case
0
:
/* Some applications send SIGHUP in order to get init to reload
* its configuration. We don't want to forward this onto the
* application itself, because it probably isn't expecting this
* signal since it was expecting init to do something with it.
*
* Instead, let's explicitly ignore it here. The actual
* terminal case is handled in the monitor's handler, which
* sends this task a SIGTERM in the case of a SIGHUP, which is
* what we want.
*/
case
SIGHUP
:
break
;
case
SIGPWR
:
case
SIGTERM
:
if
(
!
shutdown
)
{
pid_t
mypid
=
lxc_raw_getpid
();
shutdown
=
1
;
prevent_forking
();
if
(
mypid
!=
1
)
{
kill_children
(
mypid
);
}
else
{
ret
=
kill
(
-
1
,
SIGTERM
);
if
(
ret
<
0
&&
!
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to send SIGTERM to all children
\n
"
);
}
alarm
(
1
);
}
break
;
case
SIGALRM
:
{
pid_t
mypid
=
lxc_raw_getpid
();
prevent_forking
();
if
(
mypid
!=
1
)
{
kill_children
(
mypid
);
}
else
{
ret
=
kill
(
-
1
,
SIGKILL
);
if
(
ret
<
0
&&
!
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to send SIGTERM to all children
\n
"
);
}
break
;
}
default:
kill
(
pid
,
was_interrupted
);
break
;
}
ret
=
EXIT_SUCCESS
;
was_interrupted
=
0
;
waited_pid
=
wait
(
&
status
);
if
(
waited_pid
<
0
)
{
if
(
errno
==
ECHILD
)
goto
out
;
if
(
errno
==
EINTR
)
continue
;
if
(
my_args
.
quiet
)
fprintf
(
stderr
,
"Failed to wait on child %d
\n
"
,
pid
);
ret
=
-
1
;
goto
out
;
}
/* Reset timer each time a process exited. */
if
(
shutdown
)
alarm
(
1
);
/* Keep the exit code of the started application (not wrapped
* pid) and continue to wait for the end of the orphan group.
*/
if
(
waited_pid
==
pid
&&
!
have_status
)
{
exit_with
=
lxc_error_set_and_log
(
waited_pid
,
status
);
have_status
=
1
;
}
}
out:
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
exit
(
exit_with
);
}
}
src/lxc/conf.c
View file @
804f3e2a
...
@@ -3727,58 +3727,6 @@ static void turn_into_dependent_mounts(const struct lxc_rootfs *rootfs)
...
@@ -3727,58 +3727,6 @@ static void turn_into_dependent_mounts(const struct lxc_rootfs *rootfs)
TRACE
(
"Turned all mount table entries into dependent mount"
);
TRACE
(
"Turned all mount table entries into dependent mount"
);
}
}
static
int
lxc_execute_bind_init
(
struct
lxc_handler
*
handler
)
{
int
ret
;
char
*
p
;
char
path
[
PATH_MAX
],
destpath
[
PATH_MAX
];
struct
lxc_conf
*
conf
=
handler
->
conf
;
/* If init exists in the container, don't bind mount a static one */
p
=
choose_init
(
conf
->
rootfs
.
mount
);
if
(
p
)
{
__do_free
char
*
old
=
p
;
p
=
strdup
(
old
+
strlen
(
conf
->
rootfs
.
mount
));
if
(
!
p
)
return
-
ENOMEM
;
INFO
(
"Found existing init at
\"
%s
\"
"
,
p
);
goto
out
;
}
ret
=
strnprintf
(
path
,
sizeof
(
path
),
SBINDIR
"/init.lxc.static"
);
if
(
ret
<
0
)
return
-
1
;
if
(
!
file_exists
(
path
))
return
log_error_errno
(
-
1
,
errno
,
"The file
\"
%s
\"
does not exist on host"
,
path
);
ret
=
strnprintf
(
destpath
,
sizeof
(
path
),
"%s"
P_tmpdir
"%s"
,
conf
->
rootfs
.
mount
,
"/.lxc-init"
);
if
(
ret
<
0
)
return
-
1
;
if
(
!
file_exists
(
destpath
))
{
ret
=
mknod
(
destpath
,
S_IFREG
|
0000
,
0
);
if
(
ret
<
0
&&
errno
!=
EEXIST
)
return
log_error_errno
(
-
1
,
errno
,
"Failed to create
\"
%s
\"
file as bind mount target"
,
destpath
);
}
ret
=
safe_mount
(
path
,
destpath
,
"none"
,
MS_BIND
,
NULL
,
conf
->
rootfs
.
mount
);
if
(
ret
<
0
)
return
log_error_errno
(
-
1
,
errno
,
"Failed to bind mount lxc.init.static into container"
);
p
=
strdup
(
destpath
+
strlen
(
conf
->
rootfs
.
mount
));
if
(
!
p
)
return
-
ENOMEM
;
INFO
(
"Bind mounted lxc.init.static into container at
\"
%s
\"
"
,
path
);
out:
((
struct
execute_args
*
)
handler
->
data
)
->
init_fd
=
-
1
;
((
struct
execute_args
*
)
handler
->
data
)
->
init_path
=
p
;
return
0
;
}
/* This does the work of remounting / if it is shared, calling the container
/* This does the work of remounting / if it is shared, calling the container
* pre-mount hooks, and mounting the rootfs.
* pre-mount hooks, and mounting the rootfs.
*/
*/
...
@@ -3848,15 +3796,6 @@ static bool verify_start_hooks(struct lxc_conf *conf)
...
@@ -3848,15 +3796,6 @@ static bool verify_start_hooks(struct lxc_conf *conf)
return
true
;
return
true
;
}
}
static
bool
execveat_supported
(
void
)
{
execveat
(
-
1
,
""
,
NULL
,
NULL
,
AT_EMPTY_PATH
);
if
(
errno
==
ENOSYS
)
return
false
;
return
true
;
}
static
int
lxc_setup_boot_id
(
void
)
static
int
lxc_setup_boot_id
(
void
)
{
{
int
ret
;
int
ret
;
...
@@ -4176,28 +4115,6 @@ int lxc_setup(struct lxc_handler *handler)
...
@@ -4176,28 +4115,6 @@ int lxc_setup(struct lxc_handler *handler)
if
(
lxc_conf
->
rootfs
.
dfd_dev
<
0
&&
errno
!=
ENOENT
)
if
(
lxc_conf
->
rootfs
.
dfd_dev
<
0
&&
errno
!=
ENOENT
)
return
log_error_errno
(
-
errno
,
errno
,
"Failed to open
\"
/dev
\"
"
);
return
log_error_errno
(
-
errno
,
errno
,
"Failed to open
\"
/dev
\"
"
);
if
(
lxc_conf
->
is_execute
)
{
if
(
execveat_supported
())
{
int
fd
;
char
path
[
STRLITERALLEN
(
SBINDIR
)
+
STRLITERALLEN
(
"/init.lxc.static"
)
+
1
];
ret
=
strnprintf
(
path
,
sizeof
(
path
),
SBINDIR
"/init.lxc.static"
);
if
(
ret
<
0
)
return
log_error
(
-
1
,
"Path to init.lxc.static too long"
);
fd
=
open
(
path
,
O_NOCTTY
|
O_NOFOLLOW
|
O_CLOEXEC
|
O_PATH
);
if
(
fd
<
0
)
return
log_error_errno
(
-
1
,
errno
,
"Unable to open lxc.init.static"
);
((
struct
execute_args
*
)
handler
->
data
)
->
init_fd
=
fd
;
((
struct
execute_args
*
)
handler
->
data
)
->
init_path
=
NULL
;
}
else
{
ret
=
lxc_execute_bind_init
(
handler
);
if
(
ret
<
0
)
return
log_error
(
-
1
,
"Failed to bind-mount the lxc init system"
);
}
}
/* Now mount only cgroups, if wanted. Before, /sys could not have been
/* Now mount only cgroups, if wanted. Before, /sys could not have been
* mounted. It is guaranteed to be mounted now either through
* mounted. It is guaranteed to be mounted now either through
* automatically or via fstab entries.
* automatically or via fstab entries.
...
...
src/lxc/conf.h
View file @
804f3e2a
...
@@ -22,8 +22,10 @@
...
@@ -22,8 +22,10 @@
#include "list.h"
#include "list.h"
#include "lxcseccomp.h"
#include "lxcseccomp.h"
#include "memory_utils.h"
#include "memory_utils.h"
#include "namespace.h"
#include "ringbuf.h"
#include "ringbuf.h"
#include "start.h"
#include "start.h"
#include "state.h"
#include "storage/storage.h"
#include "storage/storage.h"
#include "string_utils.h"
#include "string_utils.h"
#include "syscall_wrappers.h"
#include "syscall_wrappers.h"
...
...
src/lxc/execute.c
View file @
804f3e2a
...
@@ -16,64 +16,18 @@
...
@@ -16,64 +16,18 @@
#include "start.h"
#include "start.h"
#include "process_utils.h"
#include "process_utils.h"
#include "utils.h"
#include "utils.h"
#include "initutils.h"
lxc_log_define
(
execute
,
start
);
lxc_log_define
(
execute
,
start
);
static
int
execute_start
(
struct
lxc_handler
*
handler
,
void
*
data
)
static
int
execute_start
(
struct
lxc_handler
*
handler
,
void
*
data
)
{
{
int
argc_add
,
j
;
int
argc
=
0
;
char
**
argv
;
int
argc
=
0
,
i
=
0
;
struct
execute_args
*
my_args
=
data
;
struct
execute_args
*
my_args
=
data
;
while
(
my_args
->
argv
[
argc
++
]);
while
(
my_args
->
argv
[
argc
++
]);
/* lxc-init -n name -- [argc] NULL -> 5 */
lxc_container_init
(
argc
,
my_args
->
argv
,
my_args
->
quiet
);
argc_add
=
5
;
if
(
my_args
->
quiet
)
argc_add
++
;
if
(
!
handler
->
conf
->
rootfs
.
path
)
argc_add
+=
2
;
argv
=
malloc
((
argc
+
argc_add
)
*
sizeof
(
*
argv
));
if
(
!
argv
)
{
SYSERROR
(
"Allocating init args failed"
);
goto
out1
;
}
if
(
my_args
->
init_path
)
argv
[
i
++
]
=
my_args
->
init_path
;
else
argv
[
i
++
]
=
"lxc-init"
;
argv
[
i
++
]
=
"-n"
;
argv
[
i
++
]
=
(
char
*
)
handler
->
name
;
if
(
my_args
->
quiet
)
argv
[
i
++
]
=
"--quiet"
;
if
(
!
handler
->
conf
->
rootfs
.
path
)
{
argv
[
i
++
]
=
"-P"
;
argv
[
i
++
]
=
(
char
*
)
handler
->
lxcpath
;
}
argv
[
i
++
]
=
"--"
;
for
(
j
=
0
;
j
<
argc
;
j
++
)
argv
[
i
++
]
=
my_args
->
argv
[
j
];
argv
[
i
++
]
=
NULL
;
NOTICE
(
"Exec'ing
\"
%s
\"
"
,
my_args
->
argv
[
0
]);
if
(
my_args
->
init_fd
>=
0
)
execveat
(
my_args
->
init_fd
,
""
,
argv
,
environ
,
AT_EMPTY_PATH
);
else
execvp
(
argv
[
0
],
argv
);
SYSERROR
(
"Failed to exec %s"
,
argv
[
0
]);
free
(
argv
);
out1:
return
1
;
}
}
static
int
execute_post_start
(
struct
lxc_handler
*
handler
,
void
*
data
)
static
int
execute_post_start
(
struct
lxc_handler
*
handler
,
void
*
data
)
...
...
src/lxc/initutils.c
View file @
804f3e2a
...
@@ -5,14 +5,18 @@
...
@@ -5,14 +5,18 @@
#endif
#endif
#include <sys/prctl.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unistd.h>
#include <signal.h>
#include "compiler.h"
#include "compiler.h"
#include "config.h"
#include "config.h"
#include "error.h"
#include "file_utils.h"
#include "file_utils.h"
#include "initutils.h"
#include "initutils.h"
#include "macro.h"
#include "macro.h"
#include "memory_utils.h"
#include "memory_utils.h"
#include "process_utils.h"
#ifndef HAVE_STRLCPY
#ifndef HAVE_STRLCPY
#include "include/strlcpy.h"
#include "include/strlcpy.h"
...
@@ -308,3 +312,399 @@ int setproctitle(char *title)
...
@@ -308,3 +312,399 @@ int setproctitle(char *title)
return
ret
;
return
ret
;
}
}
static
void
prevent_forking
(
void
)
{
__do_free
char
*
line
=
NULL
;
__do_fclose
FILE
*
f
=
NULL
;
char
path
[
PATH_MAX
];
size_t
len
=
0
;
f
=
fopen
(
"/proc/self/cgroup"
,
"re"
);
if
(
!
f
)
return
;
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
__do_close
int
fd
=
-
EBADF
;
int
ret
;
char
*
p
,
*
p2
;
p
=
strchr
(
line
,
':'
);
if
(
!
p
)
continue
;
p
++
;
p2
=
strchr
(
p
,
':'
);
if
(
!
p2
)
continue
;
*
p2
=
'\0'
;
/* This is a cgroup v2 entry. Skip it. */
if
((
p2
-
p
)
==
0
)
continue
;
if
(
strcmp
(
p
,
"pids"
)
!=
0
)
continue
;
p2
++
;
p2
+=
lxc_char_left_gc
(
p2
,
strlen
(
p2
));
p2
[
lxc_char_right_gc
(
p2
,
strlen
(
p2
))]
=
'\0'
;
ret
=
snprintf
(
path
,
sizeof
(
path
),
"/sys/fs/cgroup/pids/%s/pids.max"
,
p2
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
sizeof
(
path
))
{
fprintf
(
stderr
,
"Failed to create string
\n
"
);
return
;
}
fd
=
open
(
path
,
O_WRONLY
|
O_CLOEXEC
);
if
(
fd
<
0
)
{
fprintf
(
stderr
,
"Failed to open
\"
%s
\"\n
"
,
path
);
return
;
}
ret
=
write
(
fd
,
"1"
,
1
);
if
(
ret
!=
1
)
fprintf
(
stderr
,
"Failed to write to
\"
%s
\"\n
"
,
path
);
return
;
}
}
static
void
kill_children
(
pid_t
pid
)
{
__do_fclose
FILE
*
f
=
NULL
;
char
path
[
PATH_MAX
];
int
ret
;
ret
=
snprintf
(
path
,
sizeof
(
path
),
"/proc/%d/task/%d/children"
,
pid
,
pid
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
sizeof
(
path
))
{
fprintf
(
stderr
,
"Failed to create string
\n
"
);
return
;
}
f
=
fopen
(
path
,
"re"
);
if
(
!
f
)
{
fprintf
(
stderr
,
"Failed to open %s
\n
"
,
path
);
return
;
}
while
(
!
feof
(
f
))
{
pid_t
find_pid
;
if
(
fscanf
(
f
,
"%d "
,
&
find_pid
)
!=
1
)
{
fprintf
(
stderr
,
"Failed to retrieve pid
\n
"
);
return
;
}
(
void
)
kill_children
(
find_pid
);
(
void
)
kill
(
find_pid
,
SIGKILL
);
}
}
static
void
remove_self
(
void
)
{
int
ret
;
ssize_t
n
;
char
path
[
PATH_MAX
]
=
{
0
};
n
=
readlink
(
"/proc/self/exe"
,
path
,
sizeof
(
path
));
if
(
n
<
0
||
n
>=
PATH_MAX
)
return
;
path
[
n
]
=
'\0'
;
ret
=
umount2
(
path
,
MNT_DETACH
);
if
(
ret
<
0
)
return
;
ret
=
unlink
(
path
);
if
(
ret
<
0
)
return
;
}
static
sig_atomic_t
was_interrupted
;
static
void
interrupt_handler
(
int
sig
)
{
if
(
!
was_interrupted
)
was_interrupted
=
sig
;
}
static
int
close_inherited
(
void
)
{
int
fddir
;
DIR
*
dir
;
struct
dirent
*
direntp
;
restart:
dir
=
opendir
(
"/proc/self/fd"
);
if
(
!
dir
)
return
-
errno
;
fddir
=
dirfd
(
dir
);
while
((
direntp
=
readdir
(
dir
)))
{
int
fd
,
ret
;
if
(
strcmp
(
direntp
->
d_name
,
"."
)
==
0
)
continue
;
if
(
strcmp
(
direntp
->
d_name
,
".."
)
==
0
)
continue
;
ret
=
lxc_safe_int
(
direntp
->
d_name
,
&
fd
);
if
(
ret
<
0
)
continue
;
if
(
fd
==
STDERR_FILENO
||
fd
==
fddir
)
break
;
if
(
close
(
fd
))
return
-
errno
;
closedir
(
dir
);
goto
restart
;
}
closedir
(
dir
);
return
0
;
}
__noreturn
int
lxc_container_init
(
int
argc
,
char
*
const
*
argv
,
bool
quiet
)
{
int
i
,
logfd
,
ret
;
pid_t
pid
;
struct
sigaction
act
;
sigset_t
mask
,
omask
;
int
have_status
=
0
,
exit_with
=
1
,
shutdown
=
0
;
/* Mask all the signals so we are safe to install a signal handler and
* to fork.
*/
ret
=
sigfillset
(
&
mask
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
mask
,
SIGILL
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
mask
,
SIGSEGV
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
mask
,
SIGBUS
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
pthread_sigmask
(
SIG_SETMASK
,
&
mask
,
&
omask
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigfillset
(
&
act
.
sa_mask
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGILL
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGSEGV
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGBUS
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGSTOP
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
sigdelset
(
&
act
.
sa_mask
,
SIGKILL
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
act
.
sa_flags
=
0
;
act
.
sa_handler
=
interrupt_handler
;
for
(
i
=
1
;
i
<
NSIG
;
i
++
)
{
/* Exclude some signals: ILL, SEGV and BUS are likely to reveal
* a bug and we want a core. STOP and KILL cannot be handled
* anyway: they're here for documentation. 32 and 33 are not
* defined.
*/
if
(
i
==
SIGILL
||
i
==
SIGSEGV
||
i
==
SIGBUS
||
i
==
SIGSTOP
||
i
==
SIGKILL
||
i
==
32
||
i
==
33
)
continue
;
ret
=
sigaction
(
i
,
&
act
,
NULL
);
if
(
ret
<
0
)
{
if
(
errno
==
EINVAL
)
continue
;
if
(
!
quiet
)
fprintf
(
stderr
,
"Failed to change signal action
\n
"
);
exit
(
EXIT_FAILURE
);
}
}
remove_self
();
pid
=
vfork
();
if
(
pid
<
0
)
exit
(
EXIT_FAILURE
);
if
(
!
pid
)
{
/* restore default signal handlers */
for
(
i
=
1
;
i
<
NSIG
;
i
++
)
{
sighandler_t
sigerr
;
if
(
i
==
SIGILL
||
i
==
SIGSEGV
||
i
==
SIGBUS
||
i
==
SIGSTOP
||
i
==
SIGKILL
||
i
==
32
||
i
==
33
)
continue
;
sigerr
=
signal
(
i
,
SIG_DFL
);
if
(
sigerr
==
SIG_ERR
&&
!
quiet
)
fprintf
(
stderr
,
"Failed to reset to default action for signal
\"
%d
\"
: %d
\n
"
,
i
,
pid
);
}
ret
=
pthread_sigmask
(
SIG_SETMASK
,
&
omask
,
NULL
);
if
(
ret
<
0
)
{
if
(
quiet
)
fprintf
(
stderr
,
"Failed to set signal mask
\n
"
);
exit
(
EXIT_FAILURE
);
}
(
void
)
setsid
();
(
void
)
ioctl
(
STDIN_FILENO
,
TIOCSCTTY
,
0
);
ret
=
execvp
(
argv
[
0
],
argv
);
if
(
!
quiet
)
fprintf
(
stderr
,
"Failed to exec
\"
%s
\"\n
"
,
argv
[
0
]);
exit
(
ret
);
}
logfd
=
open
(
"/dev/console"
,
O_WRONLY
|
O_NOCTTY
|
O_CLOEXEC
);
if
(
logfd
>=
0
)
{
ret
=
dup3
(
logfd
,
STDERR_FILENO
,
O_CLOEXEC
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
}
(
void
)
setproctitle
(
"init"
);
/* Let's process the signals now. */
ret
=
sigdelset
(
&
omask
,
SIGALRM
);
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
ret
=
pthread_sigmask
(
SIG_SETMASK
,
&
omask
,
NULL
);
if
(
ret
<
0
)
{
if
(
!
quiet
)
fprintf
(
stderr
,
"Failed to set signal mask
\n
"
);
exit
(
EXIT_FAILURE
);
}
ret
=
close_range
(
STDERR_FILENO
+
1
,
UINT_MAX
,
CLOSE_RANGE_UNSHARE
);
if
(
ret
)
{
/*
* Fallback to close_inherited() when the syscall is not
* available or when CLOSE_RANGE_UNSHARE isn't supported.
* On a regular kernel CLOSE_RANGE_UNSHARE should always be
* available but openSUSE Leap 15.3 seems to have a partial
* backport without CLOSE_RANGE_UNSHARE support.
*/
if
(
errno
==
ENOSYS
||
errno
==
EINVAL
)
ret
=
close_inherited
();
}
if
(
ret
)
{
fprintf
(
stderr
,
"Aborting attach to prevent leaking file descriptors into container
\n
"
);
exit
(
EXIT_FAILURE
);
}
for
(;;)
{
int
status
;
pid_t
waited_pid
;
switch
(
was_interrupted
)
{
case
0
:
/* Some applications send SIGHUP in order to get init to reload
* its configuration. We don't want to forward this onto the
* application itself, because it probably isn't expecting this
* signal since it was expecting init to do something with it.
*
* Instead, let's explicitly ignore it here. The actual
* terminal case is handled in the monitor's handler, which
* sends this task a SIGTERM in the case of a SIGHUP, which is
* what we want.
*/
case
SIGHUP
:
break
;
case
SIGPWR
:
case
SIGTERM
:
if
(
!
shutdown
)
{
pid_t
mypid
=
lxc_raw_getpid
();
shutdown
=
1
;
prevent_forking
();
if
(
mypid
!=
1
)
{
kill_children
(
mypid
);
}
else
{
ret
=
kill
(
-
1
,
SIGTERM
);
if
(
ret
<
0
&&
!
quiet
)
fprintf
(
stderr
,
"Failed to send SIGTERM to all children
\n
"
);
}
alarm
(
1
);
}
break
;
case
SIGALRM
:
{
pid_t
mypid
=
lxc_raw_getpid
();
prevent_forking
();
if
(
mypid
!=
1
)
{
kill_children
(
mypid
);
}
else
{
ret
=
kill
(
-
1
,
SIGKILL
);
if
(
ret
<
0
&&
!
quiet
)
fprintf
(
stderr
,
"Failed to send SIGTERM to all children
\n
"
);
}
break
;
}
default:
kill
(
pid
,
was_interrupted
);
break
;
}
ret
=
EXIT_SUCCESS
;
was_interrupted
=
0
;
waited_pid
=
wait
(
&
status
);
if
(
waited_pid
<
0
)
{
if
(
errno
==
ECHILD
)
goto
out
;
if
(
errno
==
EINTR
)
continue
;
if
(
!
quiet
)
fprintf
(
stderr
,
"Failed to wait on child %d
\n
"
,
pid
);
ret
=
-
1
;
goto
out
;
}
/* Reset timer each time a process exited. */
if
(
shutdown
)
alarm
(
1
);
/* Keep the exit code of the started application (not wrapped
* pid) and continue to wait for the end of the orphan group.
*/
if
(
waited_pid
==
pid
&&
!
have_status
)
{
exit_with
=
lxc_error_set_and_log
(
waited_pid
,
status
);
have_status
=
1
;
}
}
out:
if
(
ret
<
0
)
exit
(
EXIT_FAILURE
);
exit
(
exit_with
);
}
src/lxc/initutils.h
View file @
804f3e2a
...
@@ -54,4 +54,6 @@ __hidden extern const char *lxc_global_config_value(const char *option_name);
...
@@ -54,4 +54,6 @@ __hidden extern const char *lxc_global_config_value(const char *option_name);
__hidden
extern
int
setproctitle
(
char
*
title
);
__hidden
extern
int
setproctitle
(
char
*
title
);
__hidden
__noreturn
int
lxc_container_init
(
int
argc
,
char
*
const
*
argv
,
bool
quiet
);
#endif
/* __LXC_INITUTILS_H */
#endif
/* __LXC_INITUTILS_H */
src/lxc/network.c
View file @
804f3e2a
...
@@ -4121,6 +4121,8 @@ int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler)
...
@@ -4121,6 +4121,8 @@ int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler)
ret
=
lxc_send_nointr
(
data_sock
,
&
netdev
->
ifindex
,
sizeof
(
netdev
->
ifindex
),
MSG_NOSIGNAL
);
ret
=
lxc_send_nointr
(
data_sock
,
&
netdev
->
ifindex
,
sizeof
(
netdev
->
ifindex
),
MSG_NOSIGNAL
);
if
(
ret
<
0
)
if
(
ret
<
0
)
return
-
1
;
return
-
1
;
TRACE
(
"Sent network device %s with ifindex %d to parent"
,
maybe_empty
(
netdev
->
name
),
netdev
->
ifindex
);
}
}
if
(
!
lxc_list_empty
(
network
))
if
(
!
lxc_list_empty
(
network
))
...
@@ -4155,6 +4157,8 @@ int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler)
...
@@ -4155,6 +4157,8 @@ int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler)
ret
=
lxc_recv_nointr
(
data_sock
,
&
netdev
->
ifindex
,
sizeof
(
netdev
->
ifindex
),
0
);
ret
=
lxc_recv_nointr
(
data_sock
,
&
netdev
->
ifindex
,
sizeof
(
netdev
->
ifindex
),
0
);
if
(
ret
<
0
)
if
(
ret
<
0
)
return
-
1
;
return
-
1
;
TRACE
(
"Received network device %s with ifindex %d from child"
,
maybe_empty
(
netdev
->
name
),
netdev
->
ifindex
);
}
}
return
0
;
return
0
;
...
...
src/lxc/start.h
View file @
804f3e2a
...
@@ -136,8 +136,6 @@ struct lxc_handler {
...
@@ -136,8 +136,6 @@ struct lxc_handler {
};
};
struct
execute_args
{
struct
execute_args
{
char
*
init_path
;
int
init_fd
;
char
*
const
*
argv
;
char
*
const
*
argv
;
int
quiet
;
int
quiet
;
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment