Skip to content

Commit 2875825

Browse files
authored
Merge pull request containerd#3365 from crosbymichael/exec-lk
Reserve exec id to prevent race
2 parents b2662f2 + 1a8df3f commit 2875825

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

runtime/v2/runc/container.go

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,11 @@ func NewContainer(ctx context.Context, platform rproc.Platform, r *task.CreateTa
125125
return nil, errdefs.ToGRPC(err)
126126
}
127127
container := &Container{
128-
ID: r.ID,
129-
Bundle: r.Bundle,
130-
process: process,
131-
processes: make(map[string]rproc.Process),
128+
ID: r.ID,
129+
Bundle: r.Bundle,
130+
process: process,
131+
processes: make(map[string]rproc.Process),
132+
reservedProcess: make(map[string]struct{}),
132133
}
133134
pid := process.Pid()
134135
if pid > 0 {
@@ -189,9 +190,10 @@ type Container struct {
189190
// Bundle path
190191
Bundle string
191192

192-
cgroup cgroups.Cgroup
193-
process rproc.Process
194-
processes map[string]rproc.Process
193+
cgroup cgroups.Cgroup
194+
process rproc.Process
195+
processes map[string]rproc.Process
196+
reservedProcess map[string]struct{}
195197
}
196198

197199
// All processes in the container
@@ -256,18 +258,35 @@ func (c *Container) Process(id string) (rproc.Process, error) {
256258
return p, nil
257259
}
258260

259-
// ProcessExists returns true if the process by id exists
260-
func (c *Container) ProcessExists(id string) bool {
261+
// ReserveProcess checks for the existence of an id and atomically
262+
// reserves the process id if it does not already exist
263+
//
264+
// Returns true if the process id was sucessfully reserved and a
265+
// cancel func to release the reservation
266+
func (c *Container) ReserveProcess(id string) (bool, func()) {
261267
c.mu.Lock()
262268
defer c.mu.Unlock()
263-
_, ok := c.processes[id]
264-
return ok
269+
270+
if _, ok := c.processes[id]; ok {
271+
return false, nil
272+
}
273+
if _, ok := c.reservedProcess[id]; ok {
274+
return false, nil
275+
}
276+
c.reservedProcess[id] = struct{}{}
277+
return true, func() {
278+
c.mu.Lock()
279+
defer c.mu.Unlock()
280+
delete(c.reservedProcess, id)
281+
}
265282
}
266283

267284
// ProcessAdd adds a new process to the container
268285
func (c *Container) ProcessAdd(process rproc.Process) {
269286
c.mu.Lock()
270287
defer c.mu.Unlock()
288+
289+
delete(c.reservedProcess, process.ID())
271290
c.processes[process.ID()] = process
272291
}
273292

runtime/v2/runc/v1/service.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,13 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*pty
326326
if err != nil {
327327
return nil, err
328328
}
329-
if container.ProcessExists(r.ExecID) {
329+
ok, cancel := container.ReserveProcess(r.ExecID)
330+
if !ok {
330331
return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID)
331332
}
332333
process, err := container.Exec(ctx, r)
333334
if err != nil {
335+
cancel()
334336
return nil, errdefs.ToGRPC(err)
335337
}
336338

runtime/v2/runc/v2/service.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,13 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*pty
375375
if err != nil {
376376
return nil, err
377377
}
378-
if container.ProcessExists(r.ExecID) {
378+
ok, cancel := container.ReserveProcess(r.ExecID)
379+
if !ok {
379380
return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID)
380381
}
381382
process, err := container.Exec(ctx, r)
382383
if err != nil {
384+
cancel()
383385
return nil, errdefs.ToGRPC(err)
384386
}
385387

0 commit comments

Comments
 (0)