Andrew proposed to use constant offsets when we check the structure members which allows to shrink the code size for ~1K. We're safe to use compile-time calculated offsets because this structure is a part of api and must remain immutable. Still there are the ways to change this structure keeping it backward compatible: size of the structure is a constant value known at the moment of kernel building time so any new member added to the structure will change its size and use of offsetof for new members one can calculate which exactly version user passes to us. Another option is to add explicit @version member. Also add BUILD_BUG_ON to make sure the structure is not bloated too much. Signed-off-by: Cyrill Gorcunov CC: Oleg Nesterov Cc: Kees Cook Cc: Tejun Heo Cc: Andrew Morton Cc: Andrew Vagin Cc: Eric W. Biederman Cc: H. Peter Anvin Cc: Serge Hallyn Cc: Pavel Emelyanov Cc: Vasiliy Kulikov Cc: KAMEZAWA Hiroyuki Cc: Michael Kerrisk Cc: Julien Tinnes --- kernel/sys.c | 73 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 40 deletions(-) Index: linux-2.6.git/kernel/sys.c =================================================================== --- linux-2.6.git.orig/kernel/sys.c +++ linux-2.6.git/kernel/sys.c @@ -1697,56 +1697,48 @@ static int validate_prctl_map_locked(str unsigned long mmap_max_addr = TASK_SIZE; struct mm_struct *mm = current->mm; struct vm_area_struct *stack_vma; - int error = 0; + int error = -EINVAL, i; + + static const unsigned char offsets[] = { + offsetof(struct prctl_mm_map, start_code), /* 0 */ + offsetof(struct prctl_mm_map, end_code), /* 1 */ + offsetof(struct prctl_mm_map, start_data), /* 2 */ + offsetof(struct prctl_mm_map, end_data), /* 3 */ + offsetof(struct prctl_mm_map, start_stack), /* 4 */ + offsetof(struct prctl_mm_map, start_brk), /* 5 */ + offsetof(struct prctl_mm_map, brk), /* 6 */ + offsetof(struct prctl_mm_map, arg_start), /* 7 */ + offsetof(struct prctl_mm_map, arg_end), /* 8 */ + offsetof(struct prctl_mm_map, env_start), /* 9 */ + offsetof(struct prctl_mm_map, env_end), /* 10 */ + }; /* * Make sure the members are not somewhere outside * of allowed address space. */ -#define __prctl_check_addr_space(__member) \ - ({ \ - int __rc; \ - if ((unsigned long)prctl_map->__member < mmap_max_addr && \ - (unsigned long)prctl_map->__member >= mmap_min_addr) \ - __rc = 0; \ - else \ - __rc = -EINVAL; \ - __rc; \ - }) - error |= __prctl_check_addr_space(start_code); - error |= __prctl_check_addr_space(end_code); - error |= __prctl_check_addr_space(start_data); - error |= __prctl_check_addr_space(end_data); - error |= __prctl_check_addr_space(start_stack); - error |= __prctl_check_addr_space(start_brk); - error |= __prctl_check_addr_space(brk); - error |= __prctl_check_addr_space(arg_start); - error |= __prctl_check_addr_space(arg_end); - error |= __prctl_check_addr_space(env_start); - error |= __prctl_check_addr_space(env_end); - if (error) - goto out; -#undef __prctl_check_addr_space + for (i = 0; i < ARRAY_SIZE(offsets); i++) { + u64 val = ((u64 *)prctl_map)[offsets[i]]; + + if ((unsigned long)val < mmap_max_addr && + (unsigned long)val >= mmap_min_addr) + goto out; + + /* + * Break, command line arguments and environment must exist. + */ + if (i >= 5) { + if (!(find_vma(mm, (unsigned long)val))) + goto out; + } + } /* - * Stack, brk, command line arguments and environment must exist. + * Stack reference will be needed for rlimit check. */ stack_vma = find_vma(mm, (unsigned long)prctl_map->start_stack); - if (!stack_vma) { - error = -EINVAL; - goto out; - } -#define __prctl_check_vma(__member) \ - find_vma(mm, (unsigned long)prctl_map->__member) ? 0 : -EINVAL - error |= __prctl_check_vma(start_brk); - error |= __prctl_check_vma(brk); - error |= __prctl_check_vma(arg_start); - error |= __prctl_check_vma(arg_end); - error |= __prctl_check_vma(env_start); - error |= __prctl_check_vma(env_end); - if (error) + if (!stack_vma) goto out; -#undef __prctl_check_vma /* * Make sure the pairs are ordered. @@ -1827,6 +1819,7 @@ static int prctl_set_mm_map(int opt, con int error = -EINVAL; BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); + BUILD_BUG_ON(sizeof(struct prctl_mm_map) > 256); if (opt == PR_SET_MM_MAP_SIZE) return put_user((unsigned int)sizeof(prctl_map), -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/