2014-04-02 19:46:31

by Jim Keniston

[permalink] [raw]
Subject: Re: [PATCH 7/7] uprobes/x86: Introduce uprobe_xol_ops and arch_uprobe->ops

On Mon, 2014-03-31 at 21:44 +0200, Oleg Nesterov wrote:
...
> +/*
> + * Adjust the return address pushed by a call insn executed out of line.
> + */
> +static int adjust_ret_addr(unsigned long sp, long correction)
> +{
> + int rasize, ncopied;
> + long ra = 0;
> +
> + if (is_ia32_task())
> + rasize = 4;
> + else
> + rasize = 8;
> +
> + ncopied = copy_from_user(&ra, (void __user *)sp, rasize);
> + if (unlikely(ncopied))
> + return -EFAULT;
> +
> + ra += correction;
> + ncopied = copy_to_user((void __user *)sp, &ra, rasize);
> + if (unlikely(ncopied))
> + return -EFAULT;
> +
> + return 0;
> +}

This isn't your bug, Oleg -- you're just moving code -- but consider
taking this opportunity to fix it...

"ncopied" is a misnomer here. copy_from_user() and copy_to_user()
return the number of bytes that could NOT be copied. Once upon a time
(in uprobes's pre-upstream days), this was called "nleft" -- i.e., the
number of bytes left uncopied. A more accurate name like "nleft" or
"nmissed" or "nr_uncopied" might yield less confusion in the future --
or just dispense with the variable altogether.

arch_uretprobe_hijack_return_addr() has this same problem, although
there we need the variable, because if zero bytes of the return address
are overwritten, we can fail more gracefully.

Jim


2014-04-03 19:49:28

by Oleg Nesterov

[permalink] [raw]
Subject: Re: [PATCH 7/7] uprobes/x86: Introduce uprobe_xol_ops and arch_uprobe->ops

On 04/02, Jim Keniston wrote:
>
> On Mon, 2014-03-31 at 21:44 +0200, Oleg Nesterov wrote:
> ...
> > +/*
> > + * Adjust the return address pushed by a call insn executed out of line.
> > + */
> > +static int adjust_ret_addr(unsigned long sp, long correction)
> > +{
> > + int rasize, ncopied;
> > + long ra = 0;
> > +
> > + if (is_ia32_task())
> > + rasize = 4;
> > + else
> > + rasize = 8;
> > +
> > + ncopied = copy_from_user(&ra, (void __user *)sp, rasize);
> > + if (unlikely(ncopied))
> > + return -EFAULT;
> > +
> > + ra += correction;
> > + ncopied = copy_to_user((void __user *)sp, &ra, rasize);
> > + if (unlikely(ncopied))
> > + return -EFAULT;
> > +
> > + return 0;
> > +}
>
> This isn't your bug, Oleg -- you're just moving code -- but consider
> taking this opportunity to fix it...
>
> "ncopied" is a misnomer here. copy_from_user() and copy_to_user()
> return the number of bytes that could NOT be copied.

Yes, thanks. I'll try to cleanup this later. I am not sure yet, but
perhaps I will change adjust_ret_addr() and hijack_return_addr() to
use a couple of new get/put_user helpers, because ->call_emulate()
needs to check is_ia32_task() and write to *sp too.

Thanks.

Oleg.