ntp: drop privileges to nobody/nogroup, retain CAP_SYS_TIME
This commit is contained in:
parent
83adedae5d
commit
3ed1e381b5
@ -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
84
cmd/ntp/privdrop.go
Normal 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())
|
||||
}
|
8
cmd/ntp/privdrop_dummy.go
Normal file
8
cmd/ntp/privdrop_dummy.go
Normal 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() {
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user