On Thu, Jan 09, 2020 at 04:10:03PM +0100, Martin Pieuchot wrote:
>               case SO_RCVTIMEO:
>                   {
>                       struct timeval tv;
> -                     int val;
> +                     uint64_t nsecs;
>
>                       if (m == NULL || m->m_len < sizeof (tv))
>                               return (EINVAL);
>                       memcpy(&tv, mtod(m, struct timeval *), sizeof tv);
> -                     val = tvtohz(&tv);
> -                     if (val > USHRT_MAX)
> -                             return (EDOM);
> -
> +                     nsecs = TIMEVAL_TO_NSEC(&tv);

There was a range check before, I would like to keep that.
And tv is user data, we should be more paranoid.
Something like this, or a new macro TIMEVAL_ISVALID() ?

                        if (tv->tv_usec < 0 || tv->tv_usec >= 1000000 ||
                            TIMEVAL_TO_NSEC(&tv) == UINT64_MAX)
                                return (EDOM);

>                       case SO_SNDTIMEO:
> -                             so->so_snd.sb_timeo = val;
> +                             so->so_snd.sb_nsecs = nsecs;

The send buffer field is stil a timeout and not some nanoseconds.
Can we call it sb_timeo_nsec ?

> -                     memset(&tv, 0, sizeof(tv));
> -                     tv.tv_sec = val / hz;
> -                     tv.tv_usec = (val % hz) * tick;
> +                     NSEC_TO_TIMEVAL(nsecs, &tv);

The memset is here to clear padding bytes and to prevent kernel
memory leakage to userland.  Please keep it.

> +static inline uint64_t
> +TIMEVAL_TO_NSEC(const struct timeval *tv)
> +{
> +     if (tv->tv_sec > (UINT64_MAX - tv->tv_usec * 1000ULL) / 1000000000ULL)
> +             return UINT64_MAX;
> +     return tv->tv_sec * 1000000000ULL + tv->tv_usec * 1000ULL;
> +}

I think this overflow check is correct under the assumption that
tv_usec is in a valid range.

bluhm

Reply via email to