ntp: drop privileges to nobody/nogroup, retain CAP_SYS_TIME

This commit is contained in:
Michael Stapelberg 2017-09-03 22:19:28 +02:00
parent 83adedae5d
commit 3ed1e381b5
3 changed files with 94 additions and 0 deletions

View File

@ -23,6 +23,8 @@ func set() error {
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
mustDropPrivileges()
for {
if err := set(); err != nil {
log.Fatalf("setting time failed: %v", err)

84
cmd/ntp/privdrop.go Normal file
View File

@ -0,0 +1,84 @@
// +build go1.9
package main
import (
"fmt"
"log"
"os"
"os/exec"
"syscall"
"unsafe"
)
type capHeader struct {
version uint32
pid int
}
type capData struct {
effective uint32
permitted uint32
inheritable uint32
}
type caps struct {
hdr capHeader
data [2]capData
}
func getCaps() (caps, error) {
var c caps
// Get capability version
if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(nil)), 0); errno != 0 {
return c, fmt.Errorf("SYS_CAPGET: %v", errno)
}
// Get current capabilities
if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0); errno != 0 {
return c, fmt.Errorf("SYS_CAPGET: %v", errno)
}
return c, nil
}
// mustDropPrivileges executes the program in a child process, dropping root
// privileges, but retaining the CAP_SYS_TIME capability to change the system
// clock.
func mustDropPrivileges() {
if os.Getenv("NTP_PRIVILEGES_DROPPED") == "1" {
return
}
// From include/uapi/linux/capability.h:
// Allow setting the real-time clock
const CAP_SYS_TIME = 25
caps, err := getCaps()
if err != nil {
log.Fatal(err)
}
// Add CAP_SYS_TIME to the permitted and inheritable capability mask,
// otherwise we will not be able to add it to the ambient capability mask.
caps.data[0].permitted |= 1 << uint(CAP_SYS_TIME)
caps.data[0].inheritable |= 1 << uint(CAP_SYS_TIME)
if _, _, errno := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); errno != 0 {
log.Fatalf("SYS_CAPSET: %v", errno)
}
cmd := exec.Command(os.Args[0])
cmd.Env = append(os.Environ(), "NTP_PRIVILEGES_DROPPED=1")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: 65534,
Gid: 65534,
},
AmbientCaps: []uintptr{CAP_SYS_TIME},
}
log.Fatal(cmd.Run())
}

View File

@ -0,0 +1,8 @@
// +build !go1.9
package main
// mustDropPrivileges (on Go < 1.9) does nothing, as the AmbientCaps field in
// syscall.SysProcAttr was only introduced in Go 1.9.
func mustDropPrivileges() {
}