Skip to content

Commit d1fd70d

Browse files
author
Doug Davis
committed
Next round - a lot of clean-up and removed some hacks
Signed-off-by: Doug Davis <[email protected]>
1 parent 25b23ff commit d1fd70d

8 files changed

Lines changed: 204 additions & 84 deletions

File tree

container.go

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,33 +34,10 @@ func createContainer(context *cli.Context, spec *specs.LinuxSpec, rspec *specs.L
3434
return nil, err
3535
}
3636

37-
//
38-
39-
process := newProcess(spec.Process)
40-
41-
/*
42-
rootuid, err := container.Config().HostUID()
43-
if err != nil {
44-
return nil, err
45-
}
46-
47-
tty, err := newTty(spec.Process.Terminal, process, rootuid, "")
48-
if err != nil {
49-
return nil, err
50-
}
51-
handler := newSignalHandler(tty)
52-
defer handler.Close()
53-
*/
54-
55-
if err := container.Create(process); err != nil {
37+
if err := container.Create(newProcess(spec.Process)); err != nil {
5638
return nil, err
5739
}
58-
/*
59-
rc, err := handler.forward(process)
60-
if rc != 0 || err != nil {
61-
return nil, err
62-
}
63-
*/
40+
6441
return container, nil
6542
}
6643

libcontainer/container_linux.go

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -172,19 +172,19 @@ func (c *linuxContainer) Set(config configs.Config) error {
172172
}
173173

174174
// Create will initialize(create) a new container by
175-
// creating the namespaces associated with it
175+
// creating the namespaces associated with it.
176176
func (c *linuxContainer) Create(process *Process) error {
177-
// Our hacking trigger for init routine
178-
process.Args = []string{"createC"}
179-
180177
c.m.Lock()
181178
defer c.m.Unlock()
182-
status, err := c.currentStatus()
183-
if err != nil {
184-
return err
185-
}
186-
doInit := status == Created
187-
parent, err := c.newParentProcess(process, doInit)
179+
180+
/*
181+
status, err := c.currentStatus()
182+
if err != nil {
183+
return err
184+
}
185+
*/
186+
187+
parent, err := c.newParentProcess(process, initCreate)
188188
if err != nil {
189189
return newSystemError(err)
190190
}
@@ -195,19 +195,15 @@ func (c *linuxContainer) Create(process *Process) error {
195195
}
196196
return newSystemError(err)
197197
}
198-
if doInit {
199-
if err := c.updateState(parent); err != nil {
200-
return err
201-
}
202-
_, err := parent.wait()
203-
if err != nil {
204-
return err
205-
}
206-
} else {
207-
panic("should not be here")
208-
c.state.transition(&runningState{
209-
c: c,
210-
})
198+
199+
if err := c.updateState(parent); err != nil {
200+
return err
201+
}
202+
203+
// Wait for process to end
204+
_, err = parent.wait()
205+
if err != nil {
206+
return err
211207
}
212208

213209
return nil
@@ -220,14 +216,17 @@ func (c *linuxContainer) Start(process *Process) error {
220216
if err != nil {
221217
return err
222218
}
223-
// doInit := status == Destroyed
219+
220+
// doInit will be true if we're creating the main proc of the container.
221+
// Otherwise we're just joining the namespaces of the existing proc.
224222
doInit := status == Created
225223

226-
// fmt.Printf("state: %#v\n", c.state)
227-
// fmt.Printf("status: %#v\n", status)
228-
// fmt.Printf("status: %q\n", status)
229-
// fmt.Printf("doInit: %v\n", doInit)
230-
parent, err := c.newParentProcess(process, doInit)
224+
it := initStandard
225+
if !doInit {
226+
it = initSetns
227+
}
228+
229+
parent, err := c.newParentProcess(process, it)
231230
if err != nil {
232231
return newSystemError(err)
233232
}
@@ -273,7 +272,7 @@ func (c *linuxContainer) Signal(s os.Signal) error {
273272
return nil
274273
}
275274

276-
func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
275+
func (c *linuxContainer) newParentProcess(p *Process, it initType) (parentProcess, error) {
277276
parentPipe, childPipe, err := newPipe()
278277
if err != nil {
279278
return nil, newSystemError(err)
@@ -282,10 +281,15 @@ func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProces
282281
if err != nil {
283282
return nil, newSystemError(err)
284283
}
285-
if !doInit {
284+
switch it {
285+
case initCreate:
286+
return c.newCreateProcess(p, cmd, parentPipe, childPipe)
287+
case initSetns:
286288
return c.newSetnsProcess(p, cmd, parentPipe, childPipe)
289+
case initStandard:
290+
return c.newInitProcess(p, cmd, parentPipe, childPipe)
287291
}
288-
return c.newInitProcess(p, cmd, parentPipe, childPipe)
292+
panic(fmt.Sprintf("should not get here - it: %v", it))
289293
}
290294

291295
func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.Cmd, error) {
@@ -311,6 +315,35 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.
311315
return cmd, nil
312316
}
313317

318+
// newCreateProcess is the same as newInitProcess except the INITTYPE value
319+
// will differ.
320+
func (c *linuxContainer) newCreateProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) {
321+
t := "_LIBCONTAINER_INITTYPE=" + string(initCreate)
322+
cloneFlags := c.config.Namespaces.CloneFlags()
323+
if cloneFlags&syscall.CLONE_NEWUSER != 0 {
324+
if err := c.addUidGidMappings(cmd.SysProcAttr); err != nil {
325+
// user mappings are not supported
326+
return nil, err
327+
}
328+
enableSetgroups(cmd.SysProcAttr)
329+
// Default to root user when user namespaces are enabled.
330+
if cmd.SysProcAttr.Credential == nil {
331+
cmd.SysProcAttr.Credential = &syscall.Credential{}
332+
}
333+
}
334+
cmd.Env = append(cmd.Env, t)
335+
cmd.SysProcAttr.Cloneflags = cloneFlags
336+
return &initProcess{
337+
cmd: cmd,
338+
childPipe: childPipe,
339+
parentPipe: parentPipe,
340+
manager: c.cgroupManager,
341+
config: c.newInitConfig(p),
342+
container: c,
343+
process: p,
344+
}, nil
345+
}
346+
314347
func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) {
315348
t := "_LIBCONTAINER_INITTYPE=" + string(initStandard)
316349
cloneFlags := c.config.Namespaces.CloneFlags()

libcontainer/create_init_linux.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// +build linux
2+
3+
package libcontainer
4+
5+
import (
6+
"io"
7+
"os"
8+
"syscall"
9+
10+
"github.com/opencontainers/runc/libcontainer/apparmor"
11+
"github.com/opencontainers/runc/libcontainer/configs"
12+
"github.com/opencontainers/runc/libcontainer/label"
13+
"github.com/opencontainers/runc/libcontainer/seccomp"
14+
"github.com/opencontainers/runc/libcontainer/system"
15+
)
16+
17+
type linuxCreateInit struct {
18+
pipe io.ReadWriter
19+
parentPid int
20+
config *initConfig
21+
}
22+
23+
func (l *linuxCreateInit) Init() error {
24+
// join any namespaces via a path to the namespace fd if provided
25+
if err := joinExistingNamespaces(l.config.Config.Namespaces); err != nil {
26+
return err
27+
}
28+
var console *linuxConsole
29+
if l.config.Console != "" {
30+
console = newConsoleFromPath(l.config.Console)
31+
if err := console.dupStdio(); err != nil {
32+
return err
33+
}
34+
}
35+
if _, err := syscall.Setsid(); err != nil {
36+
return err
37+
}
38+
if console != nil {
39+
if err := system.Setctty(); err != nil {
40+
return err
41+
}
42+
}
43+
if err := setupNetwork(l.config); err != nil {
44+
return err
45+
}
46+
if err := setupRoute(l.config.Config); err != nil {
47+
return err
48+
}
49+
if err := setupRlimits(l.config.Config); err != nil {
50+
return err
51+
}
52+
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
53+
return err
54+
}
55+
label.Init()
56+
// InitializeMountNamespace() can be executed only for a new mount namespace
57+
if l.config.Config.Namespaces.Contains(configs.NEWNS) {
58+
if err := setupRootfs(l.config.Config, console); err != nil {
59+
return err
60+
}
61+
}
62+
if hostname := l.config.Config.Hostname; hostname != "" {
63+
if err := syscall.Sethostname([]byte(hostname)); err != nil {
64+
return err
65+
}
66+
}
67+
if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil {
68+
return err
69+
}
70+
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
71+
return err
72+
}
73+
74+
for key, value := range l.config.Config.Sysctl {
75+
if err := writeSystemProperty(key, value); err != nil {
76+
return err
77+
}
78+
}
79+
for _, path := range l.config.Config.ReadonlyPaths {
80+
if err := remountReadonly(path); err != nil {
81+
return err
82+
}
83+
}
84+
for _, path := range l.config.Config.MaskPaths {
85+
if err := maskFile(path); err != nil {
86+
return err
87+
}
88+
}
89+
pdeath, err := system.GetParentDeathSignal()
90+
if err != nil {
91+
return err
92+
}
93+
94+
// Tell our parent that we're ready to Execv. This must be done before the
95+
// Seccomp rules have been applied, because we need to be able to read and
96+
// write to a socket.
97+
if err := syncParentReady(l.pipe); err != nil {
98+
return err
99+
}
100+
if l.config.Config.Seccomp != nil {
101+
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
102+
return err
103+
}
104+
}
105+
if err := finalizeNamespace(l.config); err != nil {
106+
return err
107+
}
108+
// finalizeNamespace can change user/group which clears the parent death
109+
// signal, so we restore it here.
110+
if err := pdeath.Restore(); err != nil {
111+
return err
112+
}
113+
// compare the parent from the inital start of the init process and make sure that it did not change.
114+
// if the parent changes that means it died and we were reparened to something else so we should
115+
// just kill ourself and not cause problems for someone else.
116+
if syscall.Getppid() != l.parentPid {
117+
return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
118+
}
119+
120+
os.Exit(0)
121+
return nil
122+
}

libcontainer/init_linux.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ import (
2222
"github.com/vishvananda/netlink"
2323
)
2424

25+
// initType is the reason we're being called - the action should we take
2526
type initType string
2627

2728
const (
28-
initSetns initType = "setns"
29-
initStandard initType = "standard"
29+
initCreate initType = "create" // Just setting up the namespaces
30+
initSetns initType = "setns" // Joining and existing container
31+
initStandard initType = "standard" // Starting the main proces
3032
)
3133

3234
type pid struct {
@@ -68,6 +70,12 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
6870
return nil, err
6971
}
7072
switch t {
73+
case initCreate:
74+
return &linuxCreateInit{
75+
pipe: pipe,
76+
parentPid: syscall.Getppid(),
77+
config: config,
78+
}, nil
7179
case initSetns:
7280
return &linuxSetnsInit{
7381
config: config,

libcontainer/nsenter/nsexec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void nsexec()
9090

9191
// if we dont have INITTYPE or this is the init process, skip the bootstrap process
9292
val = getenv("_LIBCONTAINER_INITTYPE");
93-
if (val == NULL || strcmp(val, "standard") == 0) {
93+
if (val == NULL || strcmp(val, "standard") == 0 || strcmp(val, "create") == 0) {
9494
return;
9595
}
9696
if (strcmp(val, "setns") != 0) {

0 commit comments

Comments
 (0)