diff options
author | Kevin Hilman <khilman@linaro.org> | 2015-08-04 10:11:52 -0700 |
---|---|---|
committer | Kevin Hilman <khilman@linaro.org> | 2015-08-04 10:11:52 -0700 |
commit | 69483e398f196d87ca3289f31ad3291bad94af60 (patch) | |
tree | 547d41fb7d28499738a4307790e9c45d1e082c68 /net/sctp/socket.c | |
parent | a32844ca3a02130d9c0166b65f54696dfaafc922 (diff) | |
parent | 863394fce1f2be8589396cd0684e6693ec89f295 (diff) |
Merge branch 'linux-linaro-lsk-v3.14' of https://git.linaro.org/people/shannon.zhao/linux-stable into linux-linaro-lsk-v3.14
Merge from Shannon Zhao: resolves conflicts between LTS v3.14.48 KVM and LSK KVM
* 'linux-linaro-lsk-v3.14' of https://git.linaro.org/people/shannon.zhao/linux-stable: (31 commits)
Linux 3.14.48
x86/iosf: Add Kconfig prompt for IOSF_MBI selection
arm/arm64: KVM: Keep elrsr/aisr in sync with software model
arm64: KVM: Do not use pgd_index to index stage-2 pgd
arm64: KVM: Fix HCR setting for 32bit guests
arm64: KVM: Fix TLB invalidation by IPA/VMID
arm/arm64: KVM: Require in-kernel vgic for the arch timers
vfs: Ignore unlocked mounts in fs_fully_visible
vfs: Remove incorrect debugging WARN in prepend_path
fs: Fix S_NOSEC handling
KVM: x86: make vapics_in_nmi_mode atomic
MIPS: Fix KVM guest fixmap address
x86/PCI: Use host bridge _CRS info on Foxconn K8M890-8237A
x86/PCI: Use host bridge _CRS info on systems with >32 bit addressing
powerpc/perf: Fix book3s kernel to userspace backtraces
arm: KVM: force execution of HCPTR access on VM exit
intel_pstate: set BYT MSR with wrmsrl_on_cpu()
iommu/amd: Handle large pages correctly in free_pagetable
Revert "crypto: talitos - convert to use be16_add_cpu()"
crypto: talitos - avoid memleak in talitos_alg_alloc()
...
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 604a6acdf92e..f940fdc540f5 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1532,8 +1532,10 @@ static void sctp_close(struct sock *sk, long timeout) /* Supposedly, no process has access to the socket, but * the net layers still may. + * Also, sctp_destroy_sock() needs to be called with addr_wq_lock + * held and that should be grabbed before socket lock. */ - local_bh_disable(); + spin_lock_bh(&net->sctp.addr_wq_lock); bh_lock_sock(sk); /* Hold the sock, since sk_common_release() will put sock_put() @@ -1543,7 +1545,7 @@ static void sctp_close(struct sock *sk, long timeout) sk_common_release(sk); bh_unlock_sock(sk); - local_bh_enable(); + spin_unlock_bh(&net->sctp.addr_wq_lock); sock_put(sk); @@ -3511,6 +3513,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) return 0; + spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); if (val == 0 && sp->do_auto_asconf) { list_del(&sp->auto_asconf_list); sp->do_auto_asconf = 0; @@ -3519,6 +3522,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, &sock_net(sk)->sctp.auto_asconf_splist); sp->do_auto_asconf = 1; } + spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); return 0; } @@ -4009,18 +4013,28 @@ static int sctp_init_sock(struct sock *sk) local_bh_disable(); percpu_counter_inc(&sctp_sockets_allocated); sock_prot_inuse_add(net, sk->sk_prot, 1); + + /* Nothing can fail after this block, otherwise + * sctp_destroy_sock() will be called without addr_wq_lock held + */ if (net->sctp.default_auto_asconf) { + spin_lock(&sock_net(sk)->sctp.addr_wq_lock); list_add_tail(&sp->auto_asconf_list, &net->sctp.auto_asconf_splist); sp->do_auto_asconf = 1; - } else + spin_unlock(&sock_net(sk)->sctp.addr_wq_lock); + } else { sp->do_auto_asconf = 0; + } + local_bh_enable(); return 0; } -/* Cleanup any SCTP per socket resources. */ +/* Cleanup any SCTP per socket resources. Must be called with + * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true + */ static void sctp_destroy_sock(struct sock *sk) { struct sctp_sock *sp; @@ -6973,6 +6987,19 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, newinet->mc_list = NULL; } +static inline void sctp_copy_descendant(struct sock *sk_to, + const struct sock *sk_from) +{ + int ancestor_size = sizeof(struct inet_sock) + + sizeof(struct sctp_sock) - + offsetof(struct sctp_sock, auto_asconf_list); + + if (sk_from->sk_family == PF_INET6) + ancestor_size += sizeof(struct ipv6_pinfo); + + __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); +} + /* Populate the fields of the newsk from the oldsk and migrate the assoc * and its messages to the newsk. */ @@ -6987,7 +7014,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, struct sk_buff *skb, *tmp; struct sctp_ulpevent *event; struct sctp_bind_hashbucket *head; - struct list_head tmplist; /* Migrate socket buffer sizes and all the socket level options to the * new socket. @@ -6995,12 +7021,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsk->sk_sndbuf = oldsk->sk_sndbuf; newsk->sk_rcvbuf = oldsk->sk_rcvbuf; /* Brute force copy old sctp opt. */ - if (oldsp->do_auto_asconf) { - memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist)); - inet_sk_copy_descendant(newsk, oldsk); - memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist)); - } else - inet_sk_copy_descendant(newsk, oldsk); + sctp_copy_descendant(newsk, oldsk); /* Restore the ep value that was overwritten with the above structure * copy. |