internal/app: less strict username regex
All checks were successful
Test / Create distribution (push) Successful in 32s
Test / Sandbox (push) Successful in 1m50s
Test / Hpkg (push) Successful in 3m34s
Test / Sandbox (race detector) (push) Successful in 4m8s
Test / Hakurei (race detector) (push) Successful in 2m46s
Test / Hakurei (push) Successful in 2m15s
Test / Flake checks (push) Successful in 1m29s

Use the default value of NAME_REGEX from adduser. Should not hurt compatibility while being less strict.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-08-28 00:22:55 +09:00
parent 0f41d96671
commit 1be8de6f5c
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
3 changed files with 22 additions and 15 deletions

View File

@ -44,7 +44,7 @@ func (seal *outcome) Run(rs *RunState) error {
defer func() { defer func() {
var revertErr error var revertErr error
storeErr := new(StateStoreError) storeErr := new(StateStoreError)
storeErr.Inner, storeErr.DoErr = store.Do(seal.user.aid.unwrap(), func(c state.Cursor) { storeErr.Inner, storeErr.DoErr = store.Do(seal.user.identity.unwrap(), func(c state.Cursor) {
revertErr = func() error { revertErr = func() error {
storeErr.InnerErr = deferredStoreFunc(c) storeErr.InnerErr = deferredStoreFunc(c)
@ -102,7 +102,7 @@ func (seal *outcome) Run(rs *RunState) error {
// 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_APP_ID=" + seal.user.aid.String(), "HAKUREI_APP_ID=" + seal.user.identity.String(),
} }
} }
@ -155,7 +155,7 @@ func (seal *outcome) Run(rs *RunState) error {
PID: cmd.Process.Pid, PID: cmd.Process.Pid,
Time: *rs.Time, Time: *rs.Time,
} }
earlyStoreErr.Inner, earlyStoreErr.DoErr = store.Do(seal.user.aid.unwrap(), func(c state.Cursor) { earlyStoreErr.Inner, earlyStoreErr.DoErr = store.Do(seal.user.identity.unwrap(), func(c state.Cursor) {
earlyStoreErr.InnerErr = c.Save(&sd, seal.ct) earlyStoreErr.InnerErr = c.Save(&sd, seal.ct)
}) })
} }

View File

@ -10,7 +10,6 @@ import (
"io/fs" "io/fs"
"os" "os"
"path" "path"
"regexp"
"slices" "slices"
"strconv" "strconv"
"strings" "strings"
@ -59,8 +58,6 @@ var (
ErrPulseMode = errors.New("unexpected pulse socket mode") ErrPulseMode = errors.New("unexpected pulse socket mode")
) )
var posixUsername = regexp.MustCompilePOSIX("^[a-z_]([A-Za-z0-9_-]{0,31}|[A-Za-z0-9_-]{0,30}\\$)$")
// outcome stores copies of various parts of [hst.Config] // outcome stores copies of various parts of [hst.Config]
type outcome struct { type outcome struct {
// copied from initialising [app] // copied from initialising [app]
@ -135,8 +132,7 @@ func (share *shareHost) runtime() *container.Absolute {
// hsuUser stores post-hsu credentials and metadata // hsuUser stores post-hsu credentials and metadata
type hsuUser struct { type hsuUser struct {
// identity identity *stringPair[int]
aid *stringPair[int]
// target uid resolved by hid:aid // target uid resolved by hid:aid
uid *stringPair[int] uid *stringPair[int]
@ -172,25 +168,24 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
seal.ct = ct seal.ct = ct
} }
// allowed aid range 0 to 9999, this is checked again in hsu // allowed identity range 0 to 9999, this is checked again in hsu
if config.Identity < 0 || config.Identity > 9999 { if config.Identity < 0 || config.Identity > 9999 {
return hlog.WrapErr(ErrIdent, return hlog.WrapErr(ErrIdent,
fmt.Sprintf("identity %d out of range", config.Identity)) fmt.Sprintf("identity %d out of range", config.Identity))
} }
seal.user = hsuUser{ seal.user = hsuUser{
aid: newInt(config.Identity), identity: newInt(config.Identity),
home: config.Home, home: config.Home,
username: config.Username, username: config.Username,
} }
if seal.user.username == "" { if seal.user.username == "" {
seal.user.username = "chronos" seal.user.username = "chronos"
} else if !posixUsername.MatchString(seal.user.username) || } else if !isValidUsername(seal.user.username) {
len(seal.user.username) >= sysconf(_SC_LOGIN_NAME_MAX) {
return hlog.WrapErr(ErrName, return hlog.WrapErr(ErrName,
fmt.Sprintf("invalid user name %q", seal.user.username)) fmt.Sprintf("invalid user name %q", seal.user.username))
} }
if u, err := sys.Uid(seal.user.aid.unwrap()); err != nil { if u, err := sys.Uid(seal.user.identity.unwrap()); err != nil {
return err return err
} else { } else {
seal.user.uid = newInt(u) seal.user.uid = newInt(u)
@ -318,7 +313,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
runtimeDir := share.sc.SharePath.Append("runtime") runtimeDir := share.sc.SharePath.Append("runtime")
seal.sys.Ensure(runtimeDir.String(), 0700) seal.sys.Ensure(runtimeDir.String(), 0700)
seal.sys.UpdatePermType(system.User, runtimeDir.String(), acl.Execute) seal.sys.UpdatePermType(system.User, runtimeDir.String(), acl.Execute)
runtimeDirInst := runtimeDir.Append(seal.user.aid.String()) runtimeDirInst := runtimeDir.Append(seal.user.identity.String())
seal.sys.Ensure(runtimeDirInst.String(), 0700) seal.sys.Ensure(runtimeDirInst.String(), 0700)
seal.sys.UpdatePermType(system.User, runtimeDirInst.String(), acl.Read, acl.Write, acl.Execute) seal.sys.UpdatePermType(system.User, runtimeDirInst.String(), acl.Read, acl.Write, acl.Execute)
seal.container.Tmpfs(container.AbsFHSRunUser, 1<<12, 0755) seal.container.Tmpfs(container.AbsFHSRunUser, 1<<12, 0755)
@ -329,7 +324,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
tmpdir := share.sc.SharePath.Append("tmpdir") tmpdir := share.sc.SharePath.Append("tmpdir")
seal.sys.Ensure(tmpdir.String(), 0700) seal.sys.Ensure(tmpdir.String(), 0700)
seal.sys.UpdatePermType(system.User, tmpdir.String(), acl.Execute) seal.sys.UpdatePermType(system.User, tmpdir.String(), acl.Execute)
tmpdirInst := tmpdir.Append(seal.user.aid.String()) tmpdirInst := tmpdir.Append(seal.user.identity.String())
seal.sys.Ensure(tmpdirInst.String(), 01700) seal.sys.Ensure(tmpdirInst.String(), 01700)
seal.sys.UpdatePermType(system.User, tmpdirInst.String(), acl.Read, acl.Write, acl.Execute) seal.sys.UpdatePermType(system.User, tmpdirInst.String(), acl.Read, acl.Write, acl.Execute)
// mount inner /tmp from share so it shares persistence and storage behaviour of host /tmp // mount inner /tmp from share so it shares persistence and storage behaviour of host /tmp

12
internal/app/username.go Normal file
View File

@ -0,0 +1,12 @@
package app
import "regexp"
// nameRegex is the default NAME_REGEX value from adduser.
var nameRegex = regexp.MustCompilePOSIX(`^[a-zA-Z][a-zA-Z0-9_-]*\$?$`)
// isValidUsername returns whether the argument is a valid username
func isValidUsername(username string) bool {
return len(username) < sysconf(_SC_LOGIN_NAME_MAX) &&
nameRegex.MatchString(username)
}