1 /*-
2  * Copyright 2003-2005 Colin Percival
3  * All rights reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted providing that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 #include "nbpatch.h"
27 #include "libc.h"
28 #include "updater.h"
29 
30 #define HEADER_SIZE 48
31 
offtin(unsigned char * buf)32 long offtin(unsigned char *buf) {
33     long y;
34 
35     y = buf[7] & 0x7F;
36     y <<= 8; y += buf[6];
37     y <<= 8; y += buf[5];
38     y <<= 8; y += buf[4];
39     y <<= 8; y += buf[3];
40     y <<= 8; y += buf[2];
41     y <<= 8; y += buf[1];
42     y <<= 8; y += buf[0];
43     if (buf[7] & 0x80)
44         y = -y;
45     return y;
46 }
47 
xz_read(xzReadHandler * handler,struct xz_buf * b,struct xz_dec * s,unsigned long patch,unsigned char * buf,int len)48 long xz_read(xzReadHandler *handler, struct xz_buf *b,struct xz_dec *s, unsigned long patch, unsigned char *buf, int len)
49 {
50     long ret = 0;
51     if (handler == NULL || b == NULL || s == NULL || patch == 0 || buf == NULL || len <= 0) {
52          return 0;
53     };
54 
55     b->out = buf;
56     b->out_pos = 0;
57     b->out_size = len;
58     while(true) {
59         if (b->in_pos == b->in_size && handler->avail_size > 0) {
60             size_t readsize = IN_BUF_MAX >  handler->avail_size ? handler->avail_size:IN_BUF_MAX;
61             b->in_size = ota_patch_read(patch, handler->in_buf, handler->read_pos, readsize);
62             handler->avail_size -= readsize;
63             handler->read_pos += readsize;
64             b->in_pos = 0;
65             b->in = handler->in_buf;
66         }
67 
68         ret = xz_dec_run(s, b);
69         if (ret != XZ_OK && ret != XZ_STREAM_END) {
70             OTA_LOG_I("xz dec err:%ld \n", ret);
71             return 0;
72         }
73         if (handler->avail_size <= 0 && b->in_pos == b->in_size
74                 && b->out_pos < len) {
75             return b->out_pos;
76         }
77 
78         if (b->out_pos == len) {
79             return len;
80         }
81     }
82     return ret;
83 }
84 
ota_nbpatch(const unsigned long old_addr,long old_size,unsigned long patch,long * seek_pos,int num)85 static long ota_nbpatch(const unsigned long old_addr, long old_size, unsigned long patch, long *seek_pos, int num)
86 {
87     int ret = 0;
88     long new_size = 0;
89     long ctrl_len = 0;
90     long diff_len = 0;
91     long extra_len = 0;
92     unsigned char header[HEADER_SIZE], buf[8];
93     unsigned char *old_buf = NULL;
94     unsigned char *new_buf = NULL;
95     long old_pos = 0;
96     long new_pos = 0;
97     long ctrl[3] = {0};
98     long read_len = 0;
99     long i = 0;
100     CRC16_CTX crc_ctx;
101     unsigned short patch_crc = 0;
102     unsigned short crc = 0, cal_crc = 0;
103     struct xz_dec *ctrl_dec = NULL, *diff_dec = NULL, *extra_dec = NULL;
104     struct xz_buf cb = {0}, db = {0}, eb = {0};
105 
106     if(!old_addr || !patch || !seek_pos ) {
107         ret = OTA_NB_INVALID_PARAM;
108         goto EXIT;
109     }
110     long patch_pos = *seek_pos;
111     old_buf = malloc(SECTOR_SIZE);
112     if (old_buf == NULL){
113         ret = OTA_NB_MEMORY_FAIL;
114         goto EXIT;
115     }
116     /*
117      File format:
118      0	8	"BSDIFF40"
119      8	8	X
120      16	8	Y
121      24	8	sizeof(newfile)
122      32	X	bzip2(control block)
123      32+X       bzip2(diff block)
124      32+X+Y     bzip2(extra block)
125      with control block a set of triples (x,y,z) meaning "add x bytes
126      from oldfile to x bytes from the diff block; copy y bytes from the
127      extra block; seek forwards in oldfile by z bytes".
128      */
129     ret = ota_patch_read(patch, header, patch_pos, HEADER_SIZE);
130     if(ret < 0) {
131         ret = OTA_NB_HEADER_FAIL;
132         goto EXIT;
133     }
134 
135     /* Check for appropriate magic */
136     if (memcmp(header, "BSDIFF40", 8) != 0) {
137         ret = OTA_NB_HEADER_FAIL;
138         goto EXIT;
139     }
140     /* Read lengths from header */
141     ctrl_len = offtin(header + 8);
142     diff_len = offtin(header + 16);
143     extra_len = offtin(header + 24);
144     new_size = offtin(header + 32);
145     crc = offtin(header + 40);
146     if ((ctrl_len < 0) || (diff_len < 0) || (new_size < 0)) {
147         ret = OTA_NB_HEADER_FAIL;
148         goto EXIT;
149     }
150 
151     OTA_LOG_I("nbpatch %d header clen:%ld dlen:%ld elen:%ld crc:0x%02x... \n", num, ctrl_len, diff_len, extra_len, crc);
152     new_buf = malloc(new_size);
153     if (new_buf == NULL) {
154         ret = OTA_NB_MEMORY_FAIL;
155         goto EXIT;
156     }
157     crc16_init(&crc_ctx);
158     xz_crc32_init();
159     ctrl_dec = xz_dec_init(XZ_DYNALLOC, DIFF_DICT_SIZE);
160     if (ctrl_dec == NULL) {
161         ret = OTA_NB_MEMORY_FAIL;
162         goto EXIT;
163     }
164     diff_dec = xz_dec_init(XZ_DYNALLOC, DIFF_DICT_SIZE);
165     if (diff_dec == NULL) {
166         ret = OTA_NB_MEMORY_FAIL;
167         goto EXIT;
168     }
169     extra_dec = xz_dec_init(XZ_DYNALLOC, DIFF_DICT_SIZE);
170     if (extra_dec == NULL) {
171         ret = OTA_NB_MEMORY_FAIL;
172         goto EXIT;
173     }
174 
175     xzReadHandler cbhandler;
176     memset(&cbhandler, 0, sizeof(xzReadHandler));
177     cbhandler.avail_size = ctrl_len;
178     cbhandler.read_pos = patch_pos + HEADER_SIZE;
179     xzReadHandler diffhandler;
180     memset(&diffhandler, 0, sizeof(xzReadHandler));
181     diffhandler.avail_size = diff_len;
182     diffhandler.read_pos = patch_pos + HEADER_SIZE + ctrl_len;
183     xzReadHandler extrahandler;
184     memset(&extrahandler, 0, sizeof(xzReadHandler));
185     extrahandler.avail_size = extra_len;
186     extrahandler.read_pos = patch_pos + HEADER_SIZE + ctrl_len + diff_len;
187 
188     while (new_pos < new_size) {
189         /* Read control data */
190         for (i = 0; i <= 2; i++) {
191             read_len = xz_read(&cbhandler, &cb, ctrl_dec, patch, buf, 8);
192             if (read_len < 8) {
193                 ret = OTA_NB_READ_CTRL_FAIL;
194                 goto EXIT;
195             }
196             ctrl[i] = offtin(buf);
197             /* OTA_LOG_I("ctrlp[i] %ld", ctrl[i]); */
198         };
199 
200         /* Sanity-check */
201         if (new_pos + ctrl[0] > new_size){
202             ret = OTA_NB_READ_DIFF_FAIL;
203             goto EXIT;
204         }
205         /* Read diff string */
206         read_len = xz_read(&diffhandler, &db, diff_dec, patch, new_buf + new_pos, ctrl[0]);
207         if ((read_len < ctrl[0])){
208             ret = OTA_NB_READ_DIFF_FAIL;
209             goto EXIT;
210         }
211         if(old_pos > old_size || old_pos + ctrl[0] > old_size) {
212             ret = OTA_NB_READ_OLD_FAIL;
213             goto EXIT;
214         }
215         long cp_size  = ctrl[0];
216         long base_pos = 0;
217         int idx = 0;
218         long i;
219         for (i = 0; i < ctrl[0]; i++) {
220             if (!(i % SECTOR_SIZE)) {
221                 base_pos = (idx++) * SECTOR_SIZE;
222                 long osize = cp_size > SECTOR_SIZE ? SECTOR_SIZE : cp_size;
223                 memset(old_buf, 0, osize);
224                 ret = ota_patch_read(old_addr, old_buf, old_pos + base_pos, osize);
225                 if(ret < 0) {
226                      ret = OTA_NB_READ_OLD_FAIL;
227                      goto EXIT;
228                 }
229                 cp_size -= osize;
230                 /* OTA_LOG_I("start cp:%ld bp:%ld",cp_size, base_pos); */
231             }
232             if (i >= base_pos) {
233                 new_buf[new_pos + i] += old_buf[i - base_pos];
234             }
235         }
236         crc16_update(&crc_ctx, new_buf + new_pos, ctrl[0]);
237         /* Adjust pointers */
238         new_pos += ctrl[0];
239         old_pos += ctrl[0];
240         /* Sanity-check */
241         if (new_pos + ctrl[1] > new_size) {
242             ret = OTA_NB_READ_EXTRA_FAIL;
243             goto EXIT;
244         }
245         /* Read extra string */
246         read_len = xz_read(&extrahandler, &eb, extra_dec, patch, new_buf + new_pos, ctrl[1]);
247         if (read_len < ctrl[1]) {
248             ret = OTA_NB_READ_EXTRA_FAIL;
249             goto EXIT;
250         }
251         crc16_update(&crc_ctx, new_buf + new_pos, ctrl[1]);
252         /* Adjust pointers */
253         new_pos += ctrl[1];
254         old_pos += ctrl[2];
255     };
256     crc16_final(&crc_ctx, &patch_crc);
257     cal_crc = crc16_computer(new_buf, new_size);
258     if(cal_crc != crc) {
259         OTA_LOG_I("cal %02x != crc %02x", cal_crc, crc);
260         ret = OTA_NB_CRC_COMP_FAIL;
261         goto EXIT;
262     }
263     ret = ota_patch_new_data(new_buf, new_size);
264     if(ret < 0) {
265         ret = OTA_NB_WRITE_DATA_FAIL;
266         goto EXIT;
267     }
268     patch_pos += HEADER_SIZE;
269     patch_pos += ctrl_len;
270     patch_pos += diff_len;
271     patch_pos += extra_len;
272     *seek_pos = patch_pos;
273 
274 EXIT:
275     OTA_LOG_I("nbpatch %d end cal_crc:0x%02x patch_crc:0x%02x ret:%d\n", num, cal_crc, patch_crc, ret);
276     if(ctrl_dec){
277         xz_dec_end(ctrl_dec);
278         ctrl_dec = NULL;
279     }
280     if(diff_dec) {
281         xz_dec_end(diff_dec);
282         diff_dec = NULL;
283     }
284     if(extra_dec){
285         xz_dec_end(extra_dec);
286         extra_dec = NULL;
287     }
288     if(old_buf){
289         free(old_buf);
290         old_buf = NULL;
291     }
292     if(new_buf){
293         free(new_buf);
294         new_buf = NULL;
295     }
296     return (ret < 0) ? ret: new_size;
297 }
298 
ota_nbpatch_main(void)299 int ota_nbpatch_main(void) {
300     int ret = -1;
301     unsigned long old_addr = 0;
302     unsigned long patch_addr = 0;
303     int patch_num = 0;
304     long patch_off = 0;
305     long patch_size = 0;
306     long old_size = 0;
307     long new_off = 0;
308     long new_size = 0;
309     ota_boot_param_t ota_param = {0};
310 
311     memset(&ota_param, 0, sizeof(ota_boot_param_t));
312     ret = ota_patch_read_param(&ota_param);
313     if(ret < 0){
314         OTA_LOG_I("r param err.\n");
315         return OTA_NB_INVALID_PARAM;
316     }
317     old_addr = ota_param.dst_adr;
318     patch_addr = ota_param.src_adr;
319     patch_off = ota_param.patch_off;
320     patch_size = ota_param.len;
321     old_size = ota_param.old_size;
322     new_off = ota_param.new_off;
323     new_size = ota_param.new_size;
324     if (!old_addr || !patch_addr || old_size <= 0 || patch_size <= 0 || (ota_param.upg_flag != OTA_UPGRADE_DIFF)) {
325         OTA_LOG_I("param check err.\n");
326         return OTA_NB_INVALID_PARAM;
327     }
328 
329     OTA_LOG_I("oaddr:0x%lx paddr:0x%lx num:%d noff:%lx nsize:%lx poff:%lx psize:%ld status:%d \n", old_addr, patch_addr, patch_num, new_off, new_size, patch_off, patch_size, ota_param.patch_status);
330     while (patch_off < patch_size) {
331         if(!ota_param.patch_status) {
332             new_size = ota_nbpatch(old_addr, old_size, patch_addr, &patch_off, patch_num);
333             ota_param.patch_num = ++patch_num;
334             ota_param.patch_off = patch_off;
335             ota_param.new_off = new_off;
336             ota_param.new_size = new_size;
337             ota_param.patch_status = 1;
338             if (new_size < 0) {
339                 ret = new_size;
340                 goto EXIT;
341             }
342             ota_patch_write_param(&ota_param);
343         }
344         ret = ota_load_new_data(new_off, new_size);
345         if(ret < 0) {
346             ret = OTA_NB_WRITE_DATA_FAIL;
347             OTA_LOG_I("err new off:%ld \n", new_size);
348             goto EXIT;
349         }
350         new_off += new_size;
351         ota_param.patch_status = 0;
352         ota_param.new_off = new_off;
353         ota_patch_write_param(&ota_param);
354     }
355 EXIT:
356     if(patch_off > patch_size) {
357         ota_param.patch_num = 0;
358         ota_param.patch_off = 0;
359         ota_param.patch_status = 0;
360         ota_param.new_off = 0;
361         ota_param.new_size = 0;
362         ota_param.upg_flag = 0;
363     }
364     ota_patch_write_param(&ota_param);
365     OTA_LOG_I("nbpatch complete ret: %d new off:%lx size:0x%lx patch_off:0x%lx \n",ret, new_off, new_size, patch_off);
366     return (ret < 0) ? ret: new_off;
367 }
368