From 9e4ad990992ebb588c599832d8d7dc0fe2a37475 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 17 Jan 2013 15:23:10 -0800 Subject: btrfs-progs: use ftw() unstead of system("du") size_sourcedir() uses shockingly bad code to try and estimate the size of the files and directories in a subtree. - Its use of snprintf(), strcat(), and sscanf() with arbitrarily small on-stack buffers manages to overflow the stack a few times when given long file names. $ BIG=$(perl -e 'print "a" x 200') $ mkdir -p /tmp/$BIG/$BIG/$BIG/$BIG/$BIG $ mkfs.btrfs /tmp/img -r /tmp/$BIG/$BIG/$BIG/$BIG/$BIG *** stack smashing detected ***: mkfs.btrfs terminated - It passes raw paths to system() allowing interpreting file names as shell control characters. $ mkfs.btrfs /tmp/img -r /tmp/spacey\ dir/ du: cannot access `/tmp/spacey': No such file or directory du: cannot access `dir/': No such file or directory - It redirects du output to "temp_file" in the current directory, allowing overwriting of files through symlinks. $ echo hi > target $ ln -s target temp_file $ mkfs.btrfs /tmp/img -r /tmp/somedir/ $ cat target 3 /tmp/somedir/ This fixes the worst problems while maintaining -r functionality by tearing out the system() code and using ftw() to walk the source tree and sum up st.st_size. Signed-off-by: Zach Brown --- kerncompat.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'kerncompat.h') diff --git a/kerncompat.h b/kerncompat.h index a38a9b0..c18fdf3 100644 --- a/kerncompat.h +++ b/kerncompat.h @@ -202,6 +202,16 @@ static inline long IS_ERR(const void *ptr) #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) +/* + * This looks more complex than it should be. But we need to + * get the type for the ~ right in round_down (it needs to be + * as wide as the result!), and we want to evaluate the macro + * arguments just once each. + */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define round_down(x, y) ((x) & ~__round_mask(x, y)) + /* * printk */ -- cgit v1.2.1