> - len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
> - if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
> + len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
> + if (!len || len > MAX_ARG_STRLEN)
strnlen_user() is a scary function. Please do remember that if the memory
we just strlen'ed is writeable by any user thread then that thread can at
any time invalidate the number which the kernel now holds.
> - !(len = strnlen_user(compat_ptr(str), bprm->p))) {
> + !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
> ret = -EFAULT;
> goto out;
> }
>
> - if (bprm->p < len) {
> + if (MAX_ARG_STRLEN < len) {
> ret = -E2BIG;
> goto out;
> }
Do we have an off-by-one here? Should it be <=?
If not, then this code is relying upon the string's terminating \0 coming
from userspace? If so, that's buggy: userspace can overwrite the \0 after
we ran the strnlen_user(), perhaps, and confound the kernel?
> + vma_adjust(vma, new_start, old_end,
> + vma->vm_pgoff - (-shift >> PAGE_SHIFT), NULL);
hm, a right-shift of a negated unsigned value. That's pretty unusual. I
hope you know what you're doing ;)
> #define EXTRA_STACK_VM_PAGES 20 /* random */
>
> +/* Finalizes the stack vm_area_struct. The flags and permissions are updated,
> + * the stack is optionally relocated, and some extra space is added.
> + */
That's better.
But what extra space is added, and why?