summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-10-06 17:24:26 -0400
committerJakub Kicinski <jakub.kicinski@netronome.com>2019-10-08 16:23:05 -0400
commitfc8d5db10cbe1338a52ebc74e7feab9276721774 (patch)
treee86c4bac21ea8bd46b6bcc73db671e8fcfed9681
parentb74555de21acd791f12c4a1aeaf653dd7ac21133 (diff)
llc: fix another potential sk_buff leak in llc_ui_sendmsg()
All callers of llc_conn_state_process() except llc_build_and_send_pkt() (via llc_ui_sendmsg() -> llc_ui_send_data()) assume that it always consumes a reference to the skb. Fix this caller to do the same. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
-rw-r--r--net/llc/af_llc.c34
-rw-r--r--net/llc/llc_conn.c2
-rw-r--r--net/llc/llc_if.c12
3 files changed, 30 insertions, 18 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 2017b7d780f5..c74f44dfaa22 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -113,22 +113,26 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
113 * 113 *
114 * Send data via reliable llc2 connection. 114 * Send data via reliable llc2 connection.
115 * Returns 0 upon success, non-zero if action did not succeed. 115 * Returns 0 upon success, non-zero if action did not succeed.
116 *
117 * This function always consumes a reference to the skb.
116 */ 118 */
117static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock) 119static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock)
118{ 120{
119 struct llc_sock* llc = llc_sk(sk); 121 struct llc_sock* llc = llc_sk(sk);
120 int rc = 0;
121 122
122 if (unlikely(llc_data_accept_state(llc->state) || 123 if (unlikely(llc_data_accept_state(llc->state) ||
123 llc->remote_busy_flag || 124 llc->remote_busy_flag ||
124 llc->p_flag)) { 125 llc->p_flag)) {
125 long timeout = sock_sndtimeo(sk, noblock); 126 long timeout = sock_sndtimeo(sk, noblock);
127 int rc;
126 128
127 rc = llc_ui_wait_for_busy_core(sk, timeout); 129 rc = llc_ui_wait_for_busy_core(sk, timeout);
130 if (rc) {
131 kfree_skb(skb);
132 return rc;
133 }
128 } 134 }
129 if (unlikely(!rc)) 135 return llc_build_and_send_pkt(sk, skb);
130 rc = llc_build_and_send_pkt(sk, skb);
131 return rc;
132} 136}
133 137
134static void llc_ui_sk_init(struct socket *sock, struct sock *sk) 138static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
@@ -899,7 +903,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
899 DECLARE_SOCKADDR(struct sockaddr_llc *, addr, msg->msg_name); 903 DECLARE_SOCKADDR(struct sockaddr_llc *, addr, msg->msg_name);
900 int flags = msg->msg_flags; 904 int flags = msg->msg_flags;
901 int noblock = flags & MSG_DONTWAIT; 905 int noblock = flags & MSG_DONTWAIT;
902 struct sk_buff *skb; 906 struct sk_buff *skb = NULL;
903 size_t size = 0; 907 size_t size = 0;
904 int rc = -EINVAL, copied = 0, hdrlen; 908 int rc = -EINVAL, copied = 0, hdrlen;
905 909
@@ -908,10 +912,10 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
908 lock_sock(sk); 912 lock_sock(sk);
909 if (addr) { 913 if (addr) {
910 if (msg->msg_namelen < sizeof(*addr)) 914 if (msg->msg_namelen < sizeof(*addr))
911 goto release; 915 goto out;
912 } else { 916 } else {
913 if (llc_ui_addr_null(&llc->addr)) 917 if (llc_ui_addr_null(&llc->addr))
914 goto release; 918 goto out;
915 addr = &llc->addr; 919 addr = &llc->addr;
916 } 920 }
917 /* must bind connection to sap if user hasn't done it. */ 921 /* must bind connection to sap if user hasn't done it. */
@@ -919,7 +923,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
919 /* bind to sap with null dev, exclusive. */ 923 /* bind to sap with null dev, exclusive. */
920 rc = llc_ui_autobind(sock, addr); 924 rc = llc_ui_autobind(sock, addr);
921 if (rc) 925 if (rc)
922 goto release; 926 goto out;
923 } 927 }
924 hdrlen = llc->dev->hard_header_len + llc_ui_header_len(sk, addr); 928 hdrlen = llc->dev->hard_header_len + llc_ui_header_len(sk, addr);
925 size = hdrlen + len; 929 size = hdrlen + len;
@@ -928,12 +932,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
928 copied = size - hdrlen; 932 copied = size - hdrlen;
929 rc = -EINVAL; 933 rc = -EINVAL;
930 if (copied < 0) 934 if (copied < 0)
931 goto release; 935 goto out;
932 release_sock(sk); 936 release_sock(sk);
933 skb = sock_alloc_send_skb(sk, size, noblock, &rc); 937 skb = sock_alloc_send_skb(sk, size, noblock, &rc);
934 lock_sock(sk); 938 lock_sock(sk);
935 if (!skb) 939 if (!skb)
936 goto release; 940 goto out;
937 skb->dev = llc->dev; 941 skb->dev = llc->dev;
938 skb->protocol = llc_proto_type(addr->sllc_arphrd); 942 skb->protocol = llc_proto_type(addr->sllc_arphrd);
939 skb_reserve(skb, hdrlen); 943 skb_reserve(skb, hdrlen);
@@ -943,29 +947,31 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
943 if (sk->sk_type == SOCK_DGRAM || addr->sllc_ua) { 947 if (sk->sk_type == SOCK_DGRAM || addr->sllc_ua) {
944 llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_mac, 948 llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_mac,
945 addr->sllc_sap); 949 addr->sllc_sap);
950 skb = NULL;
946 goto out; 951 goto out;
947 } 952 }
948 if (addr->sllc_test) { 953 if (addr->sllc_test) {
949 llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_mac, 954 llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_mac,
950 addr->sllc_sap); 955 addr->sllc_sap);
956 skb = NULL;
951 goto out; 957 goto out;
952 } 958 }
953 if (addr->sllc_xid) { 959 if (addr->sllc_xid) {
954 llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_mac, 960 llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_mac,
955 addr->sllc_sap); 961 addr->sllc_sap);
962 skb = NULL;
956 goto out; 963 goto out;
957 } 964 }
958 rc = -ENOPROTOOPT; 965 rc = -ENOPROTOOPT;
959 if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua)) 966 if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua))
960 goto out; 967 goto out;
961 rc = llc_ui_send_data(sk, skb, noblock); 968 rc = llc_ui_send_data(sk, skb, noblock);
969 skb = NULL;
962out: 970out:
963 if (rc) { 971 kfree_skb(skb);
964 kfree_skb(skb); 972 if (rc)
965release:
966 dprintk("%s: failed sending from %02X to %02X: %d\n", 973 dprintk("%s: failed sending from %02X to %02X: %d\n",
967 __func__, llc->laddr.lsap, llc->daddr.lsap, rc); 974 __func__, llc->laddr.lsap, llc->daddr.lsap, rc);
968 }
969 release_sock(sk); 975 release_sock(sk);
970 return rc ? : copied; 976 return rc ? : copied;
971} 977}
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index ed2aca12460c..0b0c6f12153b 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -55,6 +55,8 @@ int sysctl_llc2_busy_timeout = LLC2_BUSY_TIME * HZ;
55 * (executing it's actions and changing state), upper layer will be 55 * (executing it's actions and changing state), upper layer will be
56 * indicated or confirmed, if needed. Returns 0 for success, 1 for 56 * indicated or confirmed, if needed. Returns 0 for success, 1 for
57 * failure. The socket lock has to be held before calling this function. 57 * failure. The socket lock has to be held before calling this function.
58 *
59 * This function always consumes a reference to the skb.
58 */ 60 */
59int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) 61int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
60{ 62{
diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c
index 8db03c2d5440..ad6547736c21 100644
--- a/net/llc/llc_if.c
+++ b/net/llc/llc_if.c
@@ -38,6 +38,8 @@
38 * closed and -EBUSY when sending data is not permitted in this state or 38 * closed and -EBUSY when sending data is not permitted in this state or
39 * LLC has send an I pdu with p bit set to 1 and is waiting for it's 39 * LLC has send an I pdu with p bit set to 1 and is waiting for it's
40 * response. 40 * response.
41 *
42 * This function always consumes a reference to the skb.
41 */ 43 */
42int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) 44int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
43{ 45{
@@ -46,20 +48,22 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
46 struct llc_sock *llc = llc_sk(sk); 48 struct llc_sock *llc = llc_sk(sk);
47 49
48 if (unlikely(llc->state == LLC_CONN_STATE_ADM)) 50 if (unlikely(llc->state == LLC_CONN_STATE_ADM))
49 goto out; 51 goto out_free;
50 rc = -EBUSY; 52 rc = -EBUSY;
51 if (unlikely(llc_data_accept_state(llc->state) || /* data_conn_refuse */ 53 if (unlikely(llc_data_accept_state(llc->state) || /* data_conn_refuse */
52 llc->p_flag)) { 54 llc->p_flag)) {
53 llc->failed_data_req = 1; 55 llc->failed_data_req = 1;
54 goto out; 56 goto out_free;
55 } 57 }
56 ev = llc_conn_ev(skb); 58 ev = llc_conn_ev(skb);
57 ev->type = LLC_CONN_EV_TYPE_PRIM; 59 ev->type = LLC_CONN_EV_TYPE_PRIM;
58 ev->prim = LLC_DATA_PRIM; 60 ev->prim = LLC_DATA_PRIM;
59 ev->prim_type = LLC_PRIM_TYPE_REQ; 61 ev->prim_type = LLC_PRIM_TYPE_REQ;
60 skb->dev = llc->dev; 62 skb->dev = llc->dev;
61 rc = llc_conn_state_process(sk, skb); 63 return llc_conn_state_process(sk, skb);
62out: 64
65out_free:
66 kfree_skb(skb);
63 return rc; 67 return rc;
64} 68}
65 69