setxattr
The setxattr() syscall allows userspace to attach arbitrary meta data to a filesystem inode object. It is useful because the kernel must allocate memory to store the xattr value, and the contents of that allocation can be controlled from userspace.
GLibc Function
int setxattr(
const char *path,
const char *name,
const void *value,
size_t size,
int flags
);
The important arguments for heap spraying are:
path→ filesystem object to attach the xattr toname→ xattr namevalue→ attacker-controlled datasize→ size of the data copied into the kernelflags→XATTR_CREATE/XATTR_REPLACE/0
For example:
char buf[0x100];
memset(buf, 'A', sizeof(buf));
setxattr("/home/user","user.x",buf,0x100,XATTR_CREATE);
2. Why Spray setxattr()
- The primary reason is that kmem cache object is created for the attacker controlled size and moreover, the content put into that object is attacker controlled.
- However, remember that the object allocated is just for a temporary storage (i
setxattr_copy()) until a persistent data structure is created (simple_xattr_alloc()) and mapped to the corresponding inode. Eventually, this object is freed back the kmem. Therefore, this technique can be used to overwrite overlapping data structures in memory. - For more implementation details, check out
fs/xattr.c
3. Exploitation Context
setxattr() is particularly useful for:
- Heap Grooming — repeatedly create xattrs to populate a particular kmalloc cache.
- Controlled Data — the xattr value is copied from userspace, allowing control over the allocation’s contents.
The important distinction is:
setxattr()is useful not simply because it allocates memory, but because it gives you a kernel allocation whose contents are substantially controlled by userspace.
4. How to?
Minimal helper:
#include <sys/xattr.h>
static int spray_xattr(const void *buf, size_t size,int count)
{
int ret;
for(int i=0;i<count;i++){
ret = setxattr("/home/user","user.x",buf,size,XATTR_CREATE);
if(ret<0)
perror("setxattr")'
}
return 0;
}
uint8_t buf[0x100];
// set the buf with correct data to overwrite already existing object
set_buf(buf);
spray_xattr(buf, sizeof(buf),0x50)
To inspect the resulting xattrs:
getfattr -d /home/user