Skip to content

Commit 4b9b3e8

Browse files
committed
Add WithAmbientCapabilities opt
Closes #2516 This can be used for non-root users binding to low ports. Signed-off-by: Michael Crosby <[email protected]>
1 parent 0a3f87e commit 4b9b3e8

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

container_linux_test.go

+117
Original file line numberDiff line numberDiff line change
@@ -1356,3 +1356,120 @@ func TestUIDNoGID(t *testing.T) {
13561356
t.Fatalf("expected gid 0 but received %d", gid)
13571357
}
13581358
}
1359+
1360+
func TestBindLowPortNonRoot(t *testing.T) {
1361+
t.Parallel()
1362+
1363+
client, err := newClient(t, address)
1364+
if err != nil {
1365+
t.Fatal(err)
1366+
}
1367+
defer client.Close()
1368+
1369+
var (
1370+
image Image
1371+
ctx, cancel = testContext()
1372+
id = t.Name()
1373+
)
1374+
defer cancel()
1375+
1376+
image, err = client.GetImage(ctx, testImage)
1377+
if err != nil {
1378+
t.Fatal(err)
1379+
}
1380+
container, err := client.NewContainer(ctx, id,
1381+
WithNewSnapshot(id, image),
1382+
WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000)),
1383+
)
1384+
if err != nil {
1385+
t.Fatal(err)
1386+
}
1387+
defer container.Delete(ctx, WithSnapshotCleanup)
1388+
1389+
task, err := container.NewTask(ctx, empty())
1390+
if err != nil {
1391+
t.Fatal(err)
1392+
}
1393+
defer task.Delete(ctx)
1394+
1395+
statusC, err := task.Wait(ctx)
1396+
if err != nil {
1397+
t.Fatal(err)
1398+
}
1399+
1400+
if err := task.Start(ctx); err != nil {
1401+
t.Fatal(err)
1402+
}
1403+
status := <-statusC
1404+
code, _, err := status.Result()
1405+
if err != nil {
1406+
t.Fatal(err)
1407+
}
1408+
if code != 1 {
1409+
t.Errorf("expected status 1 from wait but received %d", code)
1410+
}
1411+
if _, err := task.Delete(ctx); err != nil {
1412+
t.Fatal(err)
1413+
}
1414+
}
1415+
1416+
func TestBindLowPortNonOpt(t *testing.T) {
1417+
t.Parallel()
1418+
1419+
client, err := newClient(t, address)
1420+
if err != nil {
1421+
t.Fatal(err)
1422+
}
1423+
defer client.Close()
1424+
1425+
var (
1426+
image Image
1427+
ctx, cancel = testContext()
1428+
id = t.Name()
1429+
)
1430+
defer cancel()
1431+
1432+
image, err = client.GetImage(ctx, testImage)
1433+
if err != nil {
1434+
t.Fatal(err)
1435+
}
1436+
container, err := client.NewContainer(ctx, id,
1437+
WithNewSnapshot(id, image),
1438+
WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000), oci.WithAmbientCapabilities([]string{"CAP_NET_BIND_SERVICE"})),
1439+
)
1440+
if err != nil {
1441+
t.Fatal(err)
1442+
}
1443+
defer container.Delete(ctx, WithSnapshotCleanup)
1444+
1445+
task, err := container.NewTask(ctx, empty())
1446+
if err != nil {
1447+
t.Fatal(err)
1448+
}
1449+
defer task.Delete(ctx)
1450+
1451+
statusC, err := task.Wait(ctx)
1452+
if err != nil {
1453+
t.Fatal(err)
1454+
}
1455+
1456+
if err := task.Start(ctx); err != nil {
1457+
t.Fatal(err)
1458+
}
1459+
go func() {
1460+
time.Sleep(2 * time.Second)
1461+
task.Kill(ctx, unix.SIGTERM)
1462+
}()
1463+
status := <-statusC
1464+
code, _, err := status.Result()
1465+
if err != nil {
1466+
t.Fatal(err)
1467+
}
1468+
// 128 + sigterm
1469+
if code != 143 {
1470+
t.Errorf("expected status 143 from wait but received %d", code)
1471+
}
1472+
if _, err := task.Delete(ctx); err != nil {
1473+
t.Fatal(err)
1474+
}
1475+
}

oci/spec_opts_unix.go

+12
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,18 @@ func getAllCapabilities() []string {
486486
return caps
487487
}
488488

489+
// WithAmbientCapabilities set the Linux ambient capabilities for the process
490+
// Ambient capabilities should only be set for non-root users or the caller should
491+
// understand how these capabilities are used and set
492+
func WithAmbientCapabilities(caps []string) SpecOpts {
493+
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
494+
setCapabilities(s)
495+
496+
s.Process.Capabilities.Ambient = caps
497+
return nil
498+
}
499+
}
500+
489501
var errNoUsersFound = errors.New("no users found")
490502

491503
func getUIDGIDFromPath(root string, filter func(user.User) bool) (uid, gid uint32, err error) {

0 commit comments

Comments
 (0)