Skip to content

Commit 1b18907

Browse files
committed
Add LfileLabel and LsetFileLabel
SELinux C library has two functions for dealing with file labels, one which follows symlinks and one that does not. Golang bindings should work the same way. The lack of this function is resulting in containers/buildah#3630 which has to hack around the problem. Signed-off-by: Daniel J Walsh <[email protected]>
1 parent 0cb05ae commit 1b18907

File tree

4 files changed

+99
-5
lines changed

4 files changed

+99
-5
lines changed

go-selinux/selinux.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,30 @@ func ClassIndex(class string) (int, error) {
6161
return classIndex(class)
6262
}
6363

64-
// SetFileLabel sets the SELinux label for this path or returns an error.
64+
// SetFileLabel sets the SELinux label for this path, following symlinks,
65+
// or returns an error.
6566
func SetFileLabel(fpath string, label string) error {
6667
return setFileLabel(fpath, label)
6768
}
6869

69-
// FileLabel returns the SELinux label for this path or returns an error.
70+
// LsetFileLabel sets the SELinux label for this path, not following symlinks,
71+
// or returns an error.
72+
func LsetFileLabel(fpath string, label string) error {
73+
return lSetFileLabel(fpath, label)
74+
}
75+
76+
// FileLabel returns the SELinux label for this path, following symlinks,
77+
// or returns an error.
7078
func FileLabel(fpath string) (string, error) {
7179
return fileLabel(fpath)
7280
}
7381

82+
// LfileLabel returns the SELinux label for this path, not following symlinks,
83+
// or returns an error.
84+
func LfileLabel(fpath string) (string, error) {
85+
return lFileLabel(fpath)
86+
}
87+
7488
// SetFSCreateLabel tells the kernel what label to use for all file system objects
7589
// created by this task.
7690
// Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel

go-selinux/selinux_linux.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,9 @@ func classIndex(class string) (int, error) {
316316
return index, nil
317317
}
318318

319-
// setFileLabel sets the SELinux label for this path or returns an error.
320-
func setFileLabel(fpath string, label string) error {
319+
// lSetFileLabel sets the SELinux label for this path, not following symlinks,
320+
// or returns an error.
321+
func lSetFileLabel(fpath string, label string) error {
321322
if fpath == "" {
322323
return ErrEmptyPath
323324
}
@@ -334,12 +335,50 @@ func setFileLabel(fpath string, label string) error {
334335
return nil
335336
}
336337

337-
// fileLabel returns the SELinux label for this path or returns an error.
338+
// setFileLabel sets the SELinux label for this path, following symlinks,
339+
// or returns an error.
340+
func setFileLabel(fpath string, label string) error {
341+
if fpath == "" {
342+
return ErrEmptyPath
343+
}
344+
for {
345+
err := unix.Setxattr(fpath, xattrNameSelinux, []byte(label), 0)
346+
if err == nil {
347+
break
348+
}
349+
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
350+
return &os.PathError{Op: "setxattr", Path: fpath, Err: err}
351+
}
352+
}
353+
354+
return nil
355+
}
356+
357+
// fileLabel returns the SELinux label for this path, following symlinks,
358+
// or returns an error.
338359
func fileLabel(fpath string) (string, error) {
339360
if fpath == "" {
340361
return "", ErrEmptyPath
341362
}
342363

364+
label, err := getxattr(fpath, xattrNameSelinux)
365+
if err != nil {
366+
return "", &os.PathError{Op: "getxattr", Path: fpath, Err: err}
367+
}
368+
// Trim the NUL byte at the end of the byte buffer, if present.
369+
if len(label) > 0 && label[len(label)-1] == '\x00' {
370+
label = label[:len(label)-1]
371+
}
372+
return string(label), nil
373+
}
374+
375+
// lFileLabel returns the SELinux label for this path, not following symlinks,
376+
// or returns an error.
377+
func lFileLabel(fpath string) (string, error) {
378+
if fpath == "" {
379+
return "", ErrEmptyPath
380+
}
381+
343382
label, err := lgetxattr(fpath, xattrNameSelinux)
344383
if err != nil {
345384
return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err}

go-selinux/selinux_stub.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,18 @@ func setFileLabel(fpath string, label string) error {
1717
return nil
1818
}
1919

20+
func lSetFileLabel(fpath string, label string) error {
21+
return nil
22+
}
23+
2024
func fileLabel(fpath string) (string, error) {
2125
return "", nil
2226
}
2327

28+
func lFileLabel(fpath string) (string, error) {
29+
return "", nil
30+
}
31+
2432
func setFSCreateLabel(label string) error {
2533
return nil
2634
}

go-selinux/xattrs_linux.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,36 @@ func doLgetxattr(path, attr string, dest []byte) (int, error) {
3636
}
3737
}
3838
}
39+
40+
// getxattr returns a []byte slice containing the value of
41+
// an extended attribute attr set for path.
42+
func getxattr(path, attr string) ([]byte, error) {
43+
// Start with a 128 length byte array
44+
dest := make([]byte, 128)
45+
sz, errno := dogetxattr(path, attr, dest)
46+
for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare
47+
// Buffer too small, use zero-sized buffer to get the actual size
48+
sz, errno = dogetxattr(path, attr, []byte{})
49+
if errno != nil {
50+
return nil, errno
51+
}
52+
53+
dest = make([]byte, sz)
54+
sz, errno = dogetxattr(path, attr, dest)
55+
}
56+
if errno != nil {
57+
return nil, errno
58+
}
59+
60+
return dest[:sz], nil
61+
}
62+
63+
// dogetxattr is a wrapper that retries on EINTR
64+
func dogetxattr(path, attr string, dest []byte) (int, error) {
65+
for {
66+
sz, err := unix.Getxattr(path, attr, dest)
67+
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
68+
return sz, err
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)