Drop privileges much more thoroughly, thanks nervuri! (see issue #16)
This commit is contained in:
parent
182e58ffe3
commit
7fad754ff2
4 changed files with 90 additions and 26 deletions
16
main.go
16
main.go
|
@ -7,7 +7,6 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
@ -44,18 +43,7 @@ func main() {
|
|||
|
||||
// If we are running as root, find the UID of the "nobody" user, before a
|
||||
// chroot() possibly stops seeing /etc/passwd
|
||||
uid := os.Getuid()
|
||||
nobody_uid := -1
|
||||
if uid == 0 {
|
||||
nobody_user, err := user.Lookup(config.UnprivUsername)
|
||||
if err != nil {
|
||||
log.Fatal("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + err.Error())
|
||||
}
|
||||
nobody_uid, err = strconv.Atoi(nobody_user.Uid)
|
||||
if err != nil {
|
||||
log.Fatal("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + err.Error())
|
||||
}
|
||||
}
|
||||
privInfo := getUserInfo(config)
|
||||
|
||||
// Chroot, if asked
|
||||
if config.ChrootDir != "" {
|
||||
|
@ -120,7 +108,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Apply security restrictions
|
||||
enableSecurityRestrictions(config, nobody_uid, errorLog)
|
||||
enableSecurityRestrictions(config, privInfo, errorLog)
|
||||
|
||||
// Create TLS listener
|
||||
listener, err := tls.Listen("tcp", ":"+strconv.Itoa(config.Port), tlscfg)
|
||||
|
|
|
@ -5,21 +5,97 @@ package main
|
|||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func DropPrivs(config Config, nobody_uid int, errorLog *log.Logger) {
|
||||
type userInfo struct {
|
||||
uid int
|
||||
euid int
|
||||
gid int
|
||||
egid int
|
||||
supp_groups []int
|
||||
is_setuid bool
|
||||
is_setgid bool
|
||||
root_user bool
|
||||
root_prim_group bool
|
||||
root_supp_group bool
|
||||
need_drop bool
|
||||
unpriv_uid int
|
||||
unpriv_gid int
|
||||
}
|
||||
|
||||
// Get our real and effective UIDs
|
||||
uid := os.Getuid()
|
||||
euid := os.Geteuid()
|
||||
func getUserInfo(config Config) userInfo {
|
||||
var ui userInfo
|
||||
ui.uid = os.Getuid()
|
||||
ui.euid = os.Geteuid()
|
||||
ui.gid = os.Getgid()
|
||||
ui.egid = os.Getegid()
|
||||
supp_groups, err := os.Getgroups()
|
||||
if err != nil {
|
||||
log.Fatal("Could not get supplementary groups: ", err.Error())
|
||||
}
|
||||
ui.supp_groups = supp_groups
|
||||
ui.unpriv_uid = -1
|
||||
ui.unpriv_gid = -1
|
||||
|
||||
// Are we root or are we running as a setuid binary?
|
||||
if uid == 0 || uid != euid {
|
||||
err := syscall.Setuid(nobody_uid)
|
||||
ui.is_setuid = ui.uid != ui.euid
|
||||
ui.is_setgid = ui.gid != ui.egid
|
||||
ui.root_user = ui.uid == 0 || ui.euid == 0
|
||||
ui.root_prim_group = ui.gid == 0 || ui.egid == 0
|
||||
for _, gid := range ui.supp_groups {
|
||||
if gid == 0 {
|
||||
ui.root_supp_group = true
|
||||
break
|
||||
}
|
||||
}
|
||||
ui.need_drop = ui.is_setuid || ui.is_setgid || ui.root_user || ui.root_prim_group || ui.root_supp_group
|
||||
|
||||
if ui.need_drop {
|
||||
nobody_user, err := user.Lookup(config.UnprivUsername)
|
||||
if err != nil {
|
||||
errorLog.Println("Could not setuid to " + strconv.Itoa(uid) + ": " + err.Error())
|
||||
log.Fatal("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + err.Error())
|
||||
}
|
||||
ui.unpriv_uid, err = strconv.Atoi(nobody_user.Uid)
|
||||
ui.unpriv_gid, err = strconv.Atoi(nobody_user.Gid)
|
||||
if err != nil {
|
||||
log.Fatal("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return ui
|
||||
}
|
||||
func DropPrivs(ui userInfo, errorLog *log.Logger) {
|
||||
|
||||
// If we're already unprivileged, all good
|
||||
if !ui.need_drop {
|
||||
return
|
||||
}
|
||||
|
||||
// Drop supplementary groups
|
||||
if ui.root_supp_group {
|
||||
err := syscall.Setgroups([]int{})
|
||||
if err != nil {
|
||||
errorLog.Println("Could not unset supplementary groups: " + err.Error())
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Setguid()
|
||||
if ui.root_prim_group {
|
||||
err := syscall.Setgid(ui.unpriv_gid)
|
||||
if err != nil {
|
||||
errorLog.Println("Could not setgid to " + strconv.Itoa(ui.unpriv_gid) + ": " + err.Error())
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Setuid()
|
||||
if ui.root_user {
|
||||
err := syscall.Setuid(ui.unpriv_uid)
|
||||
if err != nil {
|
||||
errorLog.Println("Could not setuid to " + strconv.Itoa(ui.unpriv_uid) + ": " + err.Error())
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ import (
|
|||
// operations available to the molly brown executable. Please note that (S)CGI
|
||||
// processes that molly brown spawns or communicates with are unrestricted
|
||||
// and should pledge their own restrictions and unveil their own files.
|
||||
func enableSecurityRestrictions(config Config, nobody_uid int, errorLog *log.Logger) {
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) {
|
||||
|
||||
// Setuid to an unprivileged user
|
||||
DropPrivs(config, nobody_uid, errorLog)
|
||||
DropPrivs(ui, errorLog)
|
||||
|
||||
// Unveil the configured document base as readable.
|
||||
log.Println("Unveiling \"" + config.DocBase + "\" as readable.")
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
"log"
|
||||
)
|
||||
|
||||
func enableSecurityRestrictions(config Config, nobody_uid int, errorLog *log.Logger) {
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) {
|
||||
|
||||
// Setuid to an unprivileged user
|
||||
DropPrivs(config, nobody_uid, errorLog)
|
||||
DropPrivs(ui, errorLog)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue