[PATCH] awk: fix use after free (CVE-2022-30065)

Natanael Copa ncopa at alpinelinux.org
Thu Jun 16 21:04:47 UTC 2022


On Thu, 16 Jun 2022 12:54:56 +0200
Natanael Copa <ncopa at alpinelinux.org> wrote:

> On Tue, 14 Jun 2022 18:24:54 +0200
> Denys Vlasenko <vda.linux at googlemail.com> wrote:
> 
> > On Tue, Jun 14, 2022 at 8:55 AM Natanael Copa <ncopa at alpinelinux.org> wrote:  
> > > Hi!
> > >
> > > Is there anything else I can do to help fix CVE-2022-30065? I have
> > > created a testcase for the testsuite and proposed a fix, but I'm not
> > > that familiar with awk code so I would appreciate some help with this
> > > before pushing it to thousands (millions?) of users.    
> > 
> > cd testsuite && ./runtest awk
> > 
> > fails a lot with this change.  
> 
> Indeed, sorry! I thought I ran it locally but I must have done something wrong when running them here.
> 
> Need to go back to the drawing board...

Ok, so I have made some progress and have another possible fix. I also
separated the test case into a separate commit, so it becomes easier to
test in different branches etc. while working on it.

I also have another (valid?) testcase which passes on gawk and nawk,
but fails with my fix suggestion. I also attach a WIP patch which adds
some debug info of pointer values to make it visible when tmpvars are
allocated and when evaluate() returns the just free'd pointer.

Summary of the attached patches:

0001-awk-fix-use-after-free-CVE-2022-30065.patch:
	Potential fix, that prevents the use-after-free. But honestly,
	I don't really know what I'm doing and I don't know if this
	breaks any valid cases.

0002-awk-test-for-CVE-2022-30065.patch:
	The test case for the CVE. gawk and mawk returns syntax error
	for this test. This patch can be applied as is, but it will not
	pass until we have a proper fix.

0003-awk-add-test-for-setting-1-while-testing-it.patch:
	A test case that passes with mawk/gawk but fails with the
	proposed fix. I don't know if this is valid syntax or if it is
	ok to error out with syntax error.

0004-WIP-debug-awk.patch:
	Temp patch that adds extra printf debug info to show what
	happens. This patch should *not* be applied upstream, but can
	be used in local development git branches to help debug.


With the attached debug print 0004-WIP-debug-awk.patch applied, gives
the following output when running: echo | ./busybox awk '$1$1=0'

# My comments are prefixed with a #
# TIP: do a in browser/reader search for '0x7f52929debb0' to highlight
# where the problematic address is used.

fsrealloc: xrealloc(0, 512)
fsrealloc: Fields=0x7f52929df030..0x7f52929df22f
getvar_i: 0.000000
getvar_i: 1.000000
entered awk_getline()
returning from awk_getline(): 1
getvar_i: 0.000000
getvar_i: 0.000000
entered evaluate(op=0x7f52929dff30, res=0x7f5292a77328)
	tmpvars=0x7f52929deb60
opinfo:00000300 opn:00000000
switch(0x3)
NEWSOURCE
opinfo:00000d00 opn:00000000
switch(0xd)
TEST
entered evaluate(op=0x7f52929dd530, res=0x7f5292a772a8)
	tmpvars=0x7f52929debb0		# this is where allocation happens
opinfo:4a031f00 opn:00000000
entered evaluate(op=0x7f52929dd470, res=0x7f52929debb0) # the buffer is passed here
	tmpvars=0x7f52929dd820
opinfo:230f1500 opn:00000000
entered evaluate(op=0x7f52929dffc0, res=0x7f52929dd820)
	tmpvars=0x7f52929dd870
opinfo:05021700 opn:00000000
entered evaluate(op=0x7f52929dd410, res=0x7f52929dd890)
	tmpvars=0x7f52929dd8c0
opinfo:00002700 opn:00000000
switch(0x27)
VAR
returning from evaluate(): res=0x7f52929dd440, tmpvars=0x7f52929dd8c0
switch(0x17)
FIELD
getvar_i: 1.000000
returning from evaluate(): res=0x7f52929df030, tmpvars=0x7f52929dd870
opinfo & OF_RES1: L.v:'0x7f52929df030'
L.s:''
entered evaluate(op=0x7f52929dd4a0, res=0x7f52929dd840)
	tmpvars=0x7f52929dd910
opinfo:05021700 opn:00000000
entered evaluate(op=0x7f52929dd4d0, res=0x7f52929dd930)
	tmpvars=0x7f52929dd960
opinfo:00002700 opn:00000000
switch(0x27)
VAR
returning from evaluate(): res=0x7f52929dd500, tmpvars=0x7f52929dd960
switch(0x17)
FIELD
getvar_i: 1.000000
returning from evaluate(): res=0x7f52929df030, tmpvars=0x7f52929dd910
R.s:''
switch(0x15)
CONCAT /
COMMA: L.s='', sep='', R.s=''
returning from evaluate(): res=0x7f52929debb0, tmpvars=0x7f52929dd820   # address is return value here
opinfo & OF_RES1: L.v:'0x7f52929debb0'		# L.v is from TEST tmpvars here
entered evaluate(op=0x7f52929dd560, res=0x7f52929debd0)
	tmpvars=0x7f52929dd820
opinfo:00002700 opn:00000000
switch(0x27)
VAR
returning from evaluate(): res=0x7f52929dd590, tmpvars=0x7f52929dd820
switch(0x1f)
MOVE L.v=0x7f52929debb0, res=0x7f5292a772a8	# MOVE passes the reference here
copyvar: number:0.000000 string:'(null)'	# copyvar here will copy the reference to res here
returning from evaluate(): res=0x7f52929debb0, tmpvars=0x7f52929debb0 # res is now set to same value as tmpvars which is free'd.
# evaluate() here returns the value it just free'd.
awk: cmd. line:1: Possible syntax error


So, during TEST tmpvars is allocated. MOVE will do res=tmpvars, and
then is tmpvars free'd and evaluate() return the free'd value.

So MOVE's copyvar should may actually copy it instead of just copying
the reference? If we do that, when and how is it free'd to avoid memory leaks?

Should we implement a refcount of some sort?

I have no idea.

Kind regards,
Natanael Copa

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0004-WIP-debug-awk.patch
Type: text/x-patch
Size: 2620 bytes
Desc: not available
URL: <http://lists.busybox.net/pipermail/busybox/attachments/20220616/d42cce5b/attachment-0004.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0003-awk-add-test-for-setting-1-while-testing-it.patch
Type: text/x-patch
Size: 718 bytes
Desc: not available
URL: <http://lists.busybox.net/pipermail/busybox/attachments/20220616/d42cce5b/attachment-0005.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-awk-test-for-CVE-2022-30065.patch
Type: text/x-patch
Size: 701 bytes
Desc: not available
URL: <http://lists.busybox.net/pipermail/busybox/attachments/20220616/d42cce5b/attachment-0006.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-awk-fix-use-after-free-CVE-2022-30065.patch
Type: text/x-patch
Size: 910 bytes
Desc: not available
URL: <http://lists.busybox.net/pipermail/busybox/attachments/20220616/d42cce5b/attachment-0007.bin>


More information about the busybox mailing list