summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-10-06 17:24:27 -0400
committerJakub Kicinski <jakub.kicinski@netronome.com>2019-10-08 16:23:05 -0400
commit36453c852816f19947ca482a595dffdd2efa4965 (patch)
treef0204d988d31cc5bc60a8e66c208a971dc48917a
parentfc8d5db10cbe1338a52ebc74e7feab9276721774 (diff)
llc: fix sk_buff refcounting in llc_conn_state_process()
If llc_conn_state_process() sees that llc_conn_service() put the skb on a list, it will drop one fewer references to it. This is wrong because the current behavior is that llc_conn_service() never consumes a reference to the skb. The code also makes the number of skb references being dropped conditional on which of ind_prim and cfm_prim are nonzero, yet neither of these affects how many references are *acquired*. So there is extra code that tries to fix this up by sometimes taking another reference. Remove the unnecessary/broken refcounting logic and instead just add an skb_get() before the only two places where an extra reference is actually consumed. 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/llc_conn.c33
1 files changed, 6 insertions, 27 deletions
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 0b0c6f12153b..a79b739eb223 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -64,12 +64,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
64 struct llc_sock *llc = llc_sk(skb->sk); 64 struct llc_sock *llc = llc_sk(skb->sk);
65 struct llc_conn_state_ev *ev = llc_conn_ev(skb); 65 struct llc_conn_state_ev *ev = llc_conn_ev(skb);
66 66
67 /*
68 * We have to hold the skb, because llc_conn_service will kfree it in
69 * the sending path and we need to look at the skb->cb, where we encode
70 * llc_conn_state_ev.
71 */
72 skb_get(skb);
73 ev->ind_prim = ev->cfm_prim = 0; 67 ev->ind_prim = ev->cfm_prim = 0;
74 /* 68 /*
75 * Send event to state machine 69 * Send event to state machine
@@ -77,21 +71,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
77 rc = llc_conn_service(skb->sk, skb); 71 rc = llc_conn_service(skb->sk, skb);
78 if (unlikely(rc != 0)) { 72 if (unlikely(rc != 0)) {
79 printk(KERN_ERR "%s: llc_conn_service failed\n", __func__); 73 printk(KERN_ERR "%s: llc_conn_service failed\n", __func__);
80 goto out_kfree_skb;
81 }
82
83 if (unlikely(!ev->ind_prim && !ev->cfm_prim)) {
84 /* indicate or confirm not required */
85 if (!skb->next)
86 goto out_kfree_skb;
87 goto out_skb_put; 74 goto out_skb_put;
88 } 75 }
89 76
90 if (unlikely(ev->ind_prim && ev->cfm_prim)) /* Paranoia */
91 skb_get(skb);
92
93 switch (ev->ind_prim) { 77 switch (ev->ind_prim) {
94 case LLC_DATA_PRIM: 78 case LLC_DATA_PRIM:
79 skb_get(skb);
95 llc_save_primitive(sk, skb, LLC_DATA_PRIM); 80 llc_save_primitive(sk, skb, LLC_DATA_PRIM);
96 if (unlikely(sock_queue_rcv_skb(sk, skb))) { 81 if (unlikely(sock_queue_rcv_skb(sk, skb))) {
97 /* 82 /*
@@ -108,6 +93,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
108 * skb->sk pointing to the newly created struct sock in 93 * skb->sk pointing to the newly created struct sock in
109 * llc_conn_handler. -acme 94 * llc_conn_handler. -acme
110 */ 95 */
96 skb_get(skb);
111 skb_queue_tail(&sk->sk_receive_queue, skb); 97 skb_queue_tail(&sk->sk_receive_queue, skb);
112 sk->sk_state_change(sk); 98 sk->sk_state_change(sk);
113 break; 99 break;
@@ -123,7 +109,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
123 sk->sk_state_change(sk); 109 sk->sk_state_change(sk);
124 } 110 }
125 } 111 }
126 kfree_skb(skb);
127 sock_put(sk); 112 sock_put(sk);
128 break; 113 break;
129 case LLC_RESET_PRIM: 114 case LLC_RESET_PRIM:
@@ -132,14 +117,11 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
132 * RESET is not being notified to upper layers for now 117 * RESET is not being notified to upper layers for now
133 */ 118 */
134 printk(KERN_INFO "%s: received a reset ind!\n", __func__); 119 printk(KERN_INFO "%s: received a reset ind!\n", __func__);
135 kfree_skb(skb);
136 break; 120 break;
137 default: 121 default:
138 if (ev->ind_prim) { 122 if (ev->ind_prim)
139 printk(KERN_INFO "%s: received unknown %d prim!\n", 123 printk(KERN_INFO "%s: received unknown %d prim!\n",
140 __func__, ev->ind_prim); 124 __func__, ev->ind_prim);
141 kfree_skb(skb);
142 }
143 /* No indication */ 125 /* No indication */
144 break; 126 break;
145 } 127 }
@@ -181,15 +163,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
181 printk(KERN_INFO "%s: received a reset conf!\n", __func__); 163 printk(KERN_INFO "%s: received a reset conf!\n", __func__);
182 break; 164 break;
183 default: 165 default:
184 if (ev->cfm_prim) { 166 if (ev->cfm_prim)
185 printk(KERN_INFO "%s: received unknown %d prim!\n", 167 printk(KERN_INFO "%s: received unknown %d prim!\n",
186 __func__, ev->cfm_prim); 168 __func__, ev->cfm_prim);
187 break; 169 /* No confirmation */
188 } 170 break;
189 goto out_skb_put; /* No confirmation */
190 } 171 }
191out_kfree_skb:
192 kfree_skb(skb);
193out_skb_put: 172out_skb_put:
194 kfree_skb(skb); 173 kfree_skb(skb);
195 return rc; 174 return rc;