Skip to content

Commit 42aefa6

Browse files
committed
Add tests for xattr error handling in exec_binfmt
Signed-off-by: Tiger Kaovilai <[email protected]>
1 parent 2bbdbe6 commit 42aefa6

File tree

2 files changed

+113
-8
lines changed

2 files changed

+113
-8
lines changed

solver/llbsolver/ops/exec_binfmt.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,7 @@ func (m *staticEmulatorMount) Mount() ([]mount.Mount, func() error, error) {
6565
if err := copy.Copy(context.TODO(), filepath.Dir(m.path), filepath.Base(m.path), tmpdir, qemuMountName, func(ci *copy.CopyInfo) {
6666
m := 0555
6767
ci.Mode = &m
68-
}, copy.WithChown(uid, gid), copy.WithXAttrErrorHandler(func(dst, src, xattrKey string, err error) error {
69-
// Only ignore ENOTSUP errors specifically for security.selinux xattr
70-
// This addresses the SELinux issue while being more targeted than ignoring all ENOTSUP errors
71-
if errors.Is(err, syscall.ENOTSUP) && xattrKey == "security.selinux" {
72-
return nil
73-
}
74-
return err
75-
})); err != nil {
68+
}, copy.WithChown(uid, gid), copy.WithXAttrErrorHandler(createSELinuxXAttrErrorHandler())); err != nil {
7669
return nil, nil, err
7770
}
7871

@@ -131,3 +124,22 @@ func getEmulator(ctx context.Context, p *pb.Platform) (*emulator, error) {
131124

132125
return &emulator{path: fn}, nil
133126
}
127+
128+
// createSELinuxXAttrErrorHandler creates an error handler for xattr copy operations
129+
// that specifically ignores ENOTSUP errors for security.selinux extended attributes.
130+
// This addresses SELinux compatibility issues where copying files to filesystems that
131+
// don't support SELinux xattrs (like tmpfs) would fail with ENOTSUP, preventing
132+
// qemu emulator setup on SELinux-enabled systems. Since the security.selinux xattr
133+
// is not critical for the emulator functionality, we safely ignore these errors
134+
// while preserving other xattr error handling.
135+
func createSELinuxXAttrErrorHandler() func(dst, src, xattrKey string, err error) error {
136+
return func(dst, src, xattrKey string, err error) error {
137+
// Ignore ENOTSUP errors specifically for security.selinux xattr
138+
// This allows qemu emulator setup to succeed on SELinux systems
139+
// when copying to filesystems that don't support SELinux xattrs
140+
if errors.Is(err, syscall.ENOTSUP) && xattrKey == "security.selinux" {
141+
return nil
142+
}
143+
return err
144+
}
145+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package ops
2+
3+
import (
4+
"syscall"
5+
"testing"
6+
7+
"github.com/pkg/errors"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestBinfmtXAttrErrorHandler(t *testing.T) {
12+
handler := createSELinuxXAttrErrorHandler()
13+
14+
tests := []struct {
15+
name string
16+
dst string
17+
src string
18+
xattrKey string
19+
inputErr error
20+
expectErr bool
21+
description string
22+
}{
23+
{
24+
name: "ENOTSUP_security_selinux_ignored",
25+
dst: "/tmp/dest",
26+
src: "/tmp/src",
27+
xattrKey: "security.selinux",
28+
inputErr: syscall.ENOTSUP,
29+
expectErr: false,
30+
description: "ENOTSUP error for security.selinux should be ignored",
31+
},
32+
{
33+
name: "ENOTSUP_other_xattr_propagated",
34+
dst: "/tmp/dest",
35+
src: "/tmp/src",
36+
xattrKey: "user.some_attr",
37+
inputErr: syscall.ENOTSUP,
38+
expectErr: true,
39+
description: "ENOTSUP error for non-selinux xattr should propagate",
40+
},
41+
{
42+
name: "ENOTSUP_security_capability_propagated",
43+
dst: "/tmp/dest",
44+
src: "/tmp/src",
45+
xattrKey: "security.capability",
46+
inputErr: syscall.ENOTSUP,
47+
expectErr: true,
48+
description: "ENOTSUP error for other security xattr should propagate",
49+
},
50+
{
51+
name: "other_error_security_selinux_propagated",
52+
dst: "/tmp/dest",
53+
src: "/tmp/src",
54+
xattrKey: "security.selinux",
55+
inputErr: syscall.EPERM,
56+
expectErr: true,
57+
description: "Non-ENOTSUP errors should always propagate",
58+
},
59+
{
60+
name: "wrapped_ENOTSUP_error_handled",
61+
dst: "/tmp/dest",
62+
src: "/tmp/src",
63+
xattrKey: "security.selinux",
64+
inputErr: errors.Wrap(syscall.ENOTSUP, "wrapped error"),
65+
expectErr: false,
66+
description: "Wrapped ENOTSUP errors should be handled with errors.Is",
67+
},
68+
{
69+
name: "nil_error_returns_nil",
70+
dst: "/tmp/dest",
71+
src: "/tmp/src",
72+
xattrKey: "security.selinux",
73+
inputErr: nil,
74+
expectErr: false,
75+
description: "Nil error should return nil",
76+
},
77+
}
78+
79+
for _, tt := range tests {
80+
t.Run(tt.name, func(t *testing.T) {
81+
t.Parallel()
82+
83+
result := handler(tt.dst, tt.src, tt.xattrKey, tt.inputErr)
84+
85+
if tt.expectErr {
86+
require.Error(t, result, tt.description)
87+
require.Equal(t, tt.inputErr, result, "Error should be propagated unchanged")
88+
} else {
89+
require.NoError(t, result, tt.description)
90+
}
91+
})
92+
}
93+
}

0 commit comments

Comments
 (0)