From patchwork Tue Aug 23 01:03:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Ahern X-Patchwork-Id: 661675 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3sJBzg1P72z9s9c for ; Tue, 23 Aug 2016 11:04:31 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=cumulusnetworks.com header.i=@cumulusnetworks.com header.b=TsFM+vJ1; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756319AbcHWBEZ (ORCPT ); Mon, 22 Aug 2016 21:04:25 -0400 Received: from mail-pa0-f47.google.com ([209.85.220.47]:33729 "EHLO mail-pa0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755182AbcHWBEX (ORCPT ); Mon, 22 Aug 2016 21:04:23 -0400 Received: by mail-pa0-f47.google.com with SMTP id ti13so42503283pac.0 for ; Mon, 22 Aug 2016 18:03:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cumulusnetworks.com; s=google; h=from:to:cc:subject:date:message-id; bh=WrVvZ6ftRtkOZhsmcEzARtZHuQaKML/WipQX45Pfeno=; b=TsFM+vJ1B0TBtI0OuR4jStqApeShtEGesCJOBzZ0IU0ih33vKCJFVL9omtpmMKm+rL psV4MdAgZdUIBUUeYXorddJkthOAwpjYBQIF1Th1SK5WubBh98AcWWwh4Yoqp8zE+nOh EGJOdb6sM4whTRF+arwjHpoVUIy1EqjsgZZiY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=WrVvZ6ftRtkOZhsmcEzARtZHuQaKML/WipQX45Pfeno=; b=iX1bSo2vEdnDjNLzlxKYRY8+P6Juj8NsNaLG8hKKHusaNLK75qX+sSTYkL0QMRrldX c5aDGwEA+KiJwoQZZ6+aqC4CsDAcMStRbvMiPS4wnK7dNjS6/CvZiBmx+FlQExugPIKV 7LGeUwLiNdWch87cerr4UZlrzxty6FeWVGlLn9YsfErFHxK7/3uq5SoqGrV15Pa9vGcp 7hvEN8q/iZzPrJ9B6fN7amKZ8QH10CJfm6j5mgOVHTicSEIcJ1MnixVmn/G/XGVH8PgI 2zDjmTG+CZx/dSJax41uBEpTOQC987dmDJwgyOw4Nn26xtqNjCrrv64/47iR7IoxupOR XBxQ== X-Gm-Message-State: AEkoouswHRd6A/k5XNT074RaLCNGHWYjLnNMEaWMttoTynK0SnY7faEBgMHicL6f0SIsptPS X-Received: by 10.66.160.165 with SMTP id xl5mr47482338pab.63.1471914228054; Mon, 22 Aug 2016 18:03:48 -0700 (PDT) Received: from kenny.cumulusnetworks.com. ([216.129.126.126]) by smtp.googlemail.com with ESMTPSA id q14sm496724pfi.76.2016.08.22.18.03.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 22 Aug 2016 18:03:47 -0700 (PDT) From: David Ahern To: netdev@vger.kernel.org Cc: David Ahern Subject: [PATCH v2 net-next] net: diag: support SOCK_DESTROY for UDP sockets Date: Mon, 22 Aug 2016 18:03:41 -0700 Message-Id: <1471914221-24213-1-git-send-email-dsa@cumulusnetworks.com> X-Mailer: git-send-email 2.1.4 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This implements SOCK_DESTROY for UDP sockets similar to what was done for TCP with commit c1e64e298b8ca ("net: diag: Support destroying TCP sockets.") A process with a UDP socket targeted for destroy is awakened and recvmsg fails with ECONNABORTED. Signed-off-by: David Ahern --- v2 - changed socket lookup to __udp{4,6}_lib_lookup include/net/udp.h | 1 + net/ipv4/udp.c | 17 +++++++++++++++++ net/ipv4/udp_diag.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/udp.c | 1 + 4 files changed, 74 insertions(+) diff --git a/include/net/udp.h b/include/net/udp.h index 8894d7144189..ea53a87d880f 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -251,6 +251,7 @@ int udp_get_port(struct sock *sk, unsigned short snum, int (*saddr_cmp)(const struct sock *, const struct sock *)); void udp_err(struct sk_buff *, u32); +int udp_abort(struct sock *sk, int err); int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); int udp_push_pending_frames(struct sock *sk); void udp_flush_pending_frames(struct sock *sk); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e61f7cd65d08..d082800557da 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2192,6 +2192,22 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) } EXPORT_SYMBOL(udp_poll); +int udp_abort(struct sock *sk, int err) +{ + lock_sock(sk); + + sk->sk_err = err; + sk->sk_error_report(sk); + udp_disconnect(sk, 0); + + release_sock(sk); + + sock_put(sk); + + return 0; +} +EXPORT_SYMBOL_GPL(udp_abort); + struct proto udp_prot = { .name = "UDP", .owner = THIS_MODULE, @@ -2223,6 +2239,7 @@ struct proto udp_prot = { .compat_getsockopt = compat_udp_getsockopt, #endif .clear_sk = sk_prot_clear_portaddr_nulls, + .diag_destroy = udp_abort, }; EXPORT_SYMBOL(udp_prot); diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 3d5ccf4b1412..904c5a9d2680 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -165,12 +165,64 @@ static void udp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, r->idiag_wqueue = sk_wmem_alloc_get(sk); } +#ifdef CONFIG_INET_DIAG_DESTROY +static int __udp_diag_destroy(struct sk_buff *in_skb, + const struct inet_diag_req_v2 *req, + struct udp_table *tbl) +{ + struct net *net = sock_net(in_skb->sk); + struct sock *sk; + + rcu_read_lock(); + + if (req->sdiag_family == AF_INET) + sk = __udp4_lib_lookup(net, + req->id.idiag_dst[0], req->id.idiag_dport, + req->id.idiag_src[0], req->id.idiag_sport, + req->id.idiag_if, tbl, NULL); +#if IS_ENABLED(CONFIG_IPV6) + else if (req->sdiag_family == AF_INET6) + sk = __udp6_lib_lookup(net, + (struct in6_addr *)req->id.idiag_dst, + req->id.idiag_dport, + (struct in6_addr *)req->id.idiag_src, + req->id.idiag_sport, + req->id.idiag_if, tbl, NULL); +#endif + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) + sk = NULL; + + rcu_read_unlock(); + + if (!sk) + return -ENOENT; + + return sock_diag_destroy(sk, ECONNABORTED); +} + +static int udp_diag_destroy(struct sk_buff *in_skb, + const struct inet_diag_req_v2 *req) +{ + return __udp_diag_destroy(in_skb, req, &udp_table); +} + +static int udplite_diag_destroy(struct sk_buff *in_skb, + const struct inet_diag_req_v2 *req) +{ + return __udp_diag_destroy(in_skb, req, &udplite_table); +} + +#endif + static const struct inet_diag_handler udp_diag_handler = { .dump = udp_diag_dump, .dump_one = udp_diag_dump_one, .idiag_get_info = udp_diag_get_info, .idiag_type = IPPROTO_UDP, .idiag_info_size = 0, +#ifdef CONFIG_INET_DIAG_DESTROY + .destroy = udp_diag_destroy, +#endif }; static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, @@ -192,6 +244,9 @@ static const struct inet_diag_handler udplite_diag_handler = { .idiag_get_info = udp_diag_get_info, .idiag_type = IPPROTO_UDPLITE, .idiag_info_size = 0, +#ifdef CONFIG_INET_DIAG_DESTROY + .destroy = udplite_diag_destroy, +#endif }; static int __init udp_diag_init(void) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 81e2f98b958d..16512cf06e73 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1467,6 +1467,7 @@ struct proto udpv6_prot = { .compat_getsockopt = compat_udpv6_getsockopt, #endif .clear_sk = udp_v6_clear_sk, + .diag_destroy = udp_abort, }; static struct inet_protosw udpv6_protosw = {