@@ -8,6 +8,7 @@ package security
88import (
99 "fmt"
1010 "os"
11+ "os/exec"
1112 "testing"
1213
1314 "github.com/sylabs/singularity/v4/e2e/internal/e2e"
@@ -231,6 +232,124 @@ func (c ctx) testSecurityConfOwnership(t *testing.T) {
231232 )
232233}
233234
235+ // testApparmor tests the apparmor security flag.
236+ func (c ctx ) testApparmor (t * testing.T ) {
237+ require .Apparmor (t )
238+ e2e .EnsureImage (t , c .env )
239+
240+ tests := []struct {
241+ name string
242+ image string
243+ argv []string
244+ opts []string
245+ expectOp e2e.SingularityCmdResultOp
246+ expectExit int
247+ }{
248+ // apparmor
249+ // Uses the profile for /usr/bin/man which will block `ls` in container root.
250+ {
251+ name : "apparmor applied" ,
252+ argv : []string {"cat" , "/proc/self/attr/current" },
253+ opts : []string {"--security" , "apparmor:/usr/bin/man" },
254+ expectOp : e2e .ExpectOutput (e2e .ExactMatch , "/usr/bin/man (enforce)" ),
255+ },
256+ {
257+ name : "apparmor denial" ,
258+ argv : []string {"ls" , "/" },
259+ opts : []string {"--security" , "apparmor:/usr/bin/man" },
260+ expectExit : 1 ,
261+ expectOp : e2e .ExpectError (e2e .ContainMatch , "Permission denied" ),
262+ },
263+ }
264+
265+ for _ , profile := range e2e .NativeProfiles {
266+ t .Run (profile .String (), func (t * testing.T ) {
267+ for _ , tt := range tests {
268+ optArgs := []string {}
269+ optArgs = append (optArgs , tt .opts ... )
270+ optArgs = append (optArgs , c .env .ImagePath )
271+ optArgs = append (optArgs , tt .argv ... )
272+
273+ c .env .RunSingularity (
274+ t ,
275+ e2e .AsSubtest (tt .name ),
276+ e2e .WithProfile (profile ),
277+ e2e .WithCommand ("exec" ),
278+ e2e .WithArgs (optArgs ... ),
279+ e2e .ExpectExit (tt .expectExit , tt .expectOp ),
280+ )
281+ }
282+ })
283+ }
284+ }
285+
286+ // testSELinux tests the selinux security flag.
287+ func (c ctx ) testSELinux (t * testing.T ) {
288+ require .Selinux (t )
289+ require .Command (t , "chcon" )
290+ e2e .EnsureImage (t , c .env )
291+
292+ sandbox , cleanup := e2e .MakeTempDir (t , c .env .TestDir , "sandbox-" , "" )
293+ defer cleanup (t )
294+ // convert test image to sandbox
295+ c .env .RunSingularity (
296+ t ,
297+ e2e .WithProfile (e2e .UserProfile ),
298+ e2e .WithCommand ("build" ),
299+ e2e .WithArgs ("--force" , "--sandbox" , sandbox , c .env .ImagePath ),
300+ e2e .ExpectExit (0 ),
301+ )
302+ // label as `container_ro_t`
303+ cmd := exec .Command ("chcon" , "-R" , "-t" , "container_ro_file_t" , sandbox )
304+ if err := cmd .Run (); err != nil {
305+ t .Fatalf ("while labeling sandbox: %v" , err )
306+ }
307+
308+ tests := []struct {
309+ name string
310+ image string
311+ argv []string
312+ opts []string
313+ expectOp e2e.SingularityCmdResultOp
314+ expectExit int
315+ }{
316+ // selinux
317+ // Uses the container_t label which will block `ls` in /tmp bind from host.
318+ {
319+ name : "selinux applied" ,
320+ argv : []string {"cat" , "/proc/self/attr/current" },
321+ opts : []string {"--security" , "selinux:unconfined_u:unconfined_r:container_t:s0" },
322+ expectOp : e2e .ExpectOutput (e2e .ContainMatch , "unconfined_u:unconfined_r:container_t:s0" ),
323+ },
324+ {
325+ name : "selinux denial" ,
326+ argv : []string {"ls" , "/tmp" },
327+ opts : []string {"--security" , "selinux:unconfined_u:unconfined_r:container_t:s0" },
328+ expectExit : 1 ,
329+ expectOp : e2e .ExpectError (e2e .ContainMatch , "Permission denied" ),
330+ },
331+ }
332+ for _ , profile := range e2e .NativeProfiles {
333+ t .Run (profile .String (), func (t * testing.T ) {
334+ for _ , tt := range tests {
335+ optArgs := []string {}
336+ optArgs = append (optArgs , tt .opts ... )
337+ optArgs = append (optArgs , sandbox )
338+ optArgs = append (optArgs , tt .argv ... )
339+
340+ c .env .RunSingularity (
341+ t ,
342+ e2e .AsSubtest (tt .name ),
343+ e2e .WithProfile (profile ),
344+ e2e .WithCommand ("exec" ),
345+ e2e .WithArgs (optArgs ... ),
346+ e2e .ExpectExit (tt .expectExit , tt .expectOp ),
347+ )
348+ }
349+ })
350+ }
351+ }
352+
234353// E2ETests is the main func to trigger the test suite
235354func E2ETests (env e2e.TestEnv ) testhelper.Tests {
236355 c := ctx {
@@ -243,6 +362,8 @@ func E2ETests(env e2e.TestEnv) testhelper.Tests {
243362 "singularitySecurityUnpriv" : c .testSecurityUnpriv ,
244363 "singularitySecurityPriv" : c .testSecurityPriv ,
245364 "testSecurityConfOwnership" : np (c .testSecurityConfOwnership ),
365+ "testApparmor" : c .testApparmor ,
366+ "testSELinux" : c .testSELinux ,
246367 // OCI-Mode
247368 "ociCapabilities" : c .ociCapabilities ,
248369 }
0 commit comments