14 "github.com/mjl-/mox/imapclient"
15 "github.com/mjl-/mox/mlog"
16 "github.com/mjl-/mox/mox-"
17 "github.com/mjl-/mox/store"
20// Fuzz the server. For each fuzz string, we set up servers in various connection states, and write the string as command.
21func FuzzServer(f *testing.F) {
23 fmt.Sprintf("authenticate plain %s", base64.StdEncoding.EncodeToString([]byte("\u0000mjl@mox.example\u0000testtest"))),
41 "rename tmpbox ntmpbox",
43 "status inbox (uidnext messages uidvalidity deleted size unseen recent)",
44 "append inbox (\\seen) {2+}\r\nhi",
47 "fetch 1 (bodystructure)",
48 `store 1 flags (\seen \answered)`,
49 `store 1 +flags ($junk)`,
50 `store 1 -flags ($junk)`,
57 for _, cmd := range seed {
62 log := mlog.New("imapserver", nil)
63 mox.ConfigStaticPath = filepath.FromSlash("../testdata/imapserverfuzz/mox.conf")
64 mox.MustLoadConfig(true, false)
65 store.Close() // May not be open, we ignore error.
66 dataDir := mox.ConfigDirPath(mox.Conf.Static.DataDir)
68 err := store.Init(ctxbg)
70 f.Fatalf("store init: %v", err)
72 defer store.Switchboard()()
74 acc, err := store.OpenAccount(log, "mjl", false)
76 f.Fatalf("open account: %v", err)
82 err = acc.SetPassword(log, password0)
84 f.Fatalf("set password: %v", err)
87 comm := store.RegisterComm(acc)
88 defer comm.Unregister()
94 fl, err = os.OpenFile("fuzz.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
100 flog := func(err error, msg string) {
101 if fl != nil && err != nil {
102 fmt.Fprintf(fl, "%s: %v\n", msg, err)
106 f.Fuzz(func(t *testing.T, s string) {
107 run := func(cmds []string) {
108 limitersInit() // Reset rate limiters.
109 serverConn, clientConn := net.Pipe()
110 defer serverConn.Close()
115 // Protocol can become botched, when fuzzer sends literals.
120 if !ok || (!errors.Is(err, os.ErrDeadlineExceeded) && !errors.Is(err, io.EOF)) {
125 defer clientConn.Close()
127 err := clientConn.SetDeadline(time.Now().Add(time.Second))
128 flog(err, "set client deadline")
129 client, _ := imapclient.New(mox.Cid(), clientConn, true)
131 for _, cmd := range cmds {
132 client.Commandf("", "%s", cmd)
135 client.Commandf("", "%s", s)
139 err = serverConn.SetDeadline(time.Now().Add(time.Second))
140 flog(err, "set server deadline")
141 serve("test", cid, nil, serverConn, false, true, false, "")
145 // Each command brings the connection state one step further. We try the fuzzing
146 // input for each state.
148 run([]string{`login mjl@mox.example "` + password0 + `"`})
149 run([]string{`login mjl@mox.example "` + password0 + `"`, "select inbox"})
150 xappend := fmt.Sprintf("append inbox () {%d+}\r\n%s", len(exampleMsg), exampleMsg)
151 run([]string{`login mjl@mox.example "` + password0 + `"`, "select inbox", xappend})