On 03/31/16 14:07, Alexander Bluhm wrote:
> On Wed, Mar 30, 2016 at 10:44:14PM +0200, Vincent Gross wrote:
>> This diff moves the "are we binding to a privileged port while not being
>> root ?"
>> check from in(6)_pcbaddrisavail() to in_pcbbind().
>
>> --- sys/netinet/in_pcb.c 26 Mar 2016 21:56:04 -0000 1.198
>> +++ sys/netinet/in_pcb.c 30 Mar 2016 20:33:00 -0000
>> @@ -341,9 +341,14 @@ in_pcbbind(struct inpcb *inp, struct mbu
>> }
>> }
>>
>> - if (lport == 0)
>> + if (lport == 0) {
>> if ((error = in_pcbpickport(&lport, wild, inp, p)))
>> return (error);
>> + } else {
>> + if (ntohs(lport) < IPPORT_RESERVED &&
>> + (error = suser(p, 0)))
>> + return (EACCES);
>> + }
>> inp->inp_lport = lport;
>
> At this point inp has already been modified. So when we bail out
> with EACCES here, we have a partially successful system call.
>
> Move the assignments
> inp->inp_laddr6 = sin6->sin6_addr;
> inp->inp_laddr = sin->sin_addr;
> down after the return (EACCES).
>
> Looks like that return (error) was wrong before.
in_pcbpickport() need the local address, so I extend the prototype and
keep a void * to the sin(6)_addr or zeroin46_addr. And while at it, I set
the INPLOOKUP_IPV6 flag which will be needed in in_pcbpickport().
Ok ?
Index: netinet/in_pcb.c
===================================================================
RCS file: /cvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.198
diff -u -p -r1.198 in_pcb.c
--- netinet/in_pcb.c 26 Mar 2016 21:56:04 -0000 1.198
+++ netinet/in_pcb.c 3 Apr 2016 19:16:37 -0000
@@ -286,6 +286,7 @@ in_pcbbind(struct inpcb *inp, struct mbu
struct socket *so = inp->inp_socket;
u_int16_t lport = 0;
int wild = 0;
+ void *laddr = &zeroin46_addr;
int error;
if (inp->inp_lport)
@@ -312,9 +313,10 @@ in_pcbbind(struct inpcb *inp, struct mbu
if (sin6->sin6_family != AF_INET6)
return (EAFNOSUPPORT);
+ wild |= INPLOOKUP_IPV6;
if ((error = in6_pcbaddrisavail(inp, sin6, wild, p)))
return (error);
- inp->inp_laddr6 = sin6->sin6_addr;
+ laddr = &sin6->sin6_addr;
lport = sin6->sin6_port;
break;
}
@@ -332,7 +334,7 @@ in_pcbbind(struct inpcb *inp, struct mbu
if ((error = in_pcbaddrisavail(inp, sin, wild, p)))
return (error);
- inp->inp_laddr = sin->sin_addr;
+ laddr = &sin->sin_addr;
lport = sin->sin_port;
break;
}
@@ -342,8 +344,20 @@ in_pcbbind(struct inpcb *inp, struct mbu
}
if (lport == 0)
- if ((error = in_pcbpickport(&lport, wild, inp, p)))
+ if ((error = in_pcbpickport(&lport, laddr, wild, inp, p)))
return (error);
+ if (nam) {
+ switch (sotopf(so)) {
+#ifdef INET6
+ case PF_INET6:
+ inp->inp_laddr6 = *(struct in6_addr *)laddr;
+ break;
+#endif
+ case PF_INET:
+ inp->inp_laddr = *(struct in_addr *)laddr;
+ break;
+ }
+ }
inp->inp_lport = lport;
in_pcbrehash(inp);
return (0);
@@ -418,12 +432,12 @@ in_pcbaddrisavail(struct inpcb *inp, str
}
int
-in_pcbpickport(u_int16_t *lport, int wild, struct inpcb *inp, struct proc *p)
+in_pcbpickport(u_int16_t *lport, void *laddr, int wild, struct inpcb *inp,
+ struct proc *p)
{
struct socket *so = inp->inp_socket;
struct inpcbtable *table = inp->inp_table;
u_int16_t first, last, lower, higher, candidate, localport;
- void *laddr;
int count;
if (inp->inp_flags & INP_HIGHPORT) {
@@ -453,10 +467,6 @@ in_pcbpickport(u_int16_t *lport, int wil
count = higher - lower;
candidate = lower + arc4random_uniform(count);
- if (sotopf(so) == PF_INET6)
- laddr = &inp->inp_laddr6;
- else
- laddr = &inp->inp_laddr;
do {
if (count-- < 0) /* completely used? */
Index: netinet/in_pcb.h
===================================================================
RCS file: /cvs/src/sys/netinet/in_pcb.h,v
retrieving revision 1.96
diff -u -p -r1.96 in_pcb.h
--- netinet/in_pcb.h 23 Mar 2016 15:50:36 -0000 1.96
+++ netinet/in_pcb.h 3 Apr 2016 19:16:37 -0000
@@ -290,6 +290,6 @@ int in6_pcbnotify(struct inpcbtable *, s
u_int, const struct sockaddr_in6 *, u_int, u_int, int, void *,
void (*)(struct inpcb *, int));
int in6_selecthlim(struct inpcb *);
-int in_pcbpickport(u_int16_t *, int, struct inpcb *, struct proc *);
+int in_pcbpickport(u_int16_t *, void *, int, struct inpcb *, struct proc *);
#endif /* _KERNEL */
#endif /* _NETINET_IN_PCB_H_ */