Skip to content

Commit f8dbdbc

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 3e29a7d commit f8dbdbc

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
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: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,31 @@ func classIndex(class string) (int, error) {
316316
return index, nil
317317
}
318318

319+
// lSetFileLabel sets the SELinux label for this path or returns an error.
320+
func lSetFileLabel(fpath string, label string) error {
321+
if fpath == "" {
322+
return ErrEmptyPath
323+
}
324+
for {
325+
err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
326+
if err == nil {
327+
break
328+
}
329+
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
330+
return &os.PathError{Op: "lsetxattr", Path: fpath, Err: err}
331+
}
332+
}
333+
334+
return nil
335+
}
336+
319337
// setFileLabel sets the SELinux label for this path or returns an error.
320338
func setFileLabel(fpath string, label string) error {
321339
if fpath == "" {
322340
return ErrEmptyPath
323341
}
324342
for {
325-
err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
343+
err := unix.Setxattr(fpath, xattrNameSelinux, []byte(label), 0)
326344
if err == nil {
327345
break
328346
}
@@ -340,6 +358,23 @@ func fileLabel(fpath string) (string, error) {
340358
return "", ErrEmptyPath
341359
}
342360

361+
label, err := getxattr(fpath, xattrNameSelinux)
362+
if err != nil {
363+
return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err}
364+
}
365+
// Trim the NUL byte at the end of the byte buffer, if present.
366+
if len(label) > 0 && label[len(label)-1] == '\x00' {
367+
label = label[:len(label)-1]
368+
}
369+
return string(label), nil
370+
}
371+
372+
// lFileLabel returns the SELinux label for this path or returns an error.
373+
func lFileLabel(fpath string) (string, error) {
374+
if fpath == "" {
375+
return "", ErrEmptyPath
376+
}
377+
343378
label, err := lgetxattr(fpath, xattrNameSelinux)
344379
if err != nil {
345380
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 = doLgetxattr(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.Lgetxattr(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)