Mercurial > hg
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); |