diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-19 22:43:37 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-19 22:43:37 -0700 | 
| commit | 07ab67c8d0d7c1021343b7d5c045033d6bf7be69 (patch) | |
| tree | 5857098ebbb760afc8b0d722f119e06b3d1f6511 | |
| parent | 66e60f92518268f4d2a702a1c4ffbe1caacd6290 (diff) | |
Fix get_unmapped_area sanity tests
As noted by Chris Wright, we need to do the full range of tests regardless
of whether MAP_FIXED is set or not, so re-organize get_unmapped_area()
slightly to do the sanity checks unconditionally.
| -rw-r--r-- | include/linux/err.h | 4 | ||||
| -rw-r--r-- | mm/mmap.c | 59 | 
2 files changed, 34 insertions, 29 deletions
diff --git a/include/linux/err.h b/include/linux/err.h index 17c55df13615..ff71d2af5da3 100644 --- a/include/linux/err.h +++ b/include/linux/err.h @@ -13,6 +13,8 @@   * This should be a per-architecture thing, to allow different   * error and pointer decisions.   */ +#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L) +  static inline void *ERR_PTR(long error)  {  	return (void *) error; @@ -25,7 +27,7 @@ static inline long PTR_ERR(const void *ptr)  static inline long IS_ERR(const void *ptr)  { -	return unlikely((unsigned long)ptr > (unsigned long)-1000L); +	return IS_ERR_VALUE((unsigned long)ptr);  }  #endif /* _LINUX_ERR_H */ diff --git a/mm/mmap.c b/mm/mmap.c index 63df2d698414..de54acd9942f 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1302,37 +1302,40 @@ unsigned long  get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,  		unsigned long pgoff, unsigned long flags)  { -	if (flags & MAP_FIXED) { -		unsigned long ret; +	unsigned long ret; -		if (addr > TASK_SIZE - len) -			return -ENOMEM; -		if (addr & ~PAGE_MASK) -			return -EINVAL; -		if (file && is_file_hugepages(file))  { -			/* -			 * Check if the given range is hugepage aligned, and -			 * can be made suitable for hugepages. -			 */ -			ret = prepare_hugepage_range(addr, len); -		} else { -			/* -			 * Ensure that a normal request is not falling in a -			 * reserved hugepage range.  For some archs like IA-64, -			 * there is a separate region for hugepages. -			 */ -			ret = is_hugepage_only_range(current->mm, addr, len); -		} -		if (ret) -			return -EINVAL; -		return addr; -	} +	if (!(flags & MAP_FIXED)) { +		unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); -	if (file && file->f_op && file->f_op->get_unmapped_area) -		return file->f_op->get_unmapped_area(file, addr, len, -						pgoff, flags); +		get_area = current->mm->get_unmapped_area; +		if (file && file->f_op && file->f_op->get_unmapped_area) +			get_area = file->f_op->get_unmapped_area; +		addr = get_area(file, addr, len, pgoff, flags); +		if (IS_ERR_VALUE(addr)) +			return addr; +	} -	return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); +	if (addr > TASK_SIZE - len) +		return -ENOMEM; +	if (addr & ~PAGE_MASK) +		return -EINVAL; +	if (file && is_file_hugepages(file))  { +		/* +		 * Check if the given range is hugepage aligned, and +		 * can be made suitable for hugepages. +		 */ +		ret = prepare_hugepage_range(addr, len); +	} else { +		/* +		 * Ensure that a normal request is not falling in a +		 * reserved hugepage range.  For some archs like IA-64, +		 * there is a separate region for hugepages. +		 */ +		ret = is_hugepage_only_range(current->mm, addr, len); +	} +	if (ret) +		return -EINVAL; +	return addr;  }  EXPORT_SYMBOL(get_unmapped_area);  | 
