summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Sarmadi <sona.sarmadi@enea.com>2017-04-19 08:06:18 +0200
committerAdrian Dudau <adrian.dudau@enea.com>2017-04-19 11:35:23 +0200
commit4c7fbbf1721c7e4fcf39e2d0f96f385c1ce1a5cf (patch)
tree4515b7005d5625e8c95351ba814a242b34bd4278
parent5b9e3eb40ae58e2e489961686b4b317e83f37577 (diff)
downloadmeta-enea-bsp-arm-4c7fbbf1721c7e4fcf39e2d0f96f385c1ce1a5cf.tar.gz
kernel: tty: CVE-2017-2636
tty: n_hdlc: get rid of racy n_hdlc.tbuf Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-2636 Reference to upstream patch: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/patch/?id=63075fbddd5151d2e98fa7cf0608a2113e23607d Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> Signed-off-by: Adrian Dudau <adrian.dudau@enea.com>
-rw-r--r--recipes-kernel/linux/linux-ls1/0002-CVE-2017-2636.patch318
-rw-r--r--recipes-kernel/linux/linux-ls1_3.12.bbappend1
2 files changed, 319 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ls1/0002-CVE-2017-2636.patch b/recipes-kernel/linux/linux-ls1/0002-CVE-2017-2636.patch
new file mode 100644
index 0000000..650d562
--- /dev/null
+++ b/recipes-kernel/linux/linux-ls1/0002-CVE-2017-2636.patch
@@ -0,0 +1,318 @@
1From 7f4446b11a368faf240947e8bab22ba857d6f31c Mon Sep 17 00:00:00 2001
2From: Alexander Popov <alex.popov@linux.com>
3Date: Tue, 28 Feb 2017 19:54:40 +0300
4Subject: [PATCH 2/2] tty: n_hdlc: get rid of racy n_hdlc.tbuf
5
6commit 82f2341c94d270421f383641b7cd670e474db56b upstream.
7
8Currently N_HDLC line discipline uses a self-made singly linked list for
9data buffers and has n_hdlc.tbuf pointer for buffer retransmitting after
10an error.
11
12The commit be10eb7589337e5defbe214dae038a53dd21add8
13("tty: n_hdlc add buffer flushing") introduced racy access to n_hdlc.tbuf.
14After tx error concurrent flush_tx_queue() and n_hdlc_send_frames() can put
15one data buffer to tx_free_buf_list twice. That causes double free in
16n_hdlc_release().
17
18Let's use standard kernel linked list and get rid of n_hdlc.tbuf:
19in case of tx error put current data buffer after the head of tx_buf_list.
20
21CVE: CVE-2017-2636
22Upstream-Status: Backport
23
24Signed-off-by: Alexander Popov <alex.popov@linux.com>
25Signed-off-by: Jiri Slaby <jslaby@suse.cz>
26Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
27---
28 drivers/tty/n_hdlc.c | 132 +++++++++++++++++++++++++++------------------------
29 1 file changed, 69 insertions(+), 63 deletions(-)
30
31diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
32index f26657c..66fb076 100644
33--- a/drivers/tty/n_hdlc.c
34+++ b/drivers/tty/n_hdlc.c
35@@ -114,7 +114,7 @@
36 #define DEFAULT_TX_BUF_COUNT 3
37
38 struct n_hdlc_buf {
39- struct n_hdlc_buf *link;
40+ struct list_head list_item;
41 int count;
42 char buf[1];
43 };
44@@ -122,8 +122,7 @@ struct n_hdlc_buf {
45 #define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
46
47 struct n_hdlc_buf_list {
48- struct n_hdlc_buf *head;
49- struct n_hdlc_buf *tail;
50+ struct list_head list;
51 int count;
52 spinlock_t spinlock;
53 };
54@@ -136,7 +135,6 @@ struct n_hdlc_buf_list {
55 * @backup_tty - TTY to use if tty gets closed
56 * @tbusy - reentrancy flag for tx wakeup code
57 * @woke_up - FIXME: describe this field
58- * @tbuf - currently transmitting tx buffer
59 * @tx_buf_list - list of pending transmit frame buffers
60 * @rx_buf_list - list of received frame buffers
61 * @tx_free_buf_list - list unused transmit frame buffers
62@@ -149,7 +147,6 @@ struct n_hdlc {
63 struct tty_struct *backup_tty;
64 int tbusy;
65 int woke_up;
66- struct n_hdlc_buf *tbuf;
67 struct n_hdlc_buf_list tx_buf_list;
68 struct n_hdlc_buf_list rx_buf_list;
69 struct n_hdlc_buf_list tx_free_buf_list;
70@@ -159,6 +156,8 @@ struct n_hdlc {
71 /*
72 * HDLC buffer list manipulation functions
73 */
74+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
75+ struct n_hdlc_buf *buf);
76 static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
77 struct n_hdlc_buf *buf);
78 static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
79@@ -208,16 +207,9 @@ static void flush_tx_queue(struct tty_struct *tty)
80 {
81 struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
82 struct n_hdlc_buf *buf;
83- unsigned long flags;
84
85 while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
86 n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
87- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
88- if (n_hdlc->tbuf) {
89- n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
90- n_hdlc->tbuf = NULL;
91- }
92- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
93 }
94
95 static struct tty_ldisc_ops n_hdlc_ldisc = {
96@@ -283,7 +275,6 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc)
97 } else
98 break;
99 }
100- kfree(n_hdlc->tbuf);
101 kfree(n_hdlc);
102
103 } /* end of n_hdlc_release() */
104@@ -402,13 +393,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
105 n_hdlc->woke_up = 0;
106 spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
107
108- /* get current transmit buffer or get new transmit */
109- /* buffer from list of pending transmit buffers */
110-
111- tbuf = n_hdlc->tbuf;
112- if (!tbuf)
113- tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
114-
115+ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
116 while (tbuf) {
117 if (debuglevel >= DEBUG_LEVEL_INFO)
118 printk("%s(%d)sending frame %p, count=%d\n",
119@@ -420,7 +405,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
120
121 /* rollback was possible and has been done */
122 if (actual == -ERESTARTSYS) {
123- n_hdlc->tbuf = tbuf;
124+ n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
125 break;
126 }
127 /* if transmit error, throw frame away by */
128@@ -435,10 +420,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
129
130 /* free current transmit buffer */
131 n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
132-
133- /* this tx buffer is done */
134- n_hdlc->tbuf = NULL;
135-
136+
137 /* wait up sleeping writers */
138 wake_up_interruptible(&tty->write_wait);
139
140@@ -448,10 +430,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
141 if (debuglevel >= DEBUG_LEVEL_INFO)
142 printk("%s(%d)frame %p pending\n",
143 __FILE__,__LINE__,tbuf);
144-
145- /* buffer not accepted by driver */
146- /* set this buffer as pending buffer */
147- n_hdlc->tbuf = tbuf;
148+
149+ /*
150+ * the buffer was not accepted by driver,
151+ * return it back into tx queue
152+ */
153+ n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
154 break;
155 }
156 }
157@@ -749,7 +733,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
158 int error = 0;
159 int count;
160 unsigned long flags;
161-
162+ struct n_hdlc_buf *buf = NULL;
163+
164 if (debuglevel >= DEBUG_LEVEL_INFO)
165 printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
166 __FILE__,__LINE__,cmd);
167@@ -763,8 +748,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
168 /* report count of read data available */
169 /* in next available frame (if any) */
170 spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
171- if (n_hdlc->rx_buf_list.head)
172- count = n_hdlc->rx_buf_list.head->count;
173+ buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
174+ struct n_hdlc_buf, list_item);
175+ if (buf)
176+ count = buf->count;
177 else
178 count = 0;
179 spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
180@@ -776,8 +763,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
181 count = tty_chars_in_buffer(tty);
182 /* add size of next output frame in queue */
183 spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
184- if (n_hdlc->tx_buf_list.head)
185- count += n_hdlc->tx_buf_list.head->count;
186+ buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
187+ struct n_hdlc_buf, list_item);
188+ if (buf)
189+ count += buf->count;
190 spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
191 error = put_user(count, (int __user *)arg);
192 break;
193@@ -825,14 +814,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
194 poll_wait(filp, &tty->write_wait, wait);
195
196 /* set bits for operations that won't block */
197- if (n_hdlc->rx_buf_list.head)
198+ if (!list_empty(&n_hdlc->rx_buf_list.list))
199 mask |= POLLIN | POLLRDNORM; /* readable */
200 if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
201 mask |= POLLHUP;
202 if (tty_hung_up_p(filp))
203 mask |= POLLHUP;
204 if (!tty_is_writelocked(tty) &&
205- n_hdlc->tx_free_buf_list.head)
206+ !list_empty(&n_hdlc->tx_free_buf_list.list))
207 mask |= POLLOUT | POLLWRNORM; /* writable */
208 }
209 return mask;
210@@ -858,7 +847,12 @@ static struct n_hdlc *n_hdlc_alloc(void)
211 spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
212 spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
213 spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
214-
215+
216+ INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
217+ INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
218+ INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
219+ INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
220+
221 /* allocate free rx buffer list */
222 for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
223 buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
224@@ -886,53 +880,65 @@ static struct n_hdlc *n_hdlc_alloc(void)
225 } /* end of n_hdlc_alloc() */
226
227 /**
228+ * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
229+ * @buf_list - pointer to the buffer list
230+ * @buf - pointer to the buffer
231+ */
232+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
233+ struct n_hdlc_buf *buf)
234+{
235+ unsigned long flags;
236+
237+ spin_lock_irqsave(&buf_list->spinlock, flags);
238+
239+ list_add(&buf->list_item, &buf_list->list);
240+ buf_list->count++;
241+
242+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
243+}
244+
245+/**
246 * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
247- * @list - pointer to buffer list
248+ * @buf_list - pointer to buffer list
249 * @buf - pointer to buffer
250 */
251-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
252+static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
253 struct n_hdlc_buf *buf)
254 {
255 unsigned long flags;
256- spin_lock_irqsave(&list->spinlock,flags);
257-
258- buf->link=NULL;
259- if (list->tail)
260- list->tail->link = buf;
261- else
262- list->head = buf;
263- list->tail = buf;
264- (list->count)++;
265-
266- spin_unlock_irqrestore(&list->spinlock,flags);
267-
268+
269+ spin_lock_irqsave(&buf_list->spinlock, flags);
270+
271+ list_add_tail(&buf->list_item, &buf_list->list);
272+ buf_list->count++;
273+
274+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
275 } /* end of n_hdlc_buf_put() */
276
277 /**
278 * n_hdlc_buf_get - remove and return an HDLC buffer from list
279- * @list - pointer to HDLC buffer list
280+ * @buf_list - pointer to HDLC buffer list
281 *
282 * Remove and return an HDLC buffer from the head of the specified HDLC buffer
283 * list.
284 * Returns a pointer to HDLC buffer if available, otherwise %NULL.
285 */
286-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
287+static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
288 {
289 unsigned long flags;
290 struct n_hdlc_buf *buf;
291- spin_lock_irqsave(&list->spinlock,flags);
292-
293- buf = list->head;
294+
295+ spin_lock_irqsave(&buf_list->spinlock, flags);
296+
297+ buf = list_first_entry_or_null(&buf_list->list,
298+ struct n_hdlc_buf, list_item);
299 if (buf) {
300- list->head = buf->link;
301- (list->count)--;
302+ list_del(&buf->list_item);
303+ buf_list->count--;
304 }
305- if (!list->head)
306- list->tail = NULL;
307-
308- spin_unlock_irqrestore(&list->spinlock,flags);
309+
310+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
311 return buf;
312-
313 } /* end of n_hdlc_buf_get() */
314
315 static char hdlc_banner[] __initdata =
316--
3171.9.1
318
diff --git a/recipes-kernel/linux/linux-ls1_3.12.bbappend b/recipes-kernel/linux/linux-ls1_3.12.bbappend
index acf04cf..d399448 100644
--- a/recipes-kernel/linux/linux-ls1_3.12.bbappend
+++ b/recipes-kernel/linux/linux-ls1_3.12.bbappend
@@ -11,6 +11,7 @@ SRC_URI += "file://ls1021aiot.dts \
11 file://CVE-2016-5195.patch \ 11 file://CVE-2016-5195.patch \
12 file://CVE-2016-6480.patch \ 12 file://CVE-2016-6480.patch \
13 file://0001-CVE-2017-2636.patch \ 13 file://0001-CVE-2017-2636.patch \
14 file://0002-CVE-2017-2636.patch \
14 " 15 "
15 16
16# fix err: "linux-ls1-3.12-r0 do_deploy: Taskhash mismatch" 17# fix err: "linux-ls1-3.12-r0 do_deploy: Taskhash mismatch"