Compare commits
No commits in common. "afa7a0800da2bb44fd9daaea1180c046ea111db8" and "409ed172c854e548352ed1480eedfa6d75572e43" have entirely different histories.
afa7a0800d
...
409ed172c8
@ -15,7 +15,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
hsuConfFile = "/etc/hsurc"
|
hsuConfFile = "/etc/hsurc"
|
||||||
envShim = "HAKUREI_SHIM"
|
envShim = "HAKUREI_SHIM"
|
||||||
envIdentity = "HAKUREI_IDENTITY"
|
envAID = "HAKUREI_APP_ID"
|
||||||
envGroups = "HAKUREI_GROUPS"
|
envGroups = "HAKUREI_GROUPS"
|
||||||
|
|
||||||
PR_SET_NO_NEW_PRIVS = 0x26
|
PR_SET_NO_NEW_PRIVS = 0x26
|
||||||
@ -48,8 +48,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// uid = 1000000 +
|
// uid = 1000000 +
|
||||||
// id * 10000 +
|
// fid * 10000 +
|
||||||
// identity
|
// aid
|
||||||
uid := 1000000
|
uid := 1000000
|
||||||
|
|
||||||
// refuse to run if hsurc is not protected correctly
|
// refuse to run if hsurc is not protected correctly
|
||||||
@ -62,25 +62,29 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// authenticate before accepting user input
|
// authenticate before accepting user input
|
||||||
var id int
|
|
||||||
if f, err := os.Open(hsuConfFile); err != nil {
|
if f, err := os.Open(hsuConfFile); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
} else if v, ok := mustParseConfig(f, puid); !ok {
|
} else if fid, ok := mustParseConfig(f, puid); !ok {
|
||||||
log.Fatalf("uid %d is not in the hsurc file", puid)
|
log.Fatalf("uid %d is not in the hsurc file", puid)
|
||||||
} else {
|
} else {
|
||||||
id = v
|
uid += fid * 10000
|
||||||
if err = f.Close(); err != nil {
|
}
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
uid += id * 10000
|
// allowed aid range 0 to 9999
|
||||||
|
if as, ok := os.LookupEnv(envAID); !ok {
|
||||||
|
log.Fatal("HAKUREI_APP_ID not set")
|
||||||
|
} else if aid, err := parseUint32Fast(as); err != nil || aid < 0 || aid > 9999 {
|
||||||
|
log.Fatal("invalid aid")
|
||||||
|
} else {
|
||||||
|
uid += aid
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass through setup fd to shim
|
// pass through setup fd to shim
|
||||||
var shimSetupFd string
|
var shimSetupFd string
|
||||||
if s, ok := os.LookupEnv(envShim); !ok {
|
if s, ok := os.LookupEnv(envShim); !ok {
|
||||||
// hakurei requests hsurc user id
|
// hakurei requests target uid
|
||||||
fmt.Print(id)
|
// print resolved uid and exit
|
||||||
|
fmt.Print(uid)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
|
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
|
||||||
log.Fatal("HAKUREI_SHIM holds an invalid value")
|
log.Fatal("HAKUREI_SHIM holds an invalid value")
|
||||||
@ -88,15 +92,6 @@ func main() {
|
|||||||
shimSetupFd = s
|
shimSetupFd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// allowed identity range 0 to 9999
|
|
||||||
if as, ok := os.LookupEnv(envIdentity); !ok {
|
|
||||||
log.Fatal("HAKUREI_IDENTITY not set")
|
|
||||||
} else if identity, err := parseUint32Fast(as); err != nil || identity < 0 || identity > 9999 {
|
|
||||||
log.Fatal("invalid identity")
|
|
||||||
} else {
|
|
||||||
uid += identity
|
|
||||||
}
|
|
||||||
|
|
||||||
// supplementary groups
|
// supplementary groups
|
||||||
var suppGroups, suppCurrent []int
|
var suppGroups, suppCurrent []int
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ func (seal *outcome) main() {
|
|||||||
// passed through to shim by hsu
|
// passed through to shim by hsu
|
||||||
shimEnv + "=" + strconv.Itoa(fd),
|
shimEnv + "=" + strconv.Itoa(fd),
|
||||||
// interpreted by hsu
|
// interpreted by hsu
|
||||||
"HAKUREI_IDENTITY=" + seal.user.identity.String(),
|
"HAKUREI_APP_ID=" + seal.user.identity.String(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,48 +17,69 @@ import (
|
|||||||
|
|
||||||
// Hsu caches responses from cmd/hsu.
|
// Hsu caches responses from cmd/hsu.
|
||||||
type Hsu struct {
|
type Hsu struct {
|
||||||
idOnce sync.Once
|
uidOnce sync.Once
|
||||||
idErr error
|
uidCopy map[int]struct {
|
||||||
id int
|
uid int
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
uidMu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrHsuAccess = errors.New("current user is not in the hsurc file")
|
var ErrHsuAccess = errors.New("current user is not in the hsurc file")
|
||||||
|
|
||||||
func (h *Hsu) Uid(identity int) (int, error) {
|
func (h *Hsu) Uid(identity int) (int, error) {
|
||||||
h.idOnce.Do(func() {
|
h.uidOnce.Do(func() {
|
||||||
h.id = -1
|
h.uidCopy = make(map[int]struct {
|
||||||
hsuPath := internal.MustHsuPath()
|
uid int
|
||||||
|
err error
|
||||||
cmd := exec.Command(hsuPath)
|
})
|
||||||
cmd.Path = hsuPath
|
|
||||||
cmd.Stderr = os.Stderr // pass through fatal messages
|
|
||||||
cmd.Env = make([]string, 0)
|
|
||||||
cmd.Dir = container.FHSRoot
|
|
||||||
var (
|
|
||||||
p []byte
|
|
||||||
exitError *exec.ExitError
|
|
||||||
)
|
|
||||||
|
|
||||||
const step = "obtain uid from hsu"
|
|
||||||
if p, h.idErr = cmd.Output(); h.idErr == nil {
|
|
||||||
h.id, h.idErr = strconv.Atoi(string(p))
|
|
||||||
if h.idErr != nil {
|
|
||||||
h.idErr = &hst.AppError{Step: step, Err: h.idErr, Msg: "invalid uid string from hsu"}
|
|
||||||
}
|
|
||||||
} else if errors.As(h.idErr, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
|
|
||||||
// hsu prints an error message in this case
|
|
||||||
h.idErr = &hst.AppError{Step: step, Err: ErrHsuAccess}
|
|
||||||
} else if os.IsNotExist(h.idErr) {
|
|
||||||
h.idErr = &hst.AppError{Step: step, Err: os.ErrNotExist,
|
|
||||||
Msg: fmt.Sprintf("the setuid helper is missing: %s", hsuPath)}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
uid := -1
|
{
|
||||||
if h.id >= 0 {
|
h.uidMu.RLock()
|
||||||
uid = 1000000 + h.id*10000 + identity
|
u, ok := h.uidCopy[identity]
|
||||||
|
h.uidMu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return u.uid, u.err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return uid, h.idErr
|
|
||||||
|
h.uidMu.Lock()
|
||||||
|
defer h.uidMu.Unlock()
|
||||||
|
|
||||||
|
u := struct {
|
||||||
|
uid int
|
||||||
|
err error
|
||||||
|
}{}
|
||||||
|
defer func() { h.uidCopy[identity] = u }()
|
||||||
|
|
||||||
|
u.uid = -1
|
||||||
|
hsuPath := internal.MustHsuPath()
|
||||||
|
|
||||||
|
cmd := exec.Command(hsuPath)
|
||||||
|
cmd.Path = hsuPath
|
||||||
|
cmd.Stderr = os.Stderr // pass through fatal messages
|
||||||
|
cmd.Env = []string{"HAKUREI_APP_ID=" + strconv.Itoa(identity)}
|
||||||
|
cmd.Dir = container.FHSRoot
|
||||||
|
var (
|
||||||
|
p []byte
|
||||||
|
exitError *exec.ExitError
|
||||||
|
)
|
||||||
|
|
||||||
|
const step = "obtain uid from hsu"
|
||||||
|
if p, u.err = cmd.Output(); u.err == nil {
|
||||||
|
u.uid, u.err = strconv.Atoi(string(p))
|
||||||
|
if u.err != nil {
|
||||||
|
u.err = &hst.AppError{Step: step, Err: u.err, Msg: "invalid uid string from hsu"}
|
||||||
|
}
|
||||||
|
} else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
|
||||||
|
// hsu prints an error message in this case
|
||||||
|
u.err = &hst.AppError{Step: step, Err: ErrHsuAccess}
|
||||||
|
} else if os.IsNotExist(u.err) {
|
||||||
|
u.err = &hst.AppError{Step: step, Err: os.ErrNotExist,
|
||||||
|
Msg: fmt.Sprintf("the setuid helper is missing: %s", hsuPath)}
|
||||||
|
}
|
||||||
|
return u.uid, u.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustUid calls [State.Uid] and terminates on error.
|
// MustUid calls [State.Uid] and terminates on error.
|
||||||
|
@ -26,7 +26,7 @@ def swaymsg(command: str = "", succeed=True, type="command"):
|
|||||||
|
|
||||||
|
|
||||||
def check_filter(check_offset, name, pname):
|
def check_filter(check_offset, name, pname):
|
||||||
pid = int(machine.wait_until_succeeds(f"pgrep -U {1000000+check_offset} -x {pname}", timeout=60))
|
pid = int(machine.wait_until_succeeds(f"pgrep -U {1000000+check_offset} -x {pname}", timeout=15))
|
||||||
hash = machine.succeed(f"sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 WAYLAND_DISPLAY=wayland-1 check-sandbox-{name} hash")
|
hash = machine.succeed(f"sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 WAYLAND_DISPLAY=wayland-1 check-sandbox-{name} hash")
|
||||||
print(machine.succeed(f"hakurei-test -s {hash} filter {pid}"))
|
print(machine.succeed(f"hakurei-test -s {hash} filter {pid}"))
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ check_offset = 0
|
|||||||
def check_sandbox(name):
|
def check_sandbox(name):
|
||||||
global check_offset
|
global check_offset
|
||||||
swaymsg(f"exec script /dev/null -E always -qec check-sandbox-{name}")
|
swaymsg(f"exec script /dev/null -E always -qec check-sandbox-{name}")
|
||||||
machine.wait_for_file(f"/var/tmp/.hakurei-check-ok.{check_offset}", timeout=60)
|
machine.wait_for_file(f"/var/tmp/.hakurei-check-ok.{check_offset}", timeout=15)
|
||||||
check_filter(check_offset, name, "hakurei-test")
|
check_filter(check_offset, name, "hakurei-test")
|
||||||
check_offset += 1
|
check_offset += 1
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user