Skip to content

Commit 299ee12

Browse files
jgunthorpedavem330
authored andcommitted
sctp: Fixup v4mapped behaviour to comply with Sock API
The SCTP socket extensions API document describes the v4mapping option as follows: 8.1.15. Set/Clear IPv4 Mapped Addresses (SCTP_I_WANT_MAPPED_V4_ADDR) This socket option is a Boolean flag which turns on or off the mapping of IPv4 addresses. If this option is turned on, then IPv4 addresses will be mapped to V6 representation. If this option is turned off, then no mapping will be done of V4 addresses and a user will receive both PF_INET6 and PF_INET type addresses on the socket. See [RFC3542] for more details on mapped V6 addresses. This description isn't really in line with what the code does though. Introduce addr_to_user (renamed addr_v4map), which should be called before any sockaddr is passed back to user space. The new function places the sockaddr into the correct format depending on the SCTP_I_WANT_MAPPED_V4_ADDR option. Audit all places that touched v4mapped and either sanely construct a v4 or v6 address then call addr_to_user, or drop the unnecessary v4mapped check entirely. Audit all places that call addr_to_user and verify they are on a sycall return path. Add a custom getname that formats the address properly. Several bugs are addressed: - SCTP_I_WANT_MAPPED_V4_ADDR=0 often returned garbage for addresses to user space - The addr_len returned from recvmsg was not correct when returning AF_INET on a v6 socket - flowlabel and scope_id were not zerod when promoting a v4 to v6 - Some syscalls like bind and connect behaved differently depending on v4mapped Tested bind, getpeername, getsockname, connect, and recvmsg for proper behaviour in v4mapped = 1 and 0 cases. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Tested-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 536721b commit 299ee12

File tree

7 files changed

+112
-105
lines changed

7 files changed

+112
-105
lines changed

include/net/sctp/sctp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,8 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr)
554554
static inline void sctp_v4_map_v6(union sctp_addr *addr)
555555
{
556556
addr->v6.sin6_family = AF_INET6;
557+
addr->v6.sin6_flowinfo = 0;
558+
addr->v6.sin6_scope_id = 0;
557559
addr->v6.sin6_port = addr->v4.sin_port;
558560
addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
559561
addr->v6.sin6_addr.s6_addr32[0] = 0;

include/net/sctp/structs.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,6 @@ struct sctp_af {
465465
int saddr);
466466
void (*from_sk) (union sctp_addr *,
467467
struct sock *sk);
468-
void (*to_sk_saddr) (union sctp_addr *,
469-
struct sock *sk);
470-
void (*to_sk_daddr) (union sctp_addr *,
471-
struct sock *sk);
472468
void (*from_addr_param) (union sctp_addr *,
473469
union sctp_addr_param *,
474470
__be16 port, int iif);
@@ -509,7 +505,9 @@ struct sctp_pf {
509505
int (*supported_addrs)(const struct sctp_sock *, __be16 *);
510506
struct sock *(*create_accept_sk) (struct sock *sk,
511507
struct sctp_association *asoc);
512-
void (*addr_v4map) (struct sctp_sock *, union sctp_addr *);
508+
int (*addr_to_user)(struct sctp_sock *sk, union sctp_addr *addr);
509+
void (*to_sk_saddr)(union sctp_addr *, struct sock *sk);
510+
void (*to_sk_daddr)(union sctp_addr *, struct sock *sk);
513511
struct sctp_af *af;
514512
};
515513

net/sctp/ipv6.c

Lines changed: 82 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
434434
/* Initialize sk->sk_rcv_saddr from sctp_addr. */
435435
static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
436436
{
437-
if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
437+
if (addr->sa.sa_family == AF_INET) {
438438
sk->sk_v6_rcv_saddr.s6_addr32[0] = 0;
439439
sk->sk_v6_rcv_saddr.s6_addr32[1] = 0;
440440
sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
@@ -448,7 +448,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
448448
/* Initialize sk->sk_daddr from sctp_addr. */
449449
static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
450450
{
451-
if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
451+
if (addr->sa.sa_family == AF_INET) {
452452
sk->sk_v6_daddr.s6_addr32[0] = 0;
453453
sk->sk_v6_daddr.s6_addr32[1] = 0;
454454
sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
@@ -556,8 +556,6 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
556556
if (IPV6_ADDR_ANY == type)
557557
return 1;
558558
if (type == IPV6_ADDR_MAPPED) {
559-
if (sp && !sp->v4mapped)
560-
return 0;
561559
if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
562560
return 0;
563561
sctp_v6_map_v4(addr);
@@ -587,8 +585,6 @@ static int sctp_v6_addr_valid(union sctp_addr *addr,
587585
/* Note: This routine is used in input, so v4-mapped-v6
588586
* are disallowed here when there is no sctp_sock.
589587
*/
590-
if (!sp || !sp->v4mapped)
591-
return 0;
592588
if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
593589
return 0;
594590
sctp_v6_map_v4(addr);
@@ -675,11 +671,23 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
675671
return newsk;
676672
}
677673

678-
/* Map v4 address to mapped v6 address */
679-
static void sctp_v6_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr)
674+
/* Format a sockaddr for return to user space. This makes sure the return is
675+
* AF_INET or AF_INET6 depending on the SCTP_I_WANT_MAPPED_V4_ADDR option.
676+
*/
677+
static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
680678
{
681-
if (sp->v4mapped && AF_INET == addr->sa.sa_family)
682-
sctp_v4_map_v6(addr);
679+
if (sp->v4mapped) {
680+
if (addr->sa.sa_family == AF_INET)
681+
sctp_v4_map_v6(addr);
682+
} else {
683+
if (addr->sa.sa_family == AF_INET6 &&
684+
ipv6_addr_v4mapped(&addr->v6.sin6_addr))
685+
sctp_v6_map_v4(addr);
686+
}
687+
688+
if (addr->sa.sa_family == AF_INET)
689+
return sizeof(struct sockaddr_in);
690+
return sizeof(struct sockaddr_in6);
683691
}
684692

685693
/* Where did this skb come from? */
@@ -706,82 +714,68 @@ static void sctp_v6_ecn_capable(struct sock *sk)
706714
inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
707715
}
708716

709-
/* Initialize a PF_INET6 socket msg_name. */
710-
static void sctp_inet6_msgname(char *msgname, int *addr_len)
711-
{
712-
struct sockaddr_in6 *sin6;
713-
714-
sin6 = (struct sockaddr_in6 *)msgname;
715-
sin6->sin6_family = AF_INET6;
716-
sin6->sin6_flowinfo = 0;
717-
sin6->sin6_scope_id = 0; /*FIXME */
718-
*addr_len = sizeof(struct sockaddr_in6);
719-
}
720-
721717
/* Initialize a PF_INET msgname from a ulpevent. */
722718
static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
723719
char *msgname, int *addrlen)
724720
{
725-
struct sockaddr_in6 *sin6, *sin6from;
726-
727-
if (msgname) {
728-
union sctp_addr *addr;
729-
struct sctp_association *asoc;
730-
731-
asoc = event->asoc;
732-
sctp_inet6_msgname(msgname, addrlen);
733-
sin6 = (struct sockaddr_in6 *)msgname;
734-
sin6->sin6_port = htons(asoc->peer.port);
735-
addr = &asoc->peer.primary_addr;
721+
union sctp_addr *addr;
722+
struct sctp_association *asoc;
723+
union sctp_addr *paddr;
736724

737-
/* Note: If we go to a common v6 format, this code
738-
* will change.
739-
*/
725+
if (!msgname)
726+
return;
740727

741-
/* Map ipv4 address into v4-mapped-on-v6 address. */
742-
if (sctp_sk(asoc->base.sk)->v4mapped &&
743-
AF_INET == addr->sa.sa_family) {
744-
sctp_v4_map_v6((union sctp_addr *)sin6);
745-
sin6->sin6_addr.s6_addr32[3] =
746-
addr->v4.sin_addr.s_addr;
747-
return;
748-
}
728+
addr = (union sctp_addr *)msgname;
729+
asoc = event->asoc;
730+
paddr = &asoc->peer.primary_addr;
749731

750-
sin6from = &asoc->peer.primary_addr.v6;
751-
sin6->sin6_addr = sin6from->sin6_addr;
752-
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
753-
sin6->sin6_scope_id = sin6from->sin6_scope_id;
732+
if (paddr->sa.sa_family == AF_INET) {
733+
addr->v4.sin_family = AF_INET;
734+
addr->v4.sin_port = htons(asoc->peer.port);
735+
addr->v4.sin_addr = paddr->v4.sin_addr;
736+
} else {
737+
addr->v6.sin6_family = AF_INET6;
738+
addr->v6.sin6_flowinfo = 0;
739+
if (ipv6_addr_type(&paddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
740+
addr->v6.sin6_scope_id = paddr->v6.sin6_scope_id;
741+
else
742+
addr->v6.sin6_scope_id = 0;
743+
addr->v6.sin6_port = htons(asoc->peer.port);
744+
addr->v6.sin6_addr = paddr->v6.sin6_addr;
754745
}
746+
747+
*addrlen = sctp_v6_addr_to_user(sctp_sk(asoc->base.sk), addr);
755748
}
756749

757750
/* Initialize a msg_name from an inbound skb. */
758751
static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
759752
int *addr_len)
760753
{
754+
union sctp_addr *addr;
761755
struct sctphdr *sh;
762-
struct sockaddr_in6 *sin6;
763-
764-
if (msgname) {
765-
sctp_inet6_msgname(msgname, addr_len);
766-
sin6 = (struct sockaddr_in6 *)msgname;
767-
sh = sctp_hdr(skb);
768-
sin6->sin6_port = sh->source;
769-
770-
/* Map ipv4 address into v4-mapped-on-v6 address. */
771-
if (sctp_sk(skb->sk)->v4mapped &&
772-
ip_hdr(skb)->version == 4) {
773-
sctp_v4_map_v6((union sctp_addr *)sin6);
774-
sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr;
775-
return;
776-
}
777756

778-
/* Otherwise, just copy the v6 address. */
779-
sin6->sin6_addr = ipv6_hdr(skb)->saddr;
780-
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
757+
if (!msgname)
758+
return;
759+
760+
addr = (union sctp_addr *)msgname;
761+
sh = sctp_hdr(skb);
762+
763+
if (ip_hdr(skb)->version == 4) {
764+
addr->v4.sin_family = AF_INET;
765+
addr->v4.sin_port = sh->source;
766+
addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr;
767+
} else {
768+
addr->v6.sin6_family = AF_INET6;
769+
addr->v6.sin6_flowinfo = 0;
770+
addr->v6.sin6_port = sh->source;
771+
addr->v6.sin6_addr = ipv6_hdr(skb)->saddr;
772+
if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
781773
struct sctp_ulpevent *ev = sctp_skb2event(skb);
782-
sin6->sin6_scope_id = ev->iif;
774+
addr->v6.sin6_scope_id = ev->iif;
783775
}
784776
}
777+
778+
*addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr);
785779
}
786780

787781
/* Do we support this AF? */
@@ -857,9 +851,6 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
857851
return 0;
858852
}
859853
rcu_read_unlock();
860-
} else if (type == IPV6_ADDR_MAPPED) {
861-
if (!opt->v4mapped)
862-
return 0;
863854
}
864855

865856
af = opt->pf->af;
@@ -914,6 +905,23 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
914905
return 1;
915906
}
916907

908+
/* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */
909+
static int sctp_getname(struct socket *sock, struct sockaddr *uaddr,
910+
int *uaddr_len, int peer)
911+
{
912+
int rc;
913+
914+
rc = inet6_getname(sock, uaddr, uaddr_len, peer);
915+
916+
if (rc != 0)
917+
return rc;
918+
919+
*uaddr_len = sctp_v6_addr_to_user(sctp_sk(sock->sk),
920+
(union sctp_addr *)uaddr);
921+
922+
return rc;
923+
}
924+
917925
static const struct proto_ops inet6_seqpacket_ops = {
918926
.family = PF_INET6,
919927
.owner = THIS_MODULE,
@@ -922,7 +930,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
922930
.connect = inet_dgram_connect,
923931
.socketpair = sock_no_socketpair,
924932
.accept = inet_accept,
925-
.getname = inet6_getname,
933+
.getname = sctp_getname,
926934
.poll = sctp_poll,
927935
.ioctl = inet6_ioctl,
928936
.listen = sctp_inet_listen,
@@ -974,8 +982,6 @@ static struct sctp_af sctp_af_inet6 = {
974982
.copy_addrlist = sctp_v6_copy_addrlist,
975983
.from_skb = sctp_v6_from_skb,
976984
.from_sk = sctp_v6_from_sk,
977-
.to_sk_saddr = sctp_v6_to_sk_saddr,
978-
.to_sk_daddr = sctp_v6_to_sk_daddr,
979985
.from_addr_param = sctp_v6_from_addr_param,
980986
.to_addr_param = sctp_v6_to_addr_param,
981987
.cmp_addr = sctp_v6_cmp_addr,
@@ -1005,7 +1011,9 @@ static struct sctp_pf sctp_pf_inet6 = {
10051011
.send_verify = sctp_inet6_send_verify,
10061012
.supported_addrs = sctp_inet6_supported_addrs,
10071013
.create_accept_sk = sctp_v6_create_accept_sk,
1008-
.addr_v4map = sctp_v6_addr_v4map,
1014+
.addr_to_user = sctp_v6_addr_to_user,
1015+
.to_sk_saddr = sctp_v6_to_sk_saddr,
1016+
.to_sk_daddr = sctp_v6_to_sk_daddr,
10091017
.af = &sctp_af_inet6,
10101018
};
10111019

net/sctp/protocol.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -576,10 +576,10 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
576576
return newsk;
577577
}
578578

579-
/* Map address, empty for v4 family */
580-
static void sctp_v4_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr)
579+
static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
581580
{
582-
/* Empty */
581+
/* No address mapping for V4 sockets */
582+
return sizeof(struct sockaddr_in);
583583
}
584584

585585
/* Dump the v4 addr to the seq file. */
@@ -976,7 +976,9 @@ static struct sctp_pf sctp_pf_inet = {
976976
.send_verify = sctp_inet_send_verify,
977977
.supported_addrs = sctp_inet_supported_addrs,
978978
.create_accept_sk = sctp_v4_create_accept_sk,
979-
.addr_v4map = sctp_v4_addr_v4map,
979+
.addr_to_user = sctp_v4_addr_to_user,
980+
.to_sk_saddr = sctp_v4_to_sk_saddr,
981+
.to_sk_daddr = sctp_v4_to_sk_daddr,
980982
.af = &sctp_af_inet
981983
};
982984

@@ -1047,8 +1049,6 @@ static struct sctp_af sctp_af_inet = {
10471049
.copy_addrlist = sctp_v4_copy_addrlist,
10481050
.from_skb = sctp_v4_from_skb,
10491051
.from_sk = sctp_v4_from_sk,
1050-
.to_sk_saddr = sctp_v4_to_sk_saddr,
1051-
.to_sk_daddr = sctp_v4_to_sk_daddr,
10521052
.from_addr_param = sctp_v4_from_addr_param,
10531053
.to_addr_param = sctp_v4_to_addr_param,
10541054
.cmp_addr = sctp_v4_cmp_addr,

0 commit comments

Comments
 (0)