Kernel space: Details of the vmsplice() exploit
A recent Linux security hole allows local users to seize the power of root. We show the Linux bugs that came together to let it happen
Jonathan Corbet (LinuxWorld) 19/03/2008 10:43:28

Last week, we published a discussion of the vmsplice() exploit which showed how the failure to check permissions for a read operation led to a buffer overflow within the kernel. Subsequently, a linux-kernel reader pointed out that the article stopped short of a complete explanation: this is not an ordinary buffer overflow exploit. This article picks up where the last one left off and describes how the vmsplice() exploit makes use of this buffer overflow to take over the system. When vmsplice() is being used to feed data from memory into a pipe, the function charged with making it all happen is vmsplice_to_pipe(), found in fs/splice.c. It declares a couple of arrays of interest:

struct page *pages[PIPE_BUFFERS]; struct partial_page partial[PIPE_BUFFERS];

PIPE_BUFFERS, remember, is 16 on exploitable configurations. Both of these arrays are passed into get_iovec_page_array(), which, as described in the previous article, makes a call to get_user_pages() to fill in the pages array. As a result of the failure to check whether the calling application is allowed to read the requested region of memory, get_user_pages() will overflow the pages array, writing far more than PIPE_BUFFERS pointers into it. These are, however, pointers to legitimate kernel data structures; it remains to be seen how this overflow enables the attacker to take control of the system.

The partial array is also passed into get_iovec_page_array(); it describes the portion of each page which should be written into the pipe. To that end, a loop like this is run immediately after returning from get_user_pages():

for (i = 0; i < error; i++) { const int plen = min_t(size_t, len, PAGE_SIZE - off); partial[buffers].offset = off; partial[buffers].len = plen; /* ... */ }

Since full pages are being written in this case, the calculated offset will be zero, and the length will be PAGE_SIZE (4096). The value of error is the return value from get_user_pages(); that will be the number of pages actually mapped: 46, in the case of the exploit. Remember that the partial array is also dimensioned to hold 16 entries, so this loop will overflow that array as well.

More about Linux
Recommend this article?
Yes0 votes
No0 votes

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

Enter the fully qualified URL, eg. http://www.example.com/
Users posting comments agree to the PC World comments policy.
Login or register to link comments to your user profile, or you may also post a comment without being logged in.
Syndicate content
 
Gift Guide
MWave
Samsung

CXO Latest

LED Advisor
 

Colour your world with Samsung

A chance to win with every
Samsung Consumable purchase*