Skip to content

Commit 953e385

Browse files
committed
libpod: fix mount order for "/" volume
The count function for / and /proc results in the same value so the order is not guaranteed. We must ensure that a / mount is always first in the spec so that other mounts are not overshadowed by it. Fixes: #26161 Signed-off-by: Paul Holzinger <[email protected]>
1 parent 8f8a90a commit 953e385

File tree

2 files changed

+89
-18
lines changed

2 files changed

+89
-18
lines changed

libpod/util.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"net/http"
1313
"os"
1414
"path/filepath"
15-
"sort"
15+
"slices"
1616
"strconv"
1717
"strings"
1818
"time"
@@ -46,26 +46,28 @@ func MountExists(specMounts []spec.Mount, dest string) bool {
4646
return false
4747
}
4848

49-
type byDestination []spec.Mount
50-
51-
func (m byDestination) Len() int {
52-
return len(m)
53-
}
54-
55-
func (m byDestination) Less(i, j int) bool {
56-
return m.parts(i) < m.parts(j)
57-
}
58-
59-
func (m byDestination) Swap(i, j int) {
60-
m[i], m[j] = m[j], m[i]
61-
}
62-
63-
func (m byDestination) parts(i int) int {
64-
return strings.Count(filepath.Clean(m[i].Destination), string(os.PathSeparator))
49+
func parts(m spec.Mount) int {
50+
// We must special case a root mount /.
51+
// The count of "/" and "/proc" are both 1 but of course logically "/" must
52+
// be mounted before "/proc" as such set the count to 0.
53+
if m.Destination == "/" {
54+
return 0
55+
}
56+
return strings.Count(filepath.Clean(m.Destination), string(os.PathSeparator))
6557
}
6658

6759
func sortMounts(m []spec.Mount) []spec.Mount {
68-
sort.Sort(byDestination(m))
60+
slices.SortStableFunc(m, func(a, b spec.Mount) int {
61+
aLen := parts(a)
62+
bLen := parts(b)
63+
if aLen < bLen {
64+
return -1
65+
}
66+
if aLen == bLen {
67+
return 0
68+
}
69+
return 1
70+
})
6971
return m
7072
}
7173

libpod/util_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//go:build !remote
2+
3+
package libpod
4+
5+
import (
6+
"testing"
7+
8+
spec "github.com/opencontainers/runtime-spec/specs-go"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func Test_sortMounts(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
args []spec.Mount
16+
want []spec.Mount
17+
}{
18+
{
19+
name: "simple nested mounts",
20+
args: []spec.Mount{
21+
{
22+
Destination: "/abc/123",
23+
},
24+
{
25+
Destination: "/abc",
26+
},
27+
},
28+
want: []spec.Mount{
29+
{
30+
Destination: "/abc",
31+
},
32+
{
33+
Destination: "/abc/123",
34+
},
35+
},
36+
},
37+
{
38+
name: "root mount",
39+
args: []spec.Mount{
40+
{
41+
Destination: "/abc",
42+
},
43+
{
44+
Destination: "/",
45+
},
46+
{
47+
Destination: "/def",
48+
},
49+
},
50+
want: []spec.Mount{
51+
{
52+
Destination: "/",
53+
},
54+
{
55+
Destination: "/abc",
56+
},
57+
{
58+
Destination: "/def",
59+
},
60+
},
61+
},
62+
}
63+
for _, tt := range tests {
64+
t.Run(tt.name, func(t *testing.T) {
65+
got := sortMounts(tt.args)
66+
assert.Equal(t, tt.want, got)
67+
})
68+
}
69+
}

0 commit comments

Comments
 (0)