comparison mercurial/parsers.c @ 26591:042344313939

parsers: fix infinite loop or out-of-bound read in fm1readmarkers (issue4888) The issue4888 was caused by 0-length obsolete marker. If msize is zero, fm1readmarkers() never ends. This patch adds several bound checks to fm1readmarker(). Therefore, 0-length and invalid-size marker should be rejected.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 11 Oct 2015 18:30:47 +0900
parents 473a63c45394
children 3111b45a2bbf
comparison
equal deleted inserted replaced
26590:473a63c45394 26591:042344313939
2547 return NULL; 2547 return NULL;
2548 } 2548 }
2549 2549
2550 #define BUMPED_FIX 1 2550 #define BUMPED_FIX 1
2551 #define USING_SHA_256 2 2551 #define USING_SHA_256 2
2552 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
2552 2553
2553 static PyObject *readshas( 2554 static PyObject *readshas(
2554 const char *source, unsigned char num, Py_ssize_t hashwidth) 2555 const char *source, unsigned char num, Py_ssize_t hashwidth)
2555 { 2556 {
2556 int i; 2557 int i;
2568 source += hashwidth; 2569 source += hashwidth;
2569 } 2570 }
2570 return list; 2571 return list;
2571 } 2572 }
2572 2573
2573 static PyObject *fm1readmarker(const char *data, uint32_t *msize) 2574 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
2574 { 2575 uint32_t *msize)
2576 {
2577 const char *data = databegin;
2575 const char *meta; 2578 const char *meta;
2576 2579
2577 double mtime; 2580 double mtime;
2578 int16_t tz; 2581 int16_t tz;
2579 uint16_t flags; 2582 uint16_t flags;
2581 Py_ssize_t hashwidth = 20; 2584 Py_ssize_t hashwidth = 20;
2582 2585
2583 PyObject *prec = NULL, *parents = NULL, *succs = NULL; 2586 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2584 PyObject *metadata = NULL, *ret = NULL; 2587 PyObject *metadata = NULL, *ret = NULL;
2585 int i; 2588 int i;
2589
2590 if (data + FM1_HEADER_SIZE > dataend) {
2591 goto overflow;
2592 }
2586 2593
2587 *msize = getbe32(data); 2594 *msize = getbe32(data);
2588 data += 4; 2595 data += 4;
2589 mtime = getbefloat64(data); 2596 mtime = getbefloat64(data);
2590 data += 8; 2597 data += 8;
2599 2606
2600 nsuccs = (unsigned char)(*data++); 2607 nsuccs = (unsigned char)(*data++);
2601 nparents = (unsigned char)(*data++); 2608 nparents = (unsigned char)(*data++);
2602 nmetadata = (unsigned char)(*data++); 2609 nmetadata = (unsigned char)(*data++);
2603 2610
2611 if (databegin + *msize > dataend) {
2612 goto overflow;
2613 }
2614 dataend = databegin + *msize; /* narrow down to marker size */
2615
2616 if (data + hashwidth > dataend) {
2617 goto overflow;
2618 }
2604 prec = PyString_FromStringAndSize(data, hashwidth); 2619 prec = PyString_FromStringAndSize(data, hashwidth);
2605 data += hashwidth; 2620 data += hashwidth;
2606 if (prec == NULL) { 2621 if (prec == NULL) {
2607 goto bail; 2622 goto bail;
2608 } 2623 }
2609 2624
2625 if (data + nsuccs * hashwidth > dataend) {
2626 goto overflow;
2627 }
2610 succs = readshas(data, nsuccs, hashwidth); 2628 succs = readshas(data, nsuccs, hashwidth);
2611 if (succs == NULL) { 2629 if (succs == NULL) {
2612 goto bail; 2630 goto bail;
2613 } 2631 }
2614 data += nsuccs * hashwidth; 2632 data += nsuccs * hashwidth;
2615 2633
2616 if (nparents == 1 || nparents == 2) { 2634 if (nparents == 1 || nparents == 2) {
2635 if (data + nparents * hashwidth > dataend) {
2636 goto overflow;
2637 }
2617 parents = readshas(data, nparents, hashwidth); 2638 parents = readshas(data, nparents, hashwidth);
2618 if (parents == NULL) { 2639 if (parents == NULL) {
2619 goto bail; 2640 goto bail;
2620 } 2641 }
2621 data += nparents * hashwidth; 2642 data += nparents * hashwidth;
2622 } else { 2643 } else {
2623 parents = Py_None; 2644 parents = Py_None;
2624 } 2645 }
2625 2646
2647 if (data + 2 * nmetadata > dataend) {
2648 goto overflow;
2649 }
2626 meta = data + (2 * nmetadata); 2650 meta = data + (2 * nmetadata);
2627 metadata = PyTuple_New(nmetadata); 2651 metadata = PyTuple_New(nmetadata);
2628 if (metadata == NULL) { 2652 if (metadata == NULL) {
2629 goto bail; 2653 goto bail;
2630 } 2654 }
2631 for (i = 0; i < nmetadata; i++) { 2655 for (i = 0; i < nmetadata; i++) {
2632 PyObject *tmp, *left = NULL, *right = NULL; 2656 PyObject *tmp, *left = NULL, *right = NULL;
2633 Py_ssize_t leftsize = (unsigned char)(*data++); 2657 Py_ssize_t leftsize = (unsigned char)(*data++);
2634 Py_ssize_t rightsize = (unsigned char)(*data++); 2658 Py_ssize_t rightsize = (unsigned char)(*data++);
2659 if (meta + leftsize + rightsize > dataend) {
2660 goto overflow;
2661 }
2635 left = PyString_FromStringAndSize(meta, leftsize); 2662 left = PyString_FromStringAndSize(meta, leftsize);
2636 meta += leftsize; 2663 meta += leftsize;
2637 right = PyString_FromStringAndSize(meta, rightsize); 2664 right = PyString_FromStringAndSize(meta, rightsize);
2638 meta += rightsize; 2665 meta += rightsize;
2639 tmp = PyTuple_New(2); 2666 tmp = PyTuple_New(2);
2647 PyTuple_SET_ITEM(tmp, 1, right); 2674 PyTuple_SET_ITEM(tmp, 1, right);
2648 PyTuple_SET_ITEM(metadata, i, tmp); 2675 PyTuple_SET_ITEM(metadata, i, tmp);
2649 } 2676 }
2650 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, 2677 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2651 metadata, mtime, (int)tz * 60, parents); 2678 metadata, mtime, (int)tz * 60, parents);
2679 goto bail; /* return successfully */
2680
2681 overflow:
2682 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
2652 bail: 2683 bail:
2653 Py_XDECREF(prec); 2684 Py_XDECREF(prec);
2654 Py_XDECREF(succs); 2685 Py_XDECREF(succs);
2655 Py_XDECREF(metadata); 2686 Py_XDECREF(metadata);
2656 if (parents != Py_None) 2687 if (parents != Py_None)
2658 return ret; 2689 return ret;
2659 } 2690 }
2660 2691
2661 2692
2662 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) { 2693 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2663 const char *data; 2694 const char *data, *dataend;
2664 Py_ssize_t datalen; 2695 Py_ssize_t datalen;
2665 Py_ssize_t offset, stop; 2696 Py_ssize_t offset, stop;
2666 PyObject *markers = NULL; 2697 PyObject *markers = NULL;
2667 2698
2668 if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) { 2699 if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) {
2669 return NULL; 2700 return NULL;
2670 } 2701 }
2702 dataend = data + datalen;
2671 data += offset; 2703 data += offset;
2672 markers = PyList_New(0); 2704 markers = PyList_New(0);
2673 if (!markers) { 2705 if (!markers) {
2674 return NULL; 2706 return NULL;
2675 } 2707 }
2676 while (offset < stop) { 2708 while (offset < stop) {
2677 uint32_t msize; 2709 uint32_t msize;
2678 int error; 2710 int error;
2679 PyObject *record = fm1readmarker(data, &msize); 2711 PyObject *record = fm1readmarker(data, dataend, &msize);
2680 if (!record) { 2712 if (!record) {
2681 goto bail; 2713 goto bail;
2682 } 2714 }
2683 error = PyList_Append(markers, record); 2715 error = PyList_Append(markers, record);
2684 Py_DECREF(record); 2716 Py_DECREF(record);