| ... | @@ -1674,6 +1674,12 @@ tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree, | ... | @@ -1674,6 +1674,12 @@ tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree, |
| 1674 | AST to TNFA compilation routines. | 1674 | AST to TNFA compilation routines. |
| 1675 | */ | 1675 | */ |
| 1676 | | 1676 | |
| | 1677 | /* check if a+b overflows for a,b in [0,INT_MAX] */ |
| | 1678 | static int check_add(unsigned a, unsigned b) |
| | 1679 | { |
| | 1680 | 	return a + b > INT_MAX; |
| | 1681 | } |
| | 1682 | |
| 1677 | typedef enum { | 1683 | typedef enum { |
| 1678 | COPY_RECURSE, | 1684 | COPY_RECURSE, |
| 1679 | COPY_SET_RESULT_PTR | 1685 | COPY_SET_RESULT_PTR |
| ... | @@ -1725,6 +1731,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, | ... | @@ -1725,6 +1731,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, |
| 1725 | 		 /* XXX - e.g. [ab] has only one position but two | 1731 | 		 /* XXX - e.g. [ab] has only one position but two |
| 1726 | 		 nodes, so we are creating holes in the state space | 1732 | 		 nodes, so we are creating holes in the state space |
| 1727 | 		 here. Not fatal, just wastes memory. */ | 1733 | 		 here. Not fatal, just wastes memory. */ |
| | 1734 | 		 if (check_add(pos, *pos_add)) |
| | 1735 | 		 return REG_ESPACE; |
| 1728 | 		 pos += *pos_add; | 1736 | 		 pos += *pos_add; |
| 1729 | 		 num_copied++; | 1737 | 		 num_copied++; |
| 1730 | 		 } | 1738 | 		 } |
| ... | @@ -1820,6 +1828,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, | ... | @@ -1820,6 +1828,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, |
| 1820 | 	 break; | 1828 | 	 break; |
| 1821 | 	} | 1829 | 	} |
| 1822 | } | 1830 | } |
| | 1831 | if (check_add(*pos_add, num_copied)) |
| | 1832 | return REG_ESPACE; |
| 1823 | *pos_add += num_copied; | 1833 | *pos_add += num_copied; |
| 1824 | return status; | 1834 | return status; |
| 1825 | } | 1835 | } |
| ... | @@ -1864,6 +1874,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, | ... | @@ -1864,6 +1874,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, |
| 1864 | 		tre_literal_t *lit= node->obj; | 1874 | 		tre_literal_t *lit= node->obj; |
| 1865 | 		if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) | 1875 | 		if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) |
| 1866 | 		 { | 1876 | 		 { |
| | 1877 | 		 if (check_add(lit->position, pos_add)) |
| | 1878 | 		 return REG_ESPACE; |
| 1867 | 		 lit->position += pos_add; | 1879 | 		 lit->position += pos_add; |
| 1868 | 		 if (lit->position > max_pos) | 1880 | 		 if (lit->position > max_pos) |
| 1869 | 		 max_pos = lit->position; | 1881 | 		 max_pos = lit->position; |
| ... | @@ -1992,6 +2004,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, | ... | @@ -1992,6 +2004,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, |
| 1992 | 	 } | 2004 | 	 } |
| 1993 | | 2005 | |
| 1994 | 	 iter_depth--; | 2006 | 	 iter_depth--; |
| | 2007 | 	 if (check_add(pos_add_total, pos_add - pos_add_last)) |
| | 2008 | 	 return REG_ESPACE; |
| 1995 | 	 pos_add_total += pos_add - pos_add_last; | 2009 | 	 pos_add_total += pos_add - pos_add_last; |
| 1996 | 	 if (iter_depth == 0) | 2010 | 	 if (iter_depth == 0) |
| 1997 | 	 pos_add = pos_add_total; | 2011 | 	 pos_add = pos_add_total; |
| ... | @@ -2004,6 +2018,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, | ... | @@ -2004,6 +2018,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, |
| 2004 | 	} | 2018 | 	} |
| 2005 | } | 2019 | } |
| 2006 | | 2020 | |
| | 2021 | if (check_add(*position, pos_add_total)) |
| | 2022 | return REG_ESPACE; |
| 2007 | *position += pos_add_total; | 2023 | *position += pos_add_total; |
| 2008 | | 2024 | |
| 2009 | /* `max_pos' should never be larger than `*position' if the above | 2025 | /* `max_pos' should never be larger than `*position' if the above |
| ... | @@ -2705,9 +2721,19 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) | ... | @@ -2705,9 +2721,19 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) |
| 2705 | /* Parse context. */ | 2721 | /* Parse context. */ |
| 2706 | tre_parse_ctx_t parse_ctx; | 2722 | tre_parse_ctx_t parse_ctx; |
| 2707 | | 2723 | |
| | 2724 | /* Limits: before tre_expand_ast, int values like position, subid or |
| | 2725 | * num_tags are bounded by 2x input length, used stack entries are |
| | 2726 | * bounded by 16x input length. input length is checked upfront to |
| | 2727 | * avoid overflows before expand. later, values that can grow big are |
| | 2728 | * bounds checked via check_add and xcalloc. */ |
| | 2729 | const int input_limit = 1024000; |
| | 2730 | const int stack_limit = 8*input_limit; |
| | 2731 | if (strnlen(regex, input_limit) >= input_limit) |
| | 2732 | return REG_ESPACE; |
| | 2733 | |
| 2708 | /* Allocate a stack used throughout the compilation process for various | 2734 | /* Allocate a stack used throughout the compilation process for various |
| 2709 | purposes. */ | 2735 | purposes. */ |
| 2710 | stack = tre_stack_new(512, 1024000, 128); | 2736 | stack = tre_stack_new(512, stack_limit, 128); |
| 2711 | if (!stack) | 2737 | if (!stack) |
| 2712 | return REG_ESPACE; | 2738 | return REG_ESPACE; |
| 2713 | /* Allocate a fast memory allocator. */ | 2739 | /* Allocate a fast memory allocator. */ |
| ... | @@ -2795,9 +2821,12 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) | ... | @@ -2795,9 +2821,12 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) |
| 2795 | 	 for example "a*" or "ab*".	Figure out a simple way to detect | 2821 | 	 for example "a*" or "ab*".	Figure out a simple way to detect |
| 2796 | 	 this possibility. */ | 2822 | 	 this possibility. */ |
| 2797 | tmp_ast_l = tree; | 2823 | tmp_ast_l = tree; |
| 2798 | tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++); | 2824 | tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position); |
| 2799 | if (tmp_ast_r == NULL) | 2825 | if (tmp_ast_r == NULL) |
| 2800 | ERROR_EXIT(REG_ESPACE); | 2826 | ERROR_EXIT(REG_ESPACE); |
| | 2827 | if (check_add(parse_ctx.position, 1)) |
| | 2828 | ERROR_EXIT(REG_ESPACE); |
| | 2829 | parse_ctx.position++; |
| 2801 | | 2830 | |
| 2802 | tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r); | 2831 | tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r); |
| 2803 | if (tree == NULL) | 2832 | if (tree == NULL) |
| ... | @@ -2807,22 +2836,22 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) | ... | @@ -2807,22 +2836,22 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) |
| 2807 | if (errcode != REG_OK) | 2836 | if (errcode != REG_OK) |
| 2808 | ERROR_EXIT(errcode); | 2837 | ERROR_EXIT(errcode); |
| 2809 | | 2838 | |
| 2810 | counts = xmalloc(sizeof(int) * parse_ctx.position); | 2839 | counts = xcalloc(sizeof(int), parse_ctx.position); |
| 2811 | if (counts == NULL) | 2840 | if (counts == NULL) |
| 2812 | ERROR_EXIT(REG_ESPACE); | 2841 | ERROR_EXIT(REG_ESPACE); |
| 2813 | | 2842 | |
| 2814 | offs = xmalloc(sizeof(int) * parse_ctx.position); | 2843 | offs = xcalloc(sizeof(int), parse_ctx.position); |
| 2815 | if (offs == NULL) | 2844 | if (offs == NULL) |
| 2816 | ERROR_EXIT(REG_ESPACE); | 2845 | ERROR_EXIT(REG_ESPACE); |
| 2817 | | 2846 | |
| 2818 | for (i = 0; i < parse_ctx.position; i++) | | |
| 2819 | counts[i] = 0; | | |
| 2820 | tre_ast_to_tnfa(tree, NULL, counts, NULL); | 2847 | tre_ast_to_tnfa(tree, NULL, counts, NULL); |
| 2821 | | 2848 | |
| 2822 | add = 0; | 2849 | add = 0; |
| 2823 | for (i = 0; i < parse_ctx.position; i++) | 2850 | for (i = 0; i < parse_ctx.position; i++) |
| 2824 | { | 2851 | { |
| 2825 | offs[i] = add; | 2852 | offs[i] = add; |
| | 2853 | if (check_add(add, counts[i] + 1)) |
| | 2854 | ERROR_EXIT(REG_ESPACE); |
| 2826 | add += counts[i] + 1; | 2855 | add += counts[i] + 1; |
| 2827 | counts[i] = 0; | 2856 | counts[i] = 0; |
| 2828 | } | 2857 | } |