-
Darrick Wong authored
With Suparna Bhattacharya <suparna@in.ibm.com> I was running a random system call generator against mainline the other day and got this bug report about AIO in dmesg: kernel BUG at fs/aio.c:1249! Each ioctx structure has a "users" field that acts as a reference counter for the ioctx, and a "dead" flag that seems to indicate that the ioctx isn't associated with any particular list of IO requests. The problem, then, lies in aio.c:1247. The io_destroy function checks the (old) value of the dead flag--if it's false (i.e. the ioctx is alive), then the function calls put_ioctx to decrease the reference count on the assumption that the ioctx is no longer associated with any requests. Later, it calls put_ioctx again, on the assumption that someone called lookup_ioctx to perform some operation at some point. This BUG is caused by the reference counts being off. The testcase that I provided looks for a chunk of user memory that's read-only and passes that to the sys_io_setup syscall. sys_io_setup checks that the pointer is readable, creates the ioctx and then tries to write the ioctx handle back to userland. This is where the problems start to surface. Since the pointer points to a non-writable region of memory, the write fails. The syscall handler then destroys the ioctx. The dead flag is zero, so io_destroy calls put_ioctx...but wait! Nobody ever put the ioctx into a request list. The ioctx is alive but not in a list, yet the io_destroy code assumes that being alive implies being in a request list somewhere. Hence, calling put_ioctx is bogus; the reference count becomes 0, and the ioctx is freed. Worse yet, put_ioctx is called again (on a freed pointer!) to clear up the lookup_ioctx that never happened. put_ioctx sees that the reference count has become negative and BUGs. Suparna's patch simply takes that additional ref so that io_destroy() will dtrt. Signed-off-by: Darrick Wong <djwong@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
e2e83e40