github.com/apptainer/singularity@v3.1.1+incompatible/internal/pkg/util/fs/mount/mount_test.go (about)

     1  // Copyright (c) 2018, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package mount
     7  
     8  import (
     9  	"fmt"
    10  	"syscall"
    11  	"testing"
    12  
    13  	specs "github.com/opencontainers/runtime-spec/specs-go"
    14  	"github.com/sylabs/singularity/internal/pkg/test"
    15  )
    16  
    17  func TestImage(t *testing.T) {
    18  	test.DropPrivilege(t)
    19  	defer test.ResetPrivilege(t)
    20  
    21  	points := &Points{}
    22  
    23  	if err := points.AddImage(RootfsTag, "", "/fake", "ext3", 0, 0, 10); err == nil {
    24  		t.Errorf("should have failed with empty source")
    25  	}
    26  	if err := points.AddImage(RootfsTag, "/fake", "", "ext3", 0, 0, 10); err == nil {
    27  		t.Errorf("should have failed with empty destination")
    28  	}
    29  
    30  	if err := points.AddImage(RootfsTag, "fake", "/", "ext3", 0, 0, 10); err == nil {
    31  		t.Errorf("should have failed as source is not an absolute path")
    32  	}
    33  	if err := points.AddImage(RootfsTag, "/", "fake", "ext3", 0, 0, 10); err == nil {
    34  		t.Errorf("should have failed as destination is not an absolute path")
    35  	}
    36  
    37  	if err := points.AddImage(RootfsTag, "", "/", "ext3", 0, 0, 10); err == nil {
    38  		t.Errorf("should have failed with empty source")
    39  	}
    40  	if err := points.AddImage(RootfsTag, "/fake", "/", "xfs", 0, 0, 10); err == nil {
    41  		t.Errorf("should have failed with bad filesystem type")
    42  	}
    43  	if err := points.AddImage(RootfsTag, "/fake", "/", "ext3", syscall.MS_BIND, 0, 10); err == nil {
    44  		t.Errorf("should have failed with bad bind flag")
    45  	}
    46  	if err := points.AddImage(RootfsTag, "/fake", "/", "ext3", syscall.MS_REMOUNT, 0, 10); err == nil {
    47  		t.Errorf("should have failed with bad remount flag")
    48  	}
    49  	if err := points.AddImage(RootfsTag, "/fake", "/", "ext3", syscall.MS_REC, 0, 10); err == nil {
    50  		t.Errorf("should have failed with bad recursive flag")
    51  	}
    52  	if err := points.AddImage(RootfsTag, "/fake", "/ext3", "ext3", 0, 0, 10); err != nil {
    53  		t.Errorf("should have passed with ext3 filesystem")
    54  	}
    55  	points.RemoveAll()
    56  	if err := points.AddImage(RootfsTag, "/fake", "/squash", "squashfs", 0, 0, 10); err != nil {
    57  		t.Errorf("should have passed with squashfs filesystem")
    58  	}
    59  	if err := points.AddImage(RootfsTag, "/fake", "/", "squashfs", 0, 0, 0); err == nil {
    60  		t.Errorf("should have failed with 0 size limit")
    61  	}
    62  	if err := points.AddImage(RootfsTag, "/fake", "/squash", "squashfs", 0, 0, 10); err == nil {
    63  		t.Errorf("nil error returned, should have returned non-nil mount.ErrMountExists")
    64  	} else if err != nil && err != ErrMountExists {
    65  		t.Errorf("non-nil error should have been mount.ErrMountExists")
    66  	}
    67  	points.RemoveAll()
    68  
    69  	if err := points.AddImage(RootfsTag, "/fake", "/", "squashfs", syscall.MS_NOSUID, 31, 10); err != nil {
    70  		t.Fatalf("should have passed with squashfs filesystem")
    71  	}
    72  	images := points.GetAllImages()
    73  	if len(images) != 1 {
    74  		t.Fatalf("should get only one registered image")
    75  	}
    76  	hasNoSuid := false
    77  	for _, option := range images[0].Options {
    78  		if option == "nosuid" {
    79  			hasNoSuid = true
    80  		}
    81  	}
    82  	if offset, err := GetOffset(images[0].InternalOptions); err != nil || offset != 31 {
    83  		t.Errorf("offset option wasn't found or is invalid")
    84  	}
    85  	if size, err := GetSizeLimit(images[0].InternalOptions); err != nil || size != 10 {
    86  		t.Errorf("sizelimit option wasn't found or is invalid")
    87  	}
    88  	if _, err := GetOffset([]string{}); err == nil {
    89  		t.Errorf("should have failed, offset not provided")
    90  	}
    91  	if _, err := GetSizeLimit([]string{}); err == nil {
    92  		t.Errorf("should have failed, sizelimit not provided")
    93  	}
    94  	if !hasNoSuid {
    95  		t.Errorf("nosuid option wasn't applied")
    96  	}
    97  	points.RemoveByDest("/")
    98  	if len(points.GetAllImages()) != 0 {
    99  		t.Errorf("failed to remove image from mount point")
   100  	}
   101  }
   102  
   103  func TestOverlay(t *testing.T) {
   104  	test.DropPrivilege(t)
   105  	defer test.ResetPrivilege(t)
   106  
   107  	points := &Points{}
   108  
   109  	if err := points.AddOverlay(LayerTag, "", 0, "/", "", ""); err == nil {
   110  		t.Errorf("should have failed with empty destination")
   111  	}
   112  	if err := points.AddOverlay(LayerTag, "/fake", 0, "", "/upper", "/work"); err == nil {
   113  		t.Errorf("should have failed with empty lowerdir")
   114  	}
   115  	if err := points.AddOverlay(LayerTag, "/fake", 0, "/lower", "/upper", ""); err == nil {
   116  		t.Errorf("should have failed with empty workdir")
   117  	}
   118  
   119  	if err := points.AddOverlay(LayerTag, "/", 0, "lower", "", ""); err == nil {
   120  		t.Errorf("should have failed as lowerdir is not an absolute path")
   121  	}
   122  	if err := points.AddOverlay(LayerTag, "/", 0, "/lower", "upper", "/work"); err == nil {
   123  		t.Errorf("should have failed as upperdir is not an absolute path")
   124  	}
   125  	if err := points.AddOverlay(LayerTag, "/", 0, "/lower", "/upper", "work"); err == nil {
   126  		t.Errorf("should have failed as workdir is not an absolute path")
   127  	}
   128  
   129  	if err := points.AddOverlay(LayerTag, "/fake", syscall.MS_BIND, "/lower", "", ""); err == nil {
   130  		t.Errorf("should have failed with bad bind flag")
   131  	}
   132  	if err := points.AddOverlay(LayerTag, "/fake", syscall.MS_REMOUNT, "/lower", "", ""); err == nil {
   133  		t.Errorf("should have failed with bad remount flag")
   134  	}
   135  	if err := points.AddOverlay(LayerTag, "/fake", syscall.MS_REC, "/lower", "", ""); err == nil {
   136  		t.Errorf("should have failed with bad recursive flag")
   137  	}
   138  	points.RemoveAll()
   139  
   140  	if err := points.AddOverlay(LayerTag, "/fake", 0, "/lower", "", ""); err != nil {
   141  		t.Errorf("%s", err)
   142  	}
   143  	points.RemoveAll()
   144  
   145  	if err := points.AddOverlay(LayerTag, "/fake", 0, "/lower", "/upper", "/work"); err != nil {
   146  		t.Errorf("%s", err)
   147  	}
   148  	points.RemoveAll()
   149  
   150  	if err := points.AddOverlay(LayerTag, "/mnt", syscall.MS_NOSUID, "/lower", "/upper", "/work"); err != nil {
   151  		t.Fatalf("%s", err)
   152  	}
   153  
   154  	overlay := points.GetByDest("/mnt")
   155  	if len(overlay) != 1 {
   156  		t.Fatalf("one filesystem mount points should be returned")
   157  	}
   158  	hasNoSuid := false
   159  	for _, option := range overlay[0].Options {
   160  		if option == "nosuid" {
   161  			hasNoSuid = true
   162  		}
   163  	}
   164  	if !hasNoSuid {
   165  		t.Errorf("option nosuid not applied for /mnt")
   166  	}
   167  }
   168  
   169  func TestFS(t *testing.T) {
   170  	test.DropPrivilege(t)
   171  	defer test.ResetPrivilege(t)
   172  
   173  	points := &Points{}
   174  
   175  	if err := points.AddFS(SessionTag, "", "tmpfs", 0, ""); err == nil {
   176  		t.Errorf("should have failed with empty destination")
   177  	}
   178  	if err := points.AddFS(SessionTag, "fake", "tmpfs", 0, ""); err == nil {
   179  		t.Errorf("should have failed as destination is not an absolute path")
   180  	}
   181  
   182  	if err := points.AddFS(SessionTag, "fake", "tmpfs", syscall.MS_BIND, ""); err == nil {
   183  		t.Errorf("should have failed with bad bind flag")
   184  	}
   185  	if err := points.AddFS(SessionTag, "fake", "tmpfs", syscall.MS_REMOUNT, ""); err == nil {
   186  		t.Errorf("should have failed with bad remount flag")
   187  	}
   188  	if err := points.AddFS(SessionTag, "fake", "tmpfs", syscall.MS_REC, ""); err == nil {
   189  		t.Errorf("should have failed with bad recursive flag")
   190  	}
   191  
   192  	points.RemoveAll()
   193  
   194  	if err := points.AddFS(SessionTag, "/fields/of", "cows", 0, ""); err == nil {
   195  		t.Errorf("should have failed as filesystem is not authorized")
   196  	}
   197  
   198  	fs := points.GetAllFS()
   199  	if len(fs) != 0 {
   200  		t.Errorf("no filesystem mount points should be returned")
   201  	}
   202  	points.RemoveAll()
   203  
   204  	if err := points.AddFS(SessionTag, "/mnt", "tmpfs", syscall.MS_NOSUID, ""); err != nil {
   205  		t.Fatalf("%s", err)
   206  	}
   207  
   208  	fs = points.GetByDest("/mnt")
   209  	if len(fs) != 1 {
   210  		t.Fatalf("one filesystem mount points should be returned")
   211  	}
   212  	hasNoSuid := false
   213  	for _, option := range fs[0].Options {
   214  		if option == "nosuid" {
   215  			hasNoSuid = true
   216  		}
   217  	}
   218  	if !hasNoSuid {
   219  		t.Errorf("option nosuid not applied for /mnt")
   220  	}
   221  }
   222  
   223  func TestBind(t *testing.T) {
   224  	test.DropPrivilege(t)
   225  	defer test.ResetPrivilege(t)
   226  
   227  	points := &Points{}
   228  
   229  	if err := points.AddBind(UserbindsTag, "/", "", 0); err == nil {
   230  		t.Errorf("should have failed with empty destination")
   231  	}
   232  
   233  	if err := points.AddBind(UserbindsTag, "fake", "/", 0); err == nil {
   234  		t.Errorf("should have failed as source is not an absolute path")
   235  	}
   236  	if err := points.AddBind(UserbindsTag, "/", "fake", 0); err == nil {
   237  		t.Errorf("should have failed as destination is not an absolute path")
   238  	}
   239  	points.RemoveAll()
   240  
   241  	if err := points.AddBind(UserbindsTag, "/", "/mnt", syscall.MS_BIND); err != nil {
   242  		t.Fatalf("%s", err)
   243  	}
   244  	bind := points.GetByDest("/mnt")
   245  	if len(bind) != 1 {
   246  		t.Fatalf("more than one mount point for /mnt has been returned")
   247  	}
   248  	hasBind := false
   249  	for _, option := range bind[0].Options {
   250  		if option == "bind" {
   251  			hasBind = true
   252  		}
   253  	}
   254  	if !hasBind {
   255  		t.Errorf("option bind not applied for /mnt")
   256  	}
   257  	points.RemoveAll()
   258  
   259  	if err := points.AddBind(UserbindsTag, "/", "/mnt", syscall.MS_BIND|syscall.MS_REC); err != nil {
   260  		t.Fatalf("%s", err)
   261  	}
   262  	bind = points.GetByDest("/mnt")
   263  	if len(bind) != 1 {
   264  		t.Fatalf("more than one mount point for /mnt has been returned")
   265  	}
   266  	bind = points.GetBySource("/")
   267  	if len(bind) != 1 {
   268  		t.Fatalf("more than one mount point for / has been returned")
   269  	}
   270  	hasBind = false
   271  	for _, option := range bind[0].Options {
   272  		if option == "rbind" {
   273  			hasBind = true
   274  		}
   275  	}
   276  	if !hasBind {
   277  		t.Errorf("option rbind not applied for /mnt")
   278  	}
   279  }
   280  
   281  func TestRemount(t *testing.T) {
   282  	test.DropPrivilege(t)
   283  	defer test.ResetPrivilege(t)
   284  
   285  	points := &Points{}
   286  
   287  	if err := points.AddRemount(UserbindsTag, "", 0); err == nil {
   288  		t.Errorf("should have failed with empty destination")
   289  	}
   290  	if err := points.AddRemount(UserbindsTag, "fake", 0); err == nil {
   291  		t.Errorf("should have failed as destination is not an absolute path")
   292  	}
   293  	points.RemoveAll()
   294  }
   295  
   296  func TestAddPropagation(t *testing.T) {
   297  	test.DropPrivilege(t)
   298  	defer test.ResetPrivilege(t)
   299  
   300  	points := &Points{}
   301  
   302  	if err := points.AddPropagation(UserbindsTag, "", 0); err == nil {
   303  		t.Errorf("should have failed with empty destination")
   304  	}
   305  	if err := points.AddPropagation(UserbindsTag, "/mnt", 0); err == nil {
   306  		t.Errorf("should have failed with no propagation flag found")
   307  	}
   308  	if err := points.AddPropagation(UserbindsTag, "/mnt", syscall.MS_SHARED|syscall.MS_REC); err != nil {
   309  		t.Error(err)
   310  	}
   311  
   312  	points.RemoveAll()
   313  }
   314  
   315  func TestImport(t *testing.T) {
   316  	test.DropPrivilege(t)
   317  	defer test.ResetPrivilege(t)
   318  
   319  	mountLabel := "system_u:object_r:removable_t"
   320  	points := &Points{}
   321  
   322  	if err := points.SetContext(mountLabel); err != nil {
   323  		t.Fatalf("should have passed since context is not set")
   324  	}
   325  	if err := points.SetContext(mountLabel); err == nil {
   326  		t.Fatalf("should have failed since context has already been set")
   327  	}
   328  	if points.GetContext() != mountLabel {
   329  		t.Fatalf("%s != %s", mountLabel, points.GetContext())
   330  	}
   331  
   332  	validImport := map[AuthorizedTag][]Point{
   333  		UserbindsTag: {
   334  			{
   335  				Mount: specs.Mount{
   336  					Source:      "/",
   337  					Destination: "/mnt",
   338  					Type:        "",
   339  					Options:     []string{"rbind", "nosuid"},
   340  				},
   341  			},
   342  		},
   343  		KernelTag: {
   344  			{
   345  				Mount: specs.Mount{
   346  					Source:      "proc",
   347  					Destination: "/proc",
   348  					Type:        "proc",
   349  					Options:     []string{"nosuid", "nodev"},
   350  				},
   351  			},
   352  			{
   353  				Mount: specs.Mount{
   354  					Source:      "sysfs",
   355  					Destination: "/sys",
   356  					Type:        "sysfs",
   357  					Options:     []string{"nosuid", "nodev"},
   358  				},
   359  			},
   360  		},
   361  		SessionTag: {
   362  			{
   363  				Mount: specs.Mount{
   364  					Source:      "",
   365  					Destination: "/tmp",
   366  					Type:        "tmpfs",
   367  					Options:     []string{"nosuid", "nodev", "mode=1777"},
   368  				},
   369  			},
   370  		},
   371  		LayerTag: {
   372  			{
   373  				Mount: specs.Mount{
   374  					Source:      "",
   375  					Destination: "/opt",
   376  					Type:        "overlay",
   377  					Options:     []string{"nosuid", "nodev", "lowerdir=/", "upperdir=/upper", "workdir=/work"},
   378  				},
   379  			},
   380  		},
   381  		RootfsTag: {
   382  			{
   383  				Mount: specs.Mount{
   384  					Source:      "/image.simg",
   385  					Destination: "/tmp/image",
   386  					Type:        "squashfs",
   387  					Options:     []string{"nosuid", "nodev"},
   388  				},
   389  				InternalOptions: []string{"offset=31", "sizelimit=10"},
   390  			},
   391  		},
   392  	}
   393  	if err := points.Import(validImport); err != nil {
   394  		t.Fatalf("%s", err)
   395  	}
   396  	if len(points.GetAll()) != len(validImport) {
   397  		t.Errorf("returned a wrong number of mount points %d instead of %d", len(points.GetAll()), len(validImport))
   398  	}
   399  	image := points.GetAllImages()
   400  	if len(image) != 1 {
   401  		t.Errorf("wrong number of image mount point found")
   402  	}
   403  	overlay := points.GetAllOverlays()
   404  	if len(overlay) != 1 {
   405  		t.Errorf("wrong number of overlay mount point found")
   406  	}
   407  	bind := points.GetAllBinds()
   408  	if len(bind) != 1 {
   409  		t.Errorf("wrong number of bind mount point found")
   410  	}
   411  	fs := points.GetAllFS()
   412  	if len(fs) != 3 {
   413  		t.Errorf("wrong number of filesystem mount point found")
   414  	}
   415  	points.RemoveByDest("/mnt")
   416  	all := points.GetByTag(UserbindsTag)
   417  	if len(all) != 0 {
   418  		t.Errorf("returned a wrong number of mount points %d instead of 0", len(all))
   419  	}
   420  	points.RemoveByDest("/tmp")
   421  	all = points.GetByTag(SessionTag)
   422  	if len(all) != 0 {
   423  		t.Errorf("returned a wrong number of mount points %d instead of 0", len(all))
   424  	}
   425  	points.RemoveByDest("/opt")
   426  	all = points.GetByTag(LayerTag)
   427  	if len(all) != 0 {
   428  		t.Errorf("returned a wrong number of mount points %d instead of 0", len(all))
   429  	}
   430  	points.RemoveBySource("/image.simg")
   431  	all = points.GetByTag(RootfsTag)
   432  	if len(all) != 0 {
   433  		t.Errorf("returned a wrong number of mount points %d instead of 0", len(all))
   434  	}
   435  
   436  	proc := points.GetByDest("/proc")
   437  	if len(proc) != 1 {
   438  		t.Fatalf("returned a wrong number of mount points %d instead of 1", len(proc))
   439  	}
   440  	for _, option := range proc[0].Options {
   441  		if option == "context="+mountLabel {
   442  			t.Errorf("context should not be set for proc filesystem")
   443  		}
   444  	}
   445  	points.RemoveByDest("/proc")
   446  
   447  	sys := points.GetByDest("/sys")
   448  	if len(sys) != 1 {
   449  		t.Fatalf("returned a wrong number of mount points %d instead of 1", len(sys))
   450  	}
   451  	for _, option := range sys[0].Options {
   452  		if option == "context="+mountLabel {
   453  			t.Errorf("context should not be set for sysfs filesystem")
   454  		}
   455  	}
   456  	points.RemoveByDest("/sys")
   457  
   458  	all = points.GetByTag(KernelTag)
   459  	if len(all) != 0 {
   460  		t.Errorf("returned a wrong number of mount points %d instead of 0", len(all))
   461  	}
   462  	points.RemoveAll()
   463  
   464  	invalidImport := map[AuthorizedTag][]Point{
   465  		UserbindsTag: {
   466  			{
   467  				Mount: specs.Mount{
   468  					Source:      "",
   469  					Destination: "/mnt",
   470  					Type:        "",
   471  					Options:     []string{"rbind", "nosuid"},
   472  				},
   473  			},
   474  		},
   475  	}
   476  	if err := points.Import(invalidImport); err == nil {
   477  		t.Errorf("import should failed: %s", err)
   478  	}
   479  
   480  	validForceContextImport := map[AuthorizedTag][]Point{
   481  		SessionTag: {
   482  			{
   483  				Mount: specs.Mount{
   484  					Source:      "/",
   485  					Destination: "/tmp",
   486  					Type:        "tmpfs",
   487  					Options:     []string{"nosuid", "nodev", "mode=1777"},
   488  				},
   489  			},
   490  		},
   491  	}
   492  
   493  	if err := points.Import(validForceContextImport); err != nil {
   494  		t.Fatalf("%s", err)
   495  	}
   496  	tmp := points.GetByDest("/tmp")
   497  	if len(tmp) != 1 {
   498  		t.Fatalf("returned a wrong number of mount points %d instead of 1", len(tmp))
   499  	}
   500  	hasContext := false
   501  	context := fmt.Sprintf("context=%q", mountLabel)
   502  	for _, option := range tmp[0].Options {
   503  		if option == context {
   504  			hasContext = true
   505  		}
   506  	}
   507  	if !hasContext {
   508  		t.Errorf("context should be set /tmp mount point")
   509  	}
   510  	points.RemoveAll()
   511  
   512  	validContextImport := map[AuthorizedTag][]Point{
   513  		SessionTag: {
   514  			{
   515  				Mount: specs.Mount{
   516  					Source:      "/",
   517  					Destination: "/tmp",
   518  					Type:        "tmpfs",
   519  					Options:     []string{"nosuid", "nodev", "mode=1777", "context=" + mountLabel},
   520  				},
   521  			},
   522  		},
   523  	}
   524  
   525  	if err := points.Import(validContextImport); err != nil {
   526  		t.Fatalf("%s", err)
   527  	}
   528  	tmp = points.GetByDest("/tmp")
   529  	if len(tmp) != 1 {
   530  		t.Fatalf("returned a wrong number of mount points %d instead of 1", len(tmp))
   531  	}
   532  	numContext := 0
   533  	for _, option := range tmp[0].Options {
   534  		if option == "context="+mountLabel {
   535  			numContext++
   536  		}
   537  	}
   538  	if numContext != 1 {
   539  		t.Errorf("context option is set %d times for /tmp mount point %s", numContext, tmp[0])
   540  	}
   541  	points.RemoveAll()
   542  
   543  	points = &Points{}
   544  
   545  	validSpecs := []specs.Mount{
   546  		{
   547  			Source:      "/",
   548  			Destination: "/mnt",
   549  			Type:        "",
   550  			Options:     []string{"rbind", "nosuid", "rshared"},
   551  		},
   552  		{
   553  			Source:      "",
   554  			Destination: "/opt",
   555  			Type:        "overlay",
   556  			Options:     []string{"nosuid", "nodev", "lowerdir=/", "upperdir=/upper", "workdir=/work"},
   557  		},
   558  		{
   559  			Source:      "",
   560  			Destination: "/tmp",
   561  			Type:        "tmpfs",
   562  			Options:     []string{"nosuid", "nodev", "mode=1777"},
   563  		},
   564  		{
   565  			Source:      "sysfs",
   566  			Destination: "/sys",
   567  			Type:        "sysfs",
   568  			Options:     []string{"nosuid", "nodev"},
   569  		},
   570  		{
   571  			Source:      "",
   572  			Destination: "/dev/pts",
   573  			Type:        "devpts",
   574  			Options:     []string{"nosuid"},
   575  		},
   576  	}
   577  	if err := points.ImportFromSpec(validSpecs); err != nil {
   578  		t.Error(err)
   579  	}
   580  	if len(points.GetByTag(KernelTag)) != 4 {
   581  		t.Errorf("returned a wrong number of mount kernel mount points %d instead of 4", len(points.GetByTag(KernelTag)))
   582  	}
   583  	if len(points.GetByTag(UserbindsTag)) != 3 {
   584  		t.Errorf("returned a wrong number of mount kernel mount points %d instead of 3", len(points.GetByTag(UserbindsTag)))
   585  	}
   586  	points.RemoveAll()
   587  
   588  	invalidSpecs := []specs.Mount{
   589  		{
   590  			Source:      "/image.simg",
   591  			Destination: "/tmp/image",
   592  			Type:        "squashfs",
   593  			Options:     []string{"nosuid", "nodev"},
   594  		},
   595  	}
   596  	if err := points.ImportFromSpec(invalidSpecs); err == nil {
   597  		t.Errorf("should have failed with non authorized filesystem type")
   598  	}
   599  }
   600  
   601  func TestTag(t *testing.T) {
   602  	test.DropPrivilege(t)
   603  	defer test.ResetPrivilege(t)
   604  
   605  	points := &Points{}
   606  
   607  	if err := points.AddBind(AuthorizedTag("unknown"), "/", "/mnt", syscall.MS_NOSUID); err == nil {
   608  		t.Errorf("should have failed with a not recognized tag")
   609  	}
   610  	if err := points.AddFS(SessionTag, "/mnt", "tmpfs", syscall.MS_NOSUID, ""); err != nil {
   611  		t.Errorf("%s", err)
   612  	}
   613  	if err := points.AddFS(SessionTag, "/mnt2", "tmpfs", syscall.MS_NOSUID, ""); err == nil {
   614  		t.Errorf("should have failed, %s allow only a single mount point", SessionTag)
   615  	}
   616  	for _, tag := range GetTagList() {
   617  		points.RemoveByTag(tag)
   618  		if len(points.GetByTag(tag)) != 0 {
   619  			t.Fatalf("removing mount point entries by tag failed")
   620  		}
   621  	}
   622  }