On 2023/03/18 15:06:43 +0100, p...@delphinusdns.org wrote: > >Synopsis: segmentation fault in opensmtpd mda > >Category: system > >Environment: > System : OpenBSD 7.2 > Details : OpenBSD 7.2 (GENERIC.MP) #2: Thu Nov 24 23:53:03 MST 2022 > > r...@syspatch-72-arm64.openbsd.org:/usr/src/sys/arch/arm64/compile/GENERIC.MP > > Architecture: OpenBSD.arm64 > Machine : arm64 > >Description: > I would have waited another week after contacting Gilles at his address > and at his openbsd.org address last week, but we're out of -beta and I'd like > to see this addressed before release. It may already be too late though. > I've found a way to crash the mda that is forked from opensmtpd before the > exec. It is a specially crafted .forward file that does this. In the worst > case scenario it will fill up /var with smtpd.core's when the > kern.nosuidcoredump sysctl is set to 3. The queue files are stuck in queue > and have to be removed either with smtpctl remove or until they time out. > A lot of these could fill /var with corefiles quicker. > >How-To-Repeat: > Here is the "exploit" code that I stuck into my .forward, I also gave > this to Gilles.
can be replicated with a way more simpler file: % cat ~/.forward "|%{mda}" Here's the backtrace: (gdb) bt #0 _libc_strlcpy (dst=<optimized out>, src=<optimized out>, dsize=<optimized out>) at /usr/src/lib/libc/string/strlcpy.c:36 #1 0x0000083cd79daac0 in mda_expand_token (dest=0x7f7ffffccf10 "", len=1024, token=0x7f7ffffcce80 "mda[0:127]:raw", dlv=0x7f7ffffce9e0, ui=0x7f7ffffcfce0, mda_command=0x0) at /usr/src/usr.sbin/smtpd/smtpd/../mda_variables.c:162 #2 0x0000083cd79da1af in mda_expand_format ( buf=0x7f7ffffcdf90 "%{mda[0:127]:raw}", len=2048, dlv=0x7f7ffffce9e0, ui=0x7f7ffffcfce0, mda_command=0x0) at /usr/src/usr.sbin/smtpd/smtpd/../mda_variables.c:298 #3 0x0000083cd79d9a3d in mda_unpriv (dsp=0x83f4722d000, deliver=0x7f7ffffce9e0, pw_name=0x7f7ffffcfce0 "op", pw_dir=0x7f7ffffcfde0 "/home/op") at /usr/src/usr.sbin/smtpd/smtpd/../mda_unpriv.c:46 #4 0x0000083cd7a13285 in forkmda (p=0x83f510fb000, id=18429899215001711955, deliver=0x7f7ffffce9e0) at /usr/src/usr.sbin/smtpd/smtpd/../smtpd.c:1533 #5 0x0000083cd7a123e8 in parent_imsg (p=0x83f510fb000, imsg=0x7f7ffffd0230) at /usr/src/usr.sbin/smtpd/smtpd/../smtpd.c:204 #6 0x0000083cd79db7fc in mproc_dispatch (fd=7, event=2, arg=0x83f510fb000) at /usr/src/usr.sbin/smtpd/smtpd/../mproc.c:194 #7 0x0000083efaf30ebf in event_process_active (base=0x83f47232400) at /usr/src/lib/libevent/event.c:333 #8 event_base_loop (base=0x83f47232400, flags=<optimized out>) at /usr/src/lib/libevent/event.c:483 #9 0x0000083cd7a1030b in smtpd () at /usr/src/usr.sbin/smtpd/smtpd/../smtpd.c:1074 #10 0x0000083cd7a0f5a7 in main (argc=0, argv=0x7f7ffffd0660) at /usr/src/usr.sbin/smtpd/smtpd/../smtpd.c:721 (gdb) f 1 #1 0x0000083cd79daac0 in mda_expand_token (dest=0x7f7ffffccf10 "", len=1024, token=0x7f7ffffcce80 "mda[0:127]:raw|", '/' <repeats 110 times>, dlv=0x7f7ffffce9e0, ui=0x7f7ffffcfce0, mda_command=0x0) at /usr/src/usr.sbin/smtpd/smtpd/../mda_variables.c:162 162 if (strlcpy(tmp, string, sizeof tmp) >= sizeof tmp) (gdb) p string $1 = 0x0 (gdb) p mda_command $2 = 0x0 We hit the else-if at line 147: 146 else if (!strcasecmp("mda", rtoken)) { 147 string = mda_command; 148 replace = 0; 149 } but mda_command is NULL. That NULL originates in mda_unpriv() (in mda_unpriv.c:46) where NULL is passed to mda_expand_format(), which is then passed as-is to mda_expand_token(). I don't see how this should work. I also don't have experience with the internals of smtpd and the more complex .forward I've used until now was "o...@omarpolo.com". I hope this can save someone else some time tho :)