hst: optionally reject insecure options

This prevents inadvertent use of insecure compatibility features.

Closes #30.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-04-10 19:12:45 +09:00
parent 952082bd9b
commit c33a6a5b7e
9 changed files with 128 additions and 39 deletions

View File

@@ -140,21 +140,29 @@ var (
ErrInsecure = errors.New("configuration is insecure")
)
const (
// VAllowInsecure allows use of compatibility options considered insecure
// under any configuration, to work around ecosystem-wide flaws.
VAllowInsecure = 1 << iota
)
// Validate checks [Config] and returns [AppError] if an invalid value is encountered.
func (config *Config) Validate() error {
func (config *Config) Validate(flags int) error {
const step = "validate configuration"
if config == nil {
return &AppError{Step: "validate configuration", Err: ErrConfigNull,
return &AppError{Step: step, Err: ErrConfigNull,
Msg: "invalid configuration"}
}
// this is checked again in hsu
if config.Identity < IdentityStart || config.Identity > IdentityEnd {
return &AppError{Step: "validate configuration", Err: ErrIdentityBounds,
return &AppError{Step: step, Err: ErrIdentityBounds,
Msg: "identity " + strconv.Itoa(config.Identity) + " out of range"}
}
if config.SchedPolicy < 0 || config.SchedPolicy > ext.SCHED_LAST {
return &AppError{Step: "validate configuration", Err: ErrSchedPolicyBounds,
return &AppError{Step: step, Err: ErrSchedPolicyBounds,
Msg: "scheduling policy " +
strconv.Itoa(int(config.SchedPolicy)) +
" out of range"}
@@ -168,34 +176,51 @@ func (config *Config) Validate() error {
}
if config.Container == nil {
return &AppError{Step: "validate configuration", Err: ErrConfigNull,
return &AppError{Step: step, Err: ErrConfigNull,
Msg: "configuration missing container state"}
}
if config.Container.Home == nil {
return &AppError{Step: "validate configuration", Err: ErrConfigNull,
return &AppError{Step: step, Err: ErrConfigNull,
Msg: "container configuration missing path to home directory"}
}
if config.Container.Shell == nil {
return &AppError{Step: "validate configuration", Err: ErrConfigNull,
return &AppError{Step: step, Err: ErrConfigNull,
Msg: "container configuration missing path to shell"}
}
if config.Container.Path == nil {
return &AppError{Step: "validate configuration", Err: ErrConfigNull,
return &AppError{Step: step, Err: ErrConfigNull,
Msg: "container configuration missing path to initial program"}
}
for key := range config.Container.Env {
if strings.IndexByte(key, '=') != -1 || strings.IndexByte(key, 0) != -1 {
return &AppError{Step: "validate configuration", Err: ErrEnviron,
return &AppError{Step: step, Err: ErrEnviron,
Msg: "invalid environment variable " + strconv.Quote(key)}
}
}
if et := config.Enablements.Unwrap(); !config.DirectPulse && et&EPulse != 0 {
return &AppError{Step: "validate configuration", Err: ErrInsecure,
et := config.Enablements.Unwrap()
if !config.DirectPulse && et&EPulse != 0 {
return &AppError{Step: step, Err: ErrInsecure,
Msg: "enablement PulseAudio is insecure and no longer supported"}
}
if flags&VAllowInsecure == 0 {
switch {
case et&EWayland != 0 && config.DirectWayland:
return &AppError{Step: step, Err: ErrInsecure,
Msg: "direct_wayland is insecure and no longer supported"}
case et&EPipeWire != 0 && config.DirectPipeWire:
return &AppError{Step: step, Err: ErrInsecure,
Msg: "direct_pipewire is insecure and no longer supported"}
case et&EPulse != 0 && config.DirectPulse:
return &AppError{Step: step, Err: ErrInsecure,
Msg: "direct_pulse is insecure and no longer supported"}
}
}
return nil
}