cmd/fsu: check parse behaviour
Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
be30e2f11e
commit
1fd571d561
@ -61,8 +61,19 @@ func main() {
|
||||
// aid
|
||||
uid := 1000000
|
||||
|
||||
// refuse to run if fsurc is not protected correctly
|
||||
if s, err := os.Stat(fsuConfFile); err != nil {
|
||||
log.Fatal(err)
|
||||
} else if s.Mode().Perm() != 0400 {
|
||||
log.Fatal("bad fsurc perm")
|
||||
} else if st := s.Sys().(*syscall.Stat_t); st.Uid != 0 || st.Gid != 0 {
|
||||
log.Fatal("fsurc must be owned by uid 0")
|
||||
}
|
||||
|
||||
// authenticate before accepting user input
|
||||
if fid, ok := parseConfig(fsuConfFile, puid); !ok {
|
||||
if f, err := os.Open(fsuConfFile); err != nil {
|
||||
log.Fatal(err)
|
||||
} else if fid, ok := mustParseConfig(f, puid); !ok {
|
||||
log.Fatalf("uid %d is not in the fsurc file", puid)
|
||||
} else {
|
||||
uid += fid * 10000
|
||||
|
@ -4,10 +4,9 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func parseUint32Fast(s string) (int, error) {
|
||||
@ -30,48 +29,39 @@ func parseUint32Fast(s string) (int, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func parseConfig(p string, puid int) (fid int, ok bool) {
|
||||
// refuse to run if fsurc is not protected correctly
|
||||
if s, err := os.Stat(p); err != nil {
|
||||
log.Fatal(err)
|
||||
} else if s.Mode().Perm() != 0400 {
|
||||
log.Fatal("bad fsurc perm")
|
||||
} else if st := s.Sys().(*syscall.Stat_t); st.Uid != 0 || st.Gid != 0 {
|
||||
log.Fatal("fsurc must be owned by uid 0")
|
||||
}
|
||||
func parseConfig(r io.Reader, puid int) (fid int, ok bool, err error) {
|
||||
s := bufio.NewScanner(r)
|
||||
var line, puid0 int
|
||||
for s.Scan() {
|
||||
line++
|
||||
|
||||
if r, err := os.Open(p); err != nil {
|
||||
log.Fatal(err)
|
||||
return -1, false
|
||||
} else {
|
||||
s := bufio.NewScanner(r)
|
||||
var line int
|
||||
for s.Scan() {
|
||||
line++
|
||||
|
||||
// <puid> <fid>
|
||||
lf := strings.SplitN(s.Text(), " ", 2)
|
||||
if len(lf) != 2 {
|
||||
log.Fatalf("invalid entry on line %d", line)
|
||||
}
|
||||
|
||||
var puid0 int
|
||||
if puid0, err = parseUint32Fast(lf[0]); err != nil || puid0 < 1 {
|
||||
log.Fatalf("invalid parent uid on line %d", line)
|
||||
}
|
||||
|
||||
ok = puid0 == puid
|
||||
if ok {
|
||||
// allowed fid range 0 to 99
|
||||
if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 {
|
||||
log.Fatalf("invalid fortify uid on line %d", line)
|
||||
}
|
||||
return
|
||||
}
|
||||
// <puid> <fid>
|
||||
lf := strings.SplitN(s.Text(), " ", 2)
|
||||
if len(lf) != 2 {
|
||||
return -1, false, fmt.Errorf("invalid entry on line %d", line)
|
||||
}
|
||||
if err = s.Err(); err != nil {
|
||||
log.Fatalf("cannot read fsurc: %v", err)
|
||||
|
||||
puid0, err = parseUint32Fast(lf[0])
|
||||
if err != nil || puid0 < 1 {
|
||||
return -1, false, fmt.Errorf("invalid parent uid on line %d", line)
|
||||
}
|
||||
|
||||
ok = puid0 == puid
|
||||
if ok {
|
||||
// allowed fid range 0 to 99
|
||||
if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 {
|
||||
return -1, false, fmt.Errorf("invalid fortify uid on line %d", line)
|
||||
}
|
||||
return
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
return -1, false, s.Err()
|
||||
}
|
||||
|
||||
func mustParseConfig(r io.Reader, puid int) (int, bool) {
|
||||
fid, ok, err := parseConfig(r, puid)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return fid, ok
|
||||
}
|
||||
|
96
cmd/fsu/parse_test.go
Normal file
96
cmd/fsu/parse_test.go
Normal file
@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseUint32Fast(t *testing.T) {
|
||||
t.Run("zero-length", func(t *testing.T) {
|
||||
if _, err := parseUint32Fast(""); err == nil || err.Error() != "zero length string" {
|
||||
t.Errorf(`parseUint32Fast(""): error = %v`, err)
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("overflow", func(t *testing.T) {
|
||||
if _, err := parseUint32Fast("10000000000"); err == nil || err.Error() != "string too long" {
|
||||
t.Errorf("parseUint32Fast: error = %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("invalid byte", func(t *testing.T) {
|
||||
if _, err := parseUint32Fast("meow"); err == nil || err.Error() != "invalid character 'm' at index 0" {
|
||||
t.Errorf(`parseUint32Fast("meow"): error = %v`, err)
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("full range", func(t *testing.T) {
|
||||
testRange := func(i, end int) {
|
||||
for ; i < end; i++ {
|
||||
s := strconv.Itoa(i)
|
||||
w := i
|
||||
t.Run("parse "+s, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
v, err := parseUint32Fast(s)
|
||||
if err != nil {
|
||||
t.Errorf("parseUint32Fast(%q): error = %v",
|
||||
s, err)
|
||||
return
|
||||
}
|
||||
if v != w {
|
||||
t.Errorf("parseUint32Fast(%q): got %v",
|
||||
s, v)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
testRange(0, 5000)
|
||||
testRange(105000, 110000)
|
||||
testRange(23005000, 23010000)
|
||||
testRange(456005000, 456010000)
|
||||
testRange(7890005000, 7890010000)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_parseConfig(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
puid, want int
|
||||
wantErr string
|
||||
rc string
|
||||
}{
|
||||
{"empty", 0, -1, "", ``},
|
||||
{"invalid field", 0, -1, "invalid entry on line 1", `9`},
|
||||
{"invalid puid", 0, -1, "invalid parent uid on line 1", `f 9`},
|
||||
{"invalid fid", 1000, -1, "invalid fortify uid on line 1", `1000 f`},
|
||||
{"match", 1000, 0, "", `1000 0`},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
fid, ok, err := parseConfig(bytes.NewBufferString(tc.rc), tc.puid)
|
||||
if err == nil && tc.wantErr != "" {
|
||||
t.Errorf("parseConfig: error = %v; wantErr %q",
|
||||
err, tc.wantErr)
|
||||
return
|
||||
}
|
||||
if err != nil && err.Error() != tc.wantErr {
|
||||
t.Errorf("parseConfig: error = %q; wantErr %q",
|
||||
err, tc.wantErr)
|
||||
return
|
||||
}
|
||||
if ok == (tc.want == -1) {
|
||||
t.Errorf("parseConfig: ok = %v; want %v",
|
||||
ok, tc.want)
|
||||
return
|
||||
}
|
||||
if fid != tc.want {
|
||||
t.Errorf("parseConfig: fid = %v; want %v",
|
||||
fid, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user