helper: separate helper args fd builder from dbus
This method of passing arguments is used in bubblewrap as well as other tools, this commit separates the argument builder/writer to the helper package and generalise it as an interface. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
parent
1cb90c0840
commit
000607da5f
|
@ -4,8 +4,9 @@ import (
|
|||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.ophivana.moe/cat/fortify/helper"
|
||||
)
|
||||
|
||||
// Proxy holds references to a xdg-dbus-proxy process, and should never be copied.
|
||||
|
@ -24,7 +25,7 @@ type Proxy struct {
|
|||
read *chan error
|
||||
ready *chan bool
|
||||
|
||||
seal *string
|
||||
seal helper.Args
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
|
@ -41,7 +42,7 @@ func (p *Proxy) String() string {
|
|||
}
|
||||
|
||||
if p.seal != nil {
|
||||
return *p.seal
|
||||
return p.seal.String()
|
||||
}
|
||||
|
||||
return "(unsealed dbus proxy)"
|
||||
|
@ -60,21 +61,20 @@ func (p *Proxy) Seal(session, system *Config) error {
|
|||
return errors.New("no configuration to seal")
|
||||
}
|
||||
|
||||
seal := strings.Builder{}
|
||||
seal := helper.NewArgs()
|
||||
|
||||
var args []string
|
||||
if session != nil {
|
||||
if err := session.buildSeal(&seal, p.session); err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args, session.Args(p.session)...)
|
||||
}
|
||||
if system != nil {
|
||||
if err := system.buildSeal(&seal, p.system); err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args, system.Args(p.system)...)
|
||||
}
|
||||
if err := seal.Seal(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := seal.String()
|
||||
p.seal = &v
|
||||
p.seal = seal
|
||||
return nil
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ func (p *Proxy) Start(ready *chan bool) error {
|
|||
|
||||
statsP, argsP := p.statP[0], p.argsP[1]
|
||||
|
||||
if _, err := argsP.Write([]byte(*p.seal)); err != nil {
|
||||
if _, err := p.seal.WriteTo(argsP); err != nil {
|
||||
if err1 := p.cmd.Process.Kill(); err1 != nil {
|
||||
panic(err1)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrContainsNull = errors.New("argument contains null character")
|
||||
)
|
||||
|
||||
// Args is sealed with a slice of arguments for writing to the helper args FD.
|
||||
// The sealing args is checked to not contain null characters.
|
||||
// Attempting to seal an instance twice will cause a panic.
|
||||
type Args interface {
|
||||
Seal(args []string) error
|
||||
io.WriterTo
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
// argsFD implements Args for helpers expecting null terminated arguments to a file descriptor.
|
||||
// argsFD must not be copied after first use.
|
||||
type argsFD struct {
|
||||
seal []byte
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (a *argsFD) Seal(args []string) error {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
if a.seal != nil {
|
||||
panic("args sealed twice")
|
||||
}
|
||||
|
||||
seal := bytes.Buffer{}
|
||||
|
||||
n := 0
|
||||
for _, arg := range args {
|
||||
// reject argument strings containing null
|
||||
if hasNull(arg) {
|
||||
return ErrContainsNull
|
||||
}
|
||||
|
||||
// accumulate buffer size
|
||||
n += len(arg) + 1
|
||||
}
|
||||
seal.Grow(n)
|
||||
|
||||
// write null terminated arguments
|
||||
for _, arg := range args {
|
||||
seal.WriteString(arg)
|
||||
seal.WriteByte('\x00')
|
||||
}
|
||||
|
||||
a.seal = seal.Bytes()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *argsFD) WriteTo(w io.Writer) (int64, error) {
|
||||
if a.seal == nil {
|
||||
panic("attempted to activate unsealed args")
|
||||
}
|
||||
|
||||
n, err := w.Write(a.seal)
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
func (a *argsFD) String() string {
|
||||
if a == nil {
|
||||
return "(invalid helper args)"
|
||||
}
|
||||
|
||||
if a.seal == nil {
|
||||
return "(unsealed helper args)"
|
||||
}
|
||||
|
||||
return strings.ReplaceAll(string(a.seal), "\x00", " ")
|
||||
}
|
||||
|
||||
func hasNull(s string) bool {
|
||||
for _, b := range s {
|
||||
if b == '\x00' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NewArgs returns a new instance of Args
|
||||
func NewArgs() Args {
|
||||
return new(argsFD)
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/*
|
||||
Package helper runs external helpers and manages their status and args FDs.
|
||||
*/
|
||||
package helper
|
Loading…
Reference in New Issue