On 15/10/15(Thu) 14:09, Vincent Gross wrote:
> On 10/07/15 14:05, Martin Pieuchot wrote:
> > On 01/10/15(Thu) 19:40, Vincent Gross wrote:
> >> Although the sysctls controlling the port range are labelled
> >> "port(hi)?first" and
> >> "port(hi)?last", no ordering is enforced and you can have portfirst >
> >> portlast.
> >> in_pcbbind() (and in6_pcbsetport()) work around this by duplicating the
> >> loop looking
> >> for an available port.
> >
> > What about a small regress test?
> >
> >> This diff introduce temporary bounds and compare them to guarantee that
> >> first <= last, thus allowing deduplication of the port scan loop.
> >
> > Makes sense to me, I'd keep the comment though.
> >
> >>
> >> Tested on my laptop with a narrow port range and heavy cheezburger
> >> browsing, no fault
> >> detected. Deeper testing welcome.
> >>
> >> Should I include in6_pcbsetport() changes right now or should ipv4 be
> >> validated first ?
> >
> > I prefer when both version are keep in sync, so yes a in6_pcbsetport()
> > diff would be nice. Plus if it's possible to have a regress test it
> > would be awesome.
> >
>
> Ok ?
ok mpi@
>
>
> Index: sys/netinet/in_pcb.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/in_pcb.c,v
> retrieving revision 1.181
> diff -u -p -r1.181 in_pcb.c
> --- sys/netinet/in_pcb.c 9 Oct 2015 01:10:27 -0000 1.181
> +++ sys/netinet/in_pcb.c 15 Oct 2015 12:08:06 -0000
> @@ -360,67 +360,47 @@ in_pcbbind(struct inpcb *inp, struct mbu
> inp->inp_laddr = sin->sin_addr;
> }
> if (lport == 0) {
> - u_int16_t first, last;
> + u_int16_t bound_a, bound_b, first, last;
> int count;
>
> if (inp->inp_flags & INP_HIGHPORT) {
> - first = ipport_hifirstauto; /* sysctl */
> - last = ipport_hilastauto;
> + bound_a = ipport_hifirstauto; /* sysctl */
> + bound_b = ipport_hilastauto;
> } else if (inp->inp_flags & INP_LOWPORT) {
> if ((error = suser(p, 0)))
> return (EACCES);
> - first = IPPORT_RESERVED-1; /* 1023 */
> - last = 600; /* not IPPORT_RESERVED/2 */
> + bound_a = IPPORT_RESERVED-1; /* 1023 */
> + bound_b = 600; /* not IPPORT_RESERVED/2 */
> } else {
> - first = ipport_firstauto; /* sysctl */
> - last = ipport_lastauto;
> + bound_a = ipport_firstauto; /* sysctl */
> + bound_b = ipport_lastauto;
> + }
> + if (bound_a < bound_b) {
> + first = bound_a;
> + last = bound_b;
> + } else {
> + first = bound_b;
> + last = bound_a;
> }
>
> /*
> * Simple check to ensure all ports are not used up causing
> * a deadlock here.
> - *
> - * We split the two cases (up and down) so that the direction
> - * is not being tested on each round of the loop.
> */
>
> - if (first > last) {
> - /*
> - * counting down
> - */
> - count = first - last;
> - if (count)
> - lastport = first - arc4random_uniform(count);
> + count = last - first;
> + lastport = first + arc4random_uniform(count);
>
> - do {
> - if (count-- < 0) /* completely used? */
> - return (EADDRNOTAVAIL);
> - --lastport;
> - if (lastport > first || lastport < last)
> - lastport = first;
> - lport = htons(lastport);
> - } while (in_baddynamic(lastport,
> so->so_proto->pr_protocol) ||
> - in_pcblookup(table, &zeroin_addr, 0,
> - &inp->inp_laddr, lport, wild, inp->inp_rtableid));
> - } else {
> - /*
> - * counting up
> - */
> - count = last - first;
> - if (count)
> - lastport = first + arc4random_uniform(count);
> -
> - do {
> - if (count-- < 0) /* completely used? */
> - return (EADDRNOTAVAIL);
> - ++lastport;
> - if (lastport < first || lastport > last)
> - lastport = first;
> - lport = htons(lastport);
> - } while (in_baddynamic(lastport,
> so->so_proto->pr_protocol) ||
> - in_pcblookup(table, &zeroin_addr, 0,
> - &inp->inp_laddr, lport, wild, inp->inp_rtableid));
> - }
> + do {
> + if (count-- < 0) /* completely used? */
> + return (EADDRNOTAVAIL);
> + ++lastport;
> + if (lastport < first || lastport > last)
> + lastport = first;
> + lport = htons(lastport);
> + } while (in_baddynamic(lastport, so->so_proto->pr_protocol) ||
> + in_pcblookup(table, &zeroin_addr, 0,
> + &inp->inp_laddr, lport, wild, inp->inp_rtableid));
> }
> inp->inp_lport = lport;
> in_pcbrehash(inp);
> Index: sys/netinet6/in6_pcb.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/in6_pcb.c,v
> retrieving revision 1.77
> diff -u -p -r1.77 in6_pcb.c
> --- sys/netinet6/in6_pcb.c 15 Oct 2015 10:27:18 -0000 1.77
> +++ sys/netinet6/in6_pcb.c 15 Oct 2015 12:08:06 -0000
> @@ -293,7 +293,7 @@ in6_pcbsetport(struct in6_addr *laddr, s
> {
> struct socket *so = inp->inp_socket;
> struct inpcbtable *table = inp->inp_table;
> - u_int16_t first, last;
> + u_int16_t bound_a, bound_b, first, last;
> u_int16_t lastport = 0;
> u_int16_t lport = 0;
> int count;
> @@ -308,63 +308,43 @@ in6_pcbsetport(struct in6_addr *laddr, s
> wild |= INPLOOKUP_WILDCARD;
>
> if (inp->inp_flags & INP_HIGHPORT) {
> - first = ipport_hifirstauto; /* sysctl */
> - last = ipport_hilastauto;
> + bound_a = ipport_hifirstauto; /* sysctl */
> + bound_b = ipport_hilastauto;
> } else if (inp->inp_flags & INP_LOWPORT) {
> if ((error = suser(p, 0)))
> return (EACCES);
> - first = IPPORT_RESERVED-1; /* 1023 */
> - last = 600; /* not IPPORT_RESERVED/2 */
> + bound_a = IPPORT_RESERVED-1; /* 1023 */
> + bound_b = 600; /* not IPPORT_RESERVED/2 */
> } else {
> - first = ipport_firstauto; /* sysctl */
> - last = ipport_lastauto;
> + bound_a = ipport_firstauto; /* sysctl */
> + bound_b = ipport_lastauto;
> + }
> + if (bound_a < bound_b) {
> + first = bound_a;
> + last = bound_b;
> + } else {
> + first = bound_b;
> + last = bound_a;
> }
>
> /*
> * Simple check to ensure all ports are not used up causing
> * a deadlock here.
> - *
> - * We split the two cases (up and down) so that the direction
> - * is not being tested on each round of the loop.
> */
>
> - if (first > last) {
> - /*
> - * counting down
> - */
> - count = first - last;
> - if (count)
> - lastport = first - arc4random_uniform(count);
> -
> - do {
> - if (count-- < 0) /* completely used? */
> - return (EADDRNOTAVAIL);
> - --lastport;
> - if (lastport > first || lastport < last)
> - lastport = first;
> - lport = htons(lastport);
> - } while (in_baddynamic(lastport, so->so_proto->pr_protocol) ||
> - in_pcblookup(table, &zeroin6_addr, 0,
> - &inp->inp_laddr6, lport, wild, inp->inp_rtableid));
> - } else {
> - /*
> - * counting up
> - */
> - count = last - first;
> - if (count)
> - lastport = first + arc4random_uniform(count);
> -
> - do {
> - if (count-- < 0) /* completely used? */
> - return (EADDRNOTAVAIL);
> - ++lastport;
> - if (lastport < first || lastport > last)
> - lastport = first;
> - lport = htons(lastport);
> - } while (in_baddynamic(lastport, so->so_proto->pr_protocol) ||
> - in_pcblookup(table, &zeroin6_addr, 0,
> - &inp->inp_laddr6, lport, wild, inp->inp_rtableid));
> - }
> + count = last - first;
> + lastport = first + arc4random_uniform(count);
> +
> + do {
> + if (count-- < 0) /* completely used? */
> + return (EADDRNOTAVAIL);
> + ++lastport;
> + if (lastport < first || lastport > last)
> + lastport = first;
> + lport = htons(lastport);
> + } while (in_baddynamic(lastport, so->so_proto->pr_protocol) ||
> + in_pcblookup(table, &zeroin6_addr, 0,
> + &inp->inp_laddr6, lport, wild, inp->inp_rtableid));
>
> inp->inp_lport = lport;
> in_pcbrehash(inp);
>