summaryrefslogtreecommitdiff
path: root/src/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c94
1 files changed, 56 insertions, 38 deletions
diff --git a/src/io.c b/src/io.c
index af2f49a..9d2de88 100644
--- a/src/io.c
+++ b/src/io.c
@@ -20,11 +20,11 @@ struct frame {
20 uint8_t cmd; 20 uint8_t cmd;
21 uint8_t bcnth; 21 uint8_t bcnth;
22 uint8_t bcntl; 22 uint8_t bcntl;
23 uint8_t data[CTAP_RPT_SIZE - 7]; 23 uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN];
24 } init; 24 } init;
25 struct { 25 struct {
26 uint8_t seq; 26 uint8_t seq;
27 uint8_t data[CTAP_RPT_SIZE - 5]; 27 uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN];
28 } cont; 28 } cont;
29 } body; 29 } body;
30}) 30})
@@ -38,6 +38,7 @@ tx_empty(fido_dev_t *d, uint8_t cmd)
38{ 38{
39 struct frame *fp; 39 struct frame *fp;
40 unsigned char pkt[sizeof(*fp) + 1]; 40 unsigned char pkt[sizeof(*fp) + 1];
41 const size_t len = d->tx_len + 1;
41 int n; 42 int n;
42 43
43 memset(&pkt, 0, sizeof(pkt)); 44 memset(&pkt, 0, sizeof(pkt));
@@ -45,8 +46,8 @@ tx_empty(fido_dev_t *d, uint8_t cmd)
45 fp->cid = d->cid; 46 fp->cid = d->cid;
46 fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 47 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
47 48
48 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 49 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
49 if (n < 0 || (size_t)n != sizeof(pkt)) 50 len)) < 0 || (size_t)n != len)
50 return (-1); 51 return (-1);
51 52
52 return (0); 53 return (0);
@@ -57,19 +58,23 @@ tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
57{ 58{
58 struct frame *fp; 59 struct frame *fp;
59 unsigned char pkt[sizeof(*fp) + 1]; 60 unsigned char pkt[sizeof(*fp) + 1];
61 const size_t len = d->tx_len + 1;
60 int n; 62 int n;
61 63
64 if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data))
65 return (0);
66
62 memset(&pkt, 0, sizeof(pkt)); 67 memset(&pkt, 0, sizeof(pkt));
63 fp = (struct frame *)(pkt + 1); 68 fp = (struct frame *)(pkt + 1);
64 fp->cid = d->cid; 69 fp->cid = d->cid;
65 fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 70 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
66 fp->body.init.bcnth = (count >> 8) & 0xff; 71 fp->body.init.bcnth = (count >> 8) & 0xff;
67 fp->body.init.bcntl = count & 0xff; 72 fp->body.init.bcntl = count & 0xff;
68 count = MIN(count, sizeof(fp->body.init.data)); 73 count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN);
69 memcpy(&fp->body.init.data, buf, count); 74 memcpy(&fp->body.init.data, buf, count);
70 75
71 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 76 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
72 if (n < 0 || (size_t)n != sizeof(pkt)) 77 len)) < 0 || (size_t)n != len)
73 return (0); 78 return (0);
74 79
75 return (count); 80 return (count);
@@ -80,17 +85,21 @@ tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
80{ 85{
81 struct frame *fp; 86 struct frame *fp;
82 unsigned char pkt[sizeof(*fp) + 1]; 87 unsigned char pkt[sizeof(*fp) + 1];
88 const size_t len = d->tx_len + 1;
83 int n; 89 int n;
84 90
91 if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data))
92 return (0);
93
85 memset(&pkt, 0, sizeof(pkt)); 94 memset(&pkt, 0, sizeof(pkt));
86 fp = (struct frame *)(pkt + 1); 95 fp = (struct frame *)(pkt + 1);
87 fp->cid = d->cid; 96 fp->cid = d->cid;
88 fp->body.cont.seq = seq; 97 fp->body.cont.seq = seq;
89 count = MIN(count, sizeof(fp->body.cont.data)); 98 count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN);
90 memcpy(&fp->body.cont.data, buf, count); 99 memcpy(&fp->body.cont.data, buf, count);
91 100
92 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 101 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
93 if (n < 0 || (size_t)n != sizeof(pkt)) 102 len)) < 0 || (size_t)n != len)
94 return (0); 103 return (0);
95 104
96 return (count); 105 return (count);
@@ -129,16 +138,12 @@ fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
129 138
130 if (d->transport.tx != NULL) 139 if (d->transport.tx != NULL)
131 return (d->transport.tx(d, cmd, buf, count)); 140 return (d->transport.tx(d, cmd, buf, count));
132
133 if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) { 141 if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) {
134 fido_log_debug("%s: invalid argument", __func__); 142 fido_log_debug("%s: invalid argument", __func__);
135 return (-1); 143 return (-1);
136 } 144 }
137 145
138 if (count == 0) 146 return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count));
139 return (tx_empty(d, cmd));
140
141 return (tx(d, cmd, buf, count));
142} 147}
143 148
144static int 149static int
@@ -146,8 +151,10 @@ rx_frame(fido_dev_t *d, struct frame *fp, int ms)
146{ 151{
147 int n; 152 int n;
148 153
149 n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms); 154 memset(fp, 0, sizeof(*fp));
150 if (n < 0 || (size_t)n != sizeof(*fp)) 155
156 if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle,
157 (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len)
151 return (-1); 158 return (-1);
152 159
153 return (0); 160 return (0);
@@ -165,8 +172,11 @@ rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
165 } while (fp->cid == d->cid && 172 } while (fp->cid == d->cid &&
166 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)); 173 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE));
167 174
175 if (d->rx_len > sizeof(*fp))
176 return (-1);
177
168 fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp); 178 fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp);
169 fido_log_xxd(fp, sizeof(*fp)); 179 fido_log_xxd(fp, d->rx_len);
170 180
171#ifdef FIDO_FUZZ 181#ifdef FIDO_FUZZ
172 fp->body.init.cmd = (CTAP_FRAME_INIT | cmd); 182 fp->body.init.cmd = (CTAP_FRAME_INIT | cmd);
@@ -185,30 +195,41 @@ static int
185rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) 195rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
186{ 196{
187 struct frame f; 197 struct frame f;
188 uint16_t r, payload_len; 198 size_t r, payload_len, init_data_len, cont_data_len;
199
200 if (d->rx_len <= CTAP_INIT_HEADER_LEN ||
201 d->rx_len <= CTAP_CONT_HEADER_LEN)
202 return (-1);
203
204 init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN;
205 cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN;
206
207 if (init_data_len > sizeof(f.body.init.data) ||
208 cont_data_len > sizeof(f.body.cont.data))
209 return (-1);
189 210
190 if (rx_preamble(d, cmd, &f, ms) < 0) { 211 if (rx_preamble(d, cmd, &f, ms) < 0) {
191 fido_log_debug("%s: rx_preamble", __func__); 212 fido_log_debug("%s: rx_preamble", __func__);
192 return (-1); 213 return (-1);
193 } 214 }
194 215
195 payload_len = (f.body.init.bcnth << 8) | f.body.init.bcntl; 216 payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl);
196 fido_log_debug("%s: payload_len=%zu", __func__, (size_t)payload_len); 217 fido_log_debug("%s: payload_len=%zu", __func__, payload_len);
197 218
198 if (count < (size_t)payload_len) { 219 if (count < payload_len) {
199 fido_log_debug("%s: count < payload_len", __func__); 220 fido_log_debug("%s: count < payload_len", __func__);
200 return (-1); 221 return (-1);
201 } 222 }
202 223
203 if (payload_len < sizeof(f.body.init.data)) { 224 if (payload_len < init_data_len) {
204 memcpy(buf, f.body.init.data, payload_len); 225 memcpy(buf, f.body.init.data, payload_len);
205 return (payload_len); 226 return ((int)payload_len);
206 } 227 }
207 228
208 memcpy(buf, f.body.init.data, sizeof(f.body.init.data)); 229 memcpy(buf, f.body.init.data, init_data_len);
209 r = sizeof(f.body.init.data); 230 r = init_data_len;
210 231
211 for (int seq = 0; (size_t)r < payload_len; seq++) { 232 for (int seq = 0; r < payload_len; seq++) {
212 if (rx_frame(d, &f, ms) < 0) { 233 if (rx_frame(d, &f, ms) < 0) {
213 fido_log_debug("%s: rx_frame", __func__); 234 fido_log_debug("%s: rx_frame", __func__);
214 return (-1); 235 return (-1);
@@ -216,11 +237,11 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
216 237
217 fido_log_debug("%s: continuation frame at %p", __func__, 238 fido_log_debug("%s: continuation frame at %p", __func__,
218 (void *)&f); 239 (void *)&f);
219 fido_log_xxd(&f, sizeof(f)); 240 fido_log_xxd(&f, d->rx_len);
220 241
221#ifdef FIDO_FUZZ 242#ifdef FIDO_FUZZ
222 f.cid = d->cid; 243 f.cid = d->cid;
223 f.body.cont.seq = seq; 244 f.body.cont.seq = (uint8_t)seq;
224#endif 245#endif
225 246
226 if (f.cid != d->cid || f.body.cont.seq != seq) { 247 if (f.cid != d->cid || f.body.cont.seq != seq) {
@@ -229,17 +250,16 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
229 return (-1); 250 return (-1);
230 } 251 }
231 252
232 if ((size_t)(payload_len - r) > sizeof(f.body.cont.data)) { 253 if (payload_len - r > cont_data_len) {
233 memcpy(buf + r, f.body.cont.data, 254 memcpy(buf + r, f.body.cont.data, cont_data_len);
234 sizeof(f.body.cont.data)); 255 r += cont_data_len;
235 r += sizeof(f.body.cont.data);
236 } else { 256 } else {
237 memcpy(buf + r, f.body.cont.data, payload_len - r); 257 memcpy(buf + r, f.body.cont.data, payload_len - r);
238 r += (payload_len - r); /* break */ 258 r += payload_len - r; /* break */
239 } 259 }
240 } 260 }
241 261
242 return (r); 262 return ((int)r);
243} 263}
244 264
245int 265int
@@ -252,15 +272,13 @@ fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
252 272
253 if (d->transport.rx != NULL) 273 if (d->transport.rx != NULL)
254 return (d->transport.rx(d, cmd, buf, count, ms)); 274 return (d->transport.rx(d, cmd, buf, count, ms));
255
256 if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) { 275 if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) {
257 fido_log_debug("%s: invalid argument", __func__); 276 fido_log_debug("%s: invalid argument", __func__);
258 return (-1); 277 return (-1);
259 } 278 }
260
261 if ((n = rx(d, cmd, buf, count, ms)) >= 0) { 279 if ((n = rx(d, cmd, buf, count, ms)) >= 0) {
262 fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n); 280 fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n);
263 fido_log_xxd(buf, n); 281 fido_log_xxd(buf, (size_t)n);
264 } 282 }
265 283
266 return (n); 284 return (n);