Go 1.18 and up now provides a strings.Cut() which is better suited for
splitting key/value pairs (and similar constructs), and performs better:
```go
func BenchmarkSplit(b *testing.B) {
        b.ReportAllocs()
        data := []string{"12hello=world", "12hello=", "12=hello", "12hello"}
        for i := 0; i < b.N; i++ {
                for _, s := range data {
                        _ = strings.SplitN(s, "=", 2)[0]
                }
        }
}
func BenchmarkCut(b *testing.B) {
        b.ReportAllocs()
        data := []string{"12hello=world", "12hello=", "12=hello", "12hello"}
        for i := 0; i < b.N; i++ {
                for _, s := range data {
                        _, _, _ = strings.Cut(s, "=")
                }
        }
}
```
    BenchmarkSplit
    BenchmarkSplit-10            8244206               128.0 ns/op           128 B/op          4 allocs/op
    BenchmarkCut
    BenchmarkCut-10             54411998                21.80 ns/op            0 B/op          0 allocs/op
While looking at occurrences of `strings.Split()`, I also updated some for alternatives,
or added some constraints; for cases where an specific number of items is expected, I used `strings.SplitN()`
with a suitable limit. This prevents (theoretical) unlimited splits.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
		
	
		
			
				
	
	
		
			188 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
   Copyright The containerd Authors.
 | 
						|
 | 
						|
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
   you may not use this file except in compliance with the License.
 | 
						|
   You may obtain a copy of the License at
 | 
						|
 | 
						|
       http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
   Unless required by applicable law or agreed to in writing, software
 | 
						|
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
   See the License for the specific language governing permissions and
 | 
						|
   limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
// Package cap provides Linux capability utility
 | 
						|
package cap
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// FromNumber returns a cap string like "CAP_SYS_ADMIN"
 | 
						|
// that corresponds to the given number like 21.
 | 
						|
//
 | 
						|
// FromNumber returns an empty string for unknown cap number.
 | 
						|
func FromNumber(num int) string {
 | 
						|
	if num < 0 || num > len(capsLatest)-1 {
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
	return capsLatest[num]
 | 
						|
}
 | 
						|
 | 
						|
// FromBitmap parses an uint64 bitmap into string slice like
 | 
						|
// []{"CAP_SYS_ADMIN", ...}.
 | 
						|
//
 | 
						|
// Unknown cap numbers are returned as []int.
 | 
						|
func FromBitmap(v uint64) ([]string, []int) {
 | 
						|
	var (
 | 
						|
		res     []string
 | 
						|
		unknown []int
 | 
						|
	)
 | 
						|
	for i := 0; i <= 63; i++ {
 | 
						|
		if b := (v >> i) & 0x1; b == 0x1 {
 | 
						|
			if s := FromNumber(i); s != "" {
 | 
						|
				res = append(res, s)
 | 
						|
			} else {
 | 
						|
				unknown = append(unknown, i)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return res, unknown
 | 
						|
}
 | 
						|
 | 
						|
// Type is the type of capability
 | 
						|
type Type int
 | 
						|
 | 
						|
const (
 | 
						|
	// Effective is CapEff
 | 
						|
	Effective Type = 1 << iota
 | 
						|
	// Permitted is CapPrm
 | 
						|
	Permitted
 | 
						|
	// Inheritable is CapInh
 | 
						|
	Inheritable
 | 
						|
	// Bounding is CapBnd
 | 
						|
	Bounding
 | 
						|
	// Ambient is CapAmb
 | 
						|
	Ambient
 | 
						|
)
 | 
						|
 | 
						|
// ParseProcPIDStatus returns uint64 bitmap value from /proc/<PID>/status file
 | 
						|
func ParseProcPIDStatus(r io.Reader) (map[Type]uint64, error) {
 | 
						|
	res := make(map[Type]uint64)
 | 
						|
	scanner := bufio.NewScanner(r)
 | 
						|
	for scanner.Scan() {
 | 
						|
		line := scanner.Text()
 | 
						|
		k, v, ok := strings.Cut(line, ":")
 | 
						|
		if !ok {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		k = strings.TrimSpace(k)
 | 
						|
		switch k {
 | 
						|
		case "CapInh", "CapPrm", "CapEff", "CapBnd", "CapAmb":
 | 
						|
			ui64, err := strconv.ParseUint(strings.TrimSpace(v), 16, 64)
 | 
						|
			if err != nil {
 | 
						|
				return nil, fmt.Errorf("failed to parse line %q", line)
 | 
						|
			}
 | 
						|
			switch k {
 | 
						|
			case "CapInh":
 | 
						|
				res[Inheritable] = ui64
 | 
						|
			case "CapPrm":
 | 
						|
				res[Permitted] = ui64
 | 
						|
			case "CapEff":
 | 
						|
				res[Effective] = ui64
 | 
						|
			case "CapBnd":
 | 
						|
				res[Bounding] = ui64
 | 
						|
			case "CapAmb":
 | 
						|
				res[Ambient] = ui64
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if err := scanner.Err(); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return res, nil
 | 
						|
}
 | 
						|
 | 
						|
// Current returns the list of the effective and the known caps of
 | 
						|
// the current process.
 | 
						|
//
 | 
						|
// The result is like []string{"CAP_SYS_ADMIN", ...}.
 | 
						|
func Current() ([]string, error) {
 | 
						|
	f, err := os.Open("/proc/self/status")
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer f.Close()
 | 
						|
	caps, err := ParseProcPIDStatus(f)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	capEff := caps[Effective]
 | 
						|
	names, _ := FromBitmap(capEff)
 | 
						|
	return names, nil
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	// caps35 is the caps of kernel 3.5 (37 entries)
 | 
						|
	caps35 = []string{
 | 
						|
		"CAP_CHOWN",            // 2.2
 | 
						|
		"CAP_DAC_OVERRIDE",     // 2.2
 | 
						|
		"CAP_DAC_READ_SEARCH",  // 2.2
 | 
						|
		"CAP_FOWNER",           // 2.2
 | 
						|
		"CAP_FSETID",           // 2.2
 | 
						|
		"CAP_KILL",             // 2.2
 | 
						|
		"CAP_SETGID",           // 2.2
 | 
						|
		"CAP_SETUID",           // 2.2
 | 
						|
		"CAP_SETPCAP",          // 2.2
 | 
						|
		"CAP_LINUX_IMMUTABLE",  // 2.2
 | 
						|
		"CAP_NET_BIND_SERVICE", // 2.2
 | 
						|
		"CAP_NET_BROADCAST",    // 2.2
 | 
						|
		"CAP_NET_ADMIN",        // 2.2
 | 
						|
		"CAP_NET_RAW",          // 2.2
 | 
						|
		"CAP_IPC_LOCK",         // 2.2
 | 
						|
		"CAP_IPC_OWNER",        // 2.2
 | 
						|
		"CAP_SYS_MODULE",       // 2.2
 | 
						|
		"CAP_SYS_RAWIO",        // 2.2
 | 
						|
		"CAP_SYS_CHROOT",       // 2.2
 | 
						|
		"CAP_SYS_PTRACE",       // 2.2
 | 
						|
		"CAP_SYS_PACCT",        // 2.2
 | 
						|
		"CAP_SYS_ADMIN",        // 2.2
 | 
						|
		"CAP_SYS_BOOT",         // 2.2
 | 
						|
		"CAP_SYS_NICE",         // 2.2
 | 
						|
		"CAP_SYS_RESOURCE",     // 2.2
 | 
						|
		"CAP_SYS_TIME",         // 2.2
 | 
						|
		"CAP_SYS_TTY_CONFIG",   // 2.2
 | 
						|
		"CAP_MKNOD",            // 2.4
 | 
						|
		"CAP_LEASE",            // 2.4
 | 
						|
		"CAP_AUDIT_WRITE",      // 2.6.11
 | 
						|
		"CAP_AUDIT_CONTROL",    // 2.6.11
 | 
						|
		"CAP_SETFCAP",          // 2.6.24
 | 
						|
		"CAP_MAC_OVERRIDE",     // 2.6.25
 | 
						|
		"CAP_MAC_ADMIN",        // 2.6.25
 | 
						|
		"CAP_SYSLOG",           // 2.6.37
 | 
						|
		"CAP_WAKE_ALARM",       // 3.0
 | 
						|
		"CAP_BLOCK_SUSPEND",    // 3.5
 | 
						|
	}
 | 
						|
	// caps316 is the caps of kernel 3.16 (38 entries)
 | 
						|
	caps316 = append(caps35, "CAP_AUDIT_READ")
 | 
						|
	// caps58 is the caps of kernel 5.8 (40 entries)
 | 
						|
	caps58 = append(caps316, []string{"CAP_PERFMON", "CAP_BPF"}...)
 | 
						|
	// caps59 is the caps of kernel 5.9 (41 entries)
 | 
						|
	caps59     = append(caps58, "CAP_CHECKPOINT_RESTORE")
 | 
						|
	capsLatest = caps59
 | 
						|
)
 | 
						|
 | 
						|
// Known returns the known cap strings of the latest kernel.
 | 
						|
// The current latest kernel is 5.9.
 | 
						|
func Known() []string {
 | 
						|
	return capsLatest
 | 
						|
}
 |