xref: /aosp_15_r20/external/selinux/libselinux/src/regex.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
2*2d543d20SAndroid Build Coastguard Worker #include <pthread.h>
3*2d543d20SAndroid Build Coastguard Worker #include <stdint.h>
4*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
5*2d543d20SAndroid Build Coastguard Worker #include <string.h>
6*2d543d20SAndroid Build Coastguard Worker 
7*2d543d20SAndroid Build Coastguard Worker #include "regex.h"
8*2d543d20SAndroid Build Coastguard Worker #include "label_file.h"
9*2d543d20SAndroid Build Coastguard Worker #include "selinux_internal.h"
10*2d543d20SAndroid Build Coastguard Worker 
11*2d543d20SAndroid Build Coastguard Worker #ifdef USE_PCRE2
12*2d543d20SAndroid Build Coastguard Worker #define REGEX_ARCH_SIZE_T PCRE2_SIZE
13*2d543d20SAndroid Build Coastguard Worker #else
14*2d543d20SAndroid Build Coastguard Worker #define REGEX_ARCH_SIZE_T size_t
15*2d543d20SAndroid Build Coastguard Worker #endif
16*2d543d20SAndroid Build Coastguard Worker 
17*2d543d20SAndroid Build Coastguard Worker #ifndef __BYTE_ORDER__
18*2d543d20SAndroid Build Coastguard Worker 
19*2d543d20SAndroid Build Coastguard Worker /* If the compiler doesn't define __BYTE_ORDER__, try to use the C
20*2d543d20SAndroid Build Coastguard Worker  * library <endian.h> header definitions. */
21*2d543d20SAndroid Build Coastguard Worker #include <endian.h>
22*2d543d20SAndroid Build Coastguard Worker #ifndef __BYTE_ORDER
23*2d543d20SAndroid Build Coastguard Worker #error Neither __BYTE_ORDER__ nor __BYTE_ORDER defined. Unable to determine endianness.
24*2d543d20SAndroid Build Coastguard Worker #endif
25*2d543d20SAndroid Build Coastguard Worker 
26*2d543d20SAndroid Build Coastguard Worker #define __ORDER_LITTLE_ENDIAN __LITTLE_ENDIAN
27*2d543d20SAndroid Build Coastguard Worker #define __ORDER_BIG_ENDIAN __BIG_ENDIAN
28*2d543d20SAndroid Build Coastguard Worker #define __BYTE_ORDER__ __BYTE_ORDER
29*2d543d20SAndroid Build Coastguard Worker 
30*2d543d20SAndroid Build Coastguard Worker #endif
31*2d543d20SAndroid Build Coastguard Worker 
32*2d543d20SAndroid Build Coastguard Worker #ifdef USE_PCRE2
33*2d543d20SAndroid Build Coastguard Worker static pthread_key_t match_data_key;
34*2d543d20SAndroid Build Coastguard Worker static int match_data_key_initialized = -1;
35*2d543d20SAndroid Build Coastguard Worker static pthread_mutex_t key_mutex = PTHREAD_MUTEX_INITIALIZER;
36*2d543d20SAndroid Build Coastguard Worker static __thread char match_data_initialized;
37*2d543d20SAndroid Build Coastguard Worker 
regex_arch_string(void)38*2d543d20SAndroid Build Coastguard Worker char const *regex_arch_string(void)
39*2d543d20SAndroid Build Coastguard Worker {
40*2d543d20SAndroid Build Coastguard Worker 	static char arch_string_buffer[32];
41*2d543d20SAndroid Build Coastguard Worker 	static char const *arch_string = "";
42*2d543d20SAndroid Build Coastguard Worker 	char const *endianness = NULL;
43*2d543d20SAndroid Build Coastguard Worker 	int rc;
44*2d543d20SAndroid Build Coastguard Worker 
45*2d543d20SAndroid Build Coastguard Worker 	if (arch_string[0] == '\0') {
46*2d543d20SAndroid Build Coastguard Worker 		if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
47*2d543d20SAndroid Build Coastguard Worker 			endianness = "el";
48*2d543d20SAndroid Build Coastguard Worker 		else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
49*2d543d20SAndroid Build Coastguard Worker 			endianness = "eb";
50*2d543d20SAndroid Build Coastguard Worker 
51*2d543d20SAndroid Build Coastguard Worker 		if (!endianness)
52*2d543d20SAndroid Build Coastguard Worker 			return NULL;
53*2d543d20SAndroid Build Coastguard Worker 
54*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer),
55*2d543d20SAndroid Build Coastguard Worker 				"%zu-%zu-%s", sizeof(void *),
56*2d543d20SAndroid Build Coastguard Worker 				sizeof(REGEX_ARCH_SIZE_T),
57*2d543d20SAndroid Build Coastguard Worker 				endianness);
58*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
59*2d543d20SAndroid Build Coastguard Worker 			abort();
60*2d543d20SAndroid Build Coastguard Worker 
61*2d543d20SAndroid Build Coastguard Worker 		arch_string = &arch_string_buffer[0];
62*2d543d20SAndroid Build Coastguard Worker 	}
63*2d543d20SAndroid Build Coastguard Worker 	return arch_string;
64*2d543d20SAndroid Build Coastguard Worker }
65*2d543d20SAndroid Build Coastguard Worker 
66*2d543d20SAndroid Build Coastguard Worker struct regex_data {
67*2d543d20SAndroid Build Coastguard Worker 	pcre2_code *regex; /* compiled regular expression */
68*2d543d20SAndroid Build Coastguard Worker };
69*2d543d20SAndroid Build Coastguard Worker 
regex_prepare_data(struct regex_data ** regex,char const * pattern_string,struct regex_error_data * errordata)70*2d543d20SAndroid Build Coastguard Worker int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
71*2d543d20SAndroid Build Coastguard Worker 		       struct regex_error_data *errordata)
72*2d543d20SAndroid Build Coastguard Worker {
73*2d543d20SAndroid Build Coastguard Worker 	memset(errordata, 0, sizeof(struct regex_error_data));
74*2d543d20SAndroid Build Coastguard Worker 
75*2d543d20SAndroid Build Coastguard Worker 	*regex = regex_data_create();
76*2d543d20SAndroid Build Coastguard Worker 	if (!(*regex))
77*2d543d20SAndroid Build Coastguard Worker 		return -1;
78*2d543d20SAndroid Build Coastguard Worker 
79*2d543d20SAndroid Build Coastguard Worker 	(*regex)->regex = pcre2_compile(
80*2d543d20SAndroid Build Coastguard Worker 	    (PCRE2_SPTR)pattern_string, PCRE2_ZERO_TERMINATED, PCRE2_DOTALL,
81*2d543d20SAndroid Build Coastguard Worker 	    &errordata->error_code, &errordata->error_offset, NULL);
82*2d543d20SAndroid Build Coastguard Worker 	if (!(*regex)->regex) {
83*2d543d20SAndroid Build Coastguard Worker 		goto err;
84*2d543d20SAndroid Build Coastguard Worker 	}
85*2d543d20SAndroid Build Coastguard Worker 
86*2d543d20SAndroid Build Coastguard Worker 	return 0;
87*2d543d20SAndroid Build Coastguard Worker 
88*2d543d20SAndroid Build Coastguard Worker err:
89*2d543d20SAndroid Build Coastguard Worker 	regex_data_free(*regex);
90*2d543d20SAndroid Build Coastguard Worker 	*regex = NULL;
91*2d543d20SAndroid Build Coastguard Worker 	return -1;
92*2d543d20SAndroid Build Coastguard Worker }
93*2d543d20SAndroid Build Coastguard Worker 
regex_version(void)94*2d543d20SAndroid Build Coastguard Worker char const *regex_version(void)
95*2d543d20SAndroid Build Coastguard Worker {
96*2d543d20SAndroid Build Coastguard Worker 	static char version_buf[256];
97*2d543d20SAndroid Build Coastguard Worker 	size_t len = pcre2_config(PCRE2_CONFIG_VERSION, NULL);
98*2d543d20SAndroid Build Coastguard Worker 	if (len <= 0 || len > sizeof(version_buf))
99*2d543d20SAndroid Build Coastguard Worker 		return NULL;
100*2d543d20SAndroid Build Coastguard Worker 
101*2d543d20SAndroid Build Coastguard Worker 	pcre2_config(PCRE2_CONFIG_VERSION, version_buf);
102*2d543d20SAndroid Build Coastguard Worker 	return version_buf;
103*2d543d20SAndroid Build Coastguard Worker }
104*2d543d20SAndroid Build Coastguard Worker 
regex_load_mmap(struct mmap_area * mmap_area,struct regex_data ** regex,int do_load_precompregex,bool * regex_compiled)105*2d543d20SAndroid Build Coastguard Worker int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
106*2d543d20SAndroid Build Coastguard Worker 		    int do_load_precompregex, bool *regex_compiled)
107*2d543d20SAndroid Build Coastguard Worker {
108*2d543d20SAndroid Build Coastguard Worker 	int rc;
109*2d543d20SAndroid Build Coastguard Worker 	uint32_t entry_len;
110*2d543d20SAndroid Build Coastguard Worker 
111*2d543d20SAndroid Build Coastguard Worker 	*regex_compiled = false;
112*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
113*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
114*2d543d20SAndroid Build Coastguard Worker 		return -1;
115*2d543d20SAndroid Build Coastguard Worker 
116*2d543d20SAndroid Build Coastguard Worker 	if (entry_len && do_load_precompregex) {
117*2d543d20SAndroid Build Coastguard Worker 		/*
118*2d543d20SAndroid Build Coastguard Worker 		 * this should yield exactly one because we store one pattern at
119*2d543d20SAndroid Build Coastguard Worker 		 * a time
120*2d543d20SAndroid Build Coastguard Worker 		 */
121*2d543d20SAndroid Build Coastguard Worker 		rc = pcre2_serialize_get_number_of_codes(mmap_area->next_addr);
122*2d543d20SAndroid Build Coastguard Worker 		if (rc != 1)
123*2d543d20SAndroid Build Coastguard Worker 			return -1;
124*2d543d20SAndroid Build Coastguard Worker 
125*2d543d20SAndroid Build Coastguard Worker 		*regex = regex_data_create();
126*2d543d20SAndroid Build Coastguard Worker 		if (!*regex)
127*2d543d20SAndroid Build Coastguard Worker 			return -1;
128*2d543d20SAndroid Build Coastguard Worker 
129*2d543d20SAndroid Build Coastguard Worker 		rc = pcre2_serialize_decode(&(*regex)->regex, 1,
130*2d543d20SAndroid Build Coastguard Worker 					    (PCRE2_SPTR)mmap_area->next_addr,
131*2d543d20SAndroid Build Coastguard Worker 					    NULL);
132*2d543d20SAndroid Build Coastguard Worker 		if (rc != 1)
133*2d543d20SAndroid Build Coastguard Worker 			goto err;
134*2d543d20SAndroid Build Coastguard Worker 
135*2d543d20SAndroid Build Coastguard Worker 		*regex_compiled = true;
136*2d543d20SAndroid Build Coastguard Worker 	}
137*2d543d20SAndroid Build Coastguard Worker 
138*2d543d20SAndroid Build Coastguard Worker 	/* and skip the decoded bit */
139*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(NULL, mmap_area, entry_len);
140*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
141*2d543d20SAndroid Build Coastguard Worker 		goto err;
142*2d543d20SAndroid Build Coastguard Worker 
143*2d543d20SAndroid Build Coastguard Worker 	return 0;
144*2d543d20SAndroid Build Coastguard Worker err:
145*2d543d20SAndroid Build Coastguard Worker 	regex_data_free(*regex);
146*2d543d20SAndroid Build Coastguard Worker 	*regex = NULL;
147*2d543d20SAndroid Build Coastguard Worker 	return -1;
148*2d543d20SAndroid Build Coastguard Worker }
149*2d543d20SAndroid Build Coastguard Worker 
regex_writef(struct regex_data * regex,FILE * fp,int do_write_precompregex)150*2d543d20SAndroid Build Coastguard Worker int regex_writef(struct regex_data *regex, FILE *fp, int do_write_precompregex)
151*2d543d20SAndroid Build Coastguard Worker {
152*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
153*2d543d20SAndroid Build Coastguard Worker 	size_t len;
154*2d543d20SAndroid Build Coastguard Worker 	PCRE2_SIZE serialized_size;
155*2d543d20SAndroid Build Coastguard Worker 	uint32_t to_write = 0;
156*2d543d20SAndroid Build Coastguard Worker 	PCRE2_UCHAR *bytes = NULL;
157*2d543d20SAndroid Build Coastguard Worker 
158*2d543d20SAndroid Build Coastguard Worker 	if (do_write_precompregex) {
159*2d543d20SAndroid Build Coastguard Worker 		/* encode the pattern for serialization */
160*2d543d20SAndroid Build Coastguard Worker 		rc = pcre2_serialize_encode((const pcre2_code **)&regex->regex,
161*2d543d20SAndroid Build Coastguard Worker 					    1, &bytes, &serialized_size, NULL);
162*2d543d20SAndroid Build Coastguard Worker 		if (rc != 1 || serialized_size >= UINT32_MAX) {
163*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
164*2d543d20SAndroid Build Coastguard Worker 			goto out;
165*2d543d20SAndroid Build Coastguard Worker 		}
166*2d543d20SAndroid Build Coastguard Worker 		to_write = serialized_size;
167*2d543d20SAndroid Build Coastguard Worker 	}
168*2d543d20SAndroid Build Coastguard Worker 
169*2d543d20SAndroid Build Coastguard Worker 	/* write serialized pattern's size */
170*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&to_write, sizeof(uint32_t), 1, fp);
171*2d543d20SAndroid Build Coastguard Worker 	if (len != 1) {
172*2d543d20SAndroid Build Coastguard Worker 		rc = -1;
173*2d543d20SAndroid Build Coastguard Worker 		goto out;
174*2d543d20SAndroid Build Coastguard Worker 	}
175*2d543d20SAndroid Build Coastguard Worker 
176*2d543d20SAndroid Build Coastguard Worker 	if (do_write_precompregex) {
177*2d543d20SAndroid Build Coastguard Worker 		/* write serialized pattern */
178*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(bytes, 1, to_write, fp);
179*2d543d20SAndroid Build Coastguard Worker 		if (len != to_write)
180*2d543d20SAndroid Build Coastguard Worker 			rc = -1;
181*2d543d20SAndroid Build Coastguard Worker 	}
182*2d543d20SAndroid Build Coastguard Worker 
183*2d543d20SAndroid Build Coastguard Worker out:
184*2d543d20SAndroid Build Coastguard Worker 	if (bytes)
185*2d543d20SAndroid Build Coastguard Worker 		pcre2_serialize_free(bytes);
186*2d543d20SAndroid Build Coastguard Worker 
187*2d543d20SAndroid Build Coastguard Worker 	return rc;
188*2d543d20SAndroid Build Coastguard Worker }
189*2d543d20SAndroid Build Coastguard Worker 
match_data_thread_free(void * key)190*2d543d20SAndroid Build Coastguard Worker static void __attribute__((destructor)) match_data_thread_free(void *key)
191*2d543d20SAndroid Build Coastguard Worker {
192*2d543d20SAndroid Build Coastguard Worker 	void *value;
193*2d543d20SAndroid Build Coastguard Worker 	pcre2_match_data *match_data;
194*2d543d20SAndroid Build Coastguard Worker 
195*2d543d20SAndroid Build Coastguard Worker 	if (match_data_key_initialized <= 0 || !match_data_initialized)
196*2d543d20SAndroid Build Coastguard Worker 		return;
197*2d543d20SAndroid Build Coastguard Worker 
198*2d543d20SAndroid Build Coastguard Worker 	value = __selinux_getspecific(match_data_key);
199*2d543d20SAndroid Build Coastguard Worker 	match_data = value ? value : key;
200*2d543d20SAndroid Build Coastguard Worker 
201*2d543d20SAndroid Build Coastguard Worker 	pcre2_match_data_free(match_data);
202*2d543d20SAndroid Build Coastguard Worker 
203*2d543d20SAndroid Build Coastguard Worker 	__pthread_mutex_lock(&key_mutex);
204*2d543d20SAndroid Build Coastguard Worker 	if (--match_data_key_initialized == 1) {
205*2d543d20SAndroid Build Coastguard Worker 		__selinux_key_delete(match_data_key);
206*2d543d20SAndroid Build Coastguard Worker 		match_data_key_initialized = -1;
207*2d543d20SAndroid Build Coastguard Worker 	}
208*2d543d20SAndroid Build Coastguard Worker 	__pthread_mutex_unlock(&key_mutex);
209*2d543d20SAndroid Build Coastguard Worker }
210*2d543d20SAndroid Build Coastguard Worker 
regex_data_free(struct regex_data * regex)211*2d543d20SAndroid Build Coastguard Worker void regex_data_free(struct regex_data *regex)
212*2d543d20SAndroid Build Coastguard Worker {
213*2d543d20SAndroid Build Coastguard Worker 	if (regex) {
214*2d543d20SAndroid Build Coastguard Worker 		if (regex->regex)
215*2d543d20SAndroid Build Coastguard Worker 			pcre2_code_free(regex->regex);
216*2d543d20SAndroid Build Coastguard Worker 		free(regex);
217*2d543d20SAndroid Build Coastguard Worker 	}
218*2d543d20SAndroid Build Coastguard Worker }
219*2d543d20SAndroid Build Coastguard Worker 
regex_match(struct regex_data * regex,char const * subject,int partial)220*2d543d20SAndroid Build Coastguard Worker int regex_match(struct regex_data *regex, char const *subject, int partial)
221*2d543d20SAndroid Build Coastguard Worker {
222*2d543d20SAndroid Build Coastguard Worker 	int rc;
223*2d543d20SAndroid Build Coastguard Worker 	bool slow;
224*2d543d20SAndroid Build Coastguard Worker 	pcre2_match_data *match_data = NULL;
225*2d543d20SAndroid Build Coastguard Worker 
226*2d543d20SAndroid Build Coastguard Worker 	if (match_data_key_initialized > 0) {
227*2d543d20SAndroid Build Coastguard Worker 		if (match_data_initialized == 0) {
228*2d543d20SAndroid Build Coastguard Worker 			match_data = pcre2_match_data_create(1, NULL);
229*2d543d20SAndroid Build Coastguard Worker 			if (match_data) {
230*2d543d20SAndroid Build Coastguard Worker 				match_data_initialized = 1;
231*2d543d20SAndroid Build Coastguard Worker 				__selinux_setspecific(match_data_key,
232*2d543d20SAndroid Build Coastguard Worker 							match_data);
233*2d543d20SAndroid Build Coastguard Worker 				__pthread_mutex_lock(&key_mutex);
234*2d543d20SAndroid Build Coastguard Worker 				match_data_key_initialized++;
235*2d543d20SAndroid Build Coastguard Worker 				__pthread_mutex_unlock(&key_mutex);
236*2d543d20SAndroid Build Coastguard Worker 			}
237*2d543d20SAndroid Build Coastguard Worker 		} else
238*2d543d20SAndroid Build Coastguard Worker 			match_data = __selinux_getspecific(match_data_key);
239*2d543d20SAndroid Build Coastguard Worker 	}
240*2d543d20SAndroid Build Coastguard Worker 
241*2d543d20SAndroid Build Coastguard Worker 	slow = (match_data_key_initialized <= 0 || match_data == NULL);
242*2d543d20SAndroid Build Coastguard Worker 	if (slow) {
243*2d543d20SAndroid Build Coastguard Worker 		match_data = pcre2_match_data_create_from_pattern(regex->regex,
244*2d543d20SAndroid Build Coastguard Worker 									NULL);
245*2d543d20SAndroid Build Coastguard Worker 		if (!match_data)
246*2d543d20SAndroid Build Coastguard Worker 			return REGEX_ERROR;
247*2d543d20SAndroid Build Coastguard Worker 	}
248*2d543d20SAndroid Build Coastguard Worker 
249*2d543d20SAndroid Build Coastguard Worker 	rc = pcre2_match(
250*2d543d20SAndroid Build Coastguard Worker 	    regex->regex, (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0,
251*2d543d20SAndroid Build Coastguard Worker 	    partial ? PCRE2_PARTIAL_SOFT : 0, match_data, NULL);
252*2d543d20SAndroid Build Coastguard Worker 
253*2d543d20SAndroid Build Coastguard Worker 	if (slow)
254*2d543d20SAndroid Build Coastguard Worker 		pcre2_match_data_free(match_data);
255*2d543d20SAndroid Build Coastguard Worker 
256*2d543d20SAndroid Build Coastguard Worker 	if (rc >= 0)
257*2d543d20SAndroid Build Coastguard Worker 		return REGEX_MATCH;
258*2d543d20SAndroid Build Coastguard Worker 	switch (rc) {
259*2d543d20SAndroid Build Coastguard Worker 	case PCRE2_ERROR_PARTIAL:
260*2d543d20SAndroid Build Coastguard Worker 		return REGEX_MATCH_PARTIAL;
261*2d543d20SAndroid Build Coastguard Worker 	case PCRE2_ERROR_NOMATCH:
262*2d543d20SAndroid Build Coastguard Worker 		return REGEX_NO_MATCH;
263*2d543d20SAndroid Build Coastguard Worker 	default:
264*2d543d20SAndroid Build Coastguard Worker 		return REGEX_ERROR;
265*2d543d20SAndroid Build Coastguard Worker 	}
266*2d543d20SAndroid Build Coastguard Worker }
267*2d543d20SAndroid Build Coastguard Worker 
268*2d543d20SAndroid Build Coastguard Worker /*
269*2d543d20SAndroid Build Coastguard Worker  * TODO Replace this compare function with something that actually compares the
270*2d543d20SAndroid Build Coastguard Worker  * regular expressions.
271*2d543d20SAndroid Build Coastguard Worker  * This compare function basically just compares the binary representations of
272*2d543d20SAndroid Build Coastguard Worker  * the automatons, and because this representation contains pointers and
273*2d543d20SAndroid Build Coastguard Worker  * metadata, it can only return a match if regex1 == regex2.
274*2d543d20SAndroid Build Coastguard Worker  * Preferably, this function would be replaced with an algorithm that computes
275*2d543d20SAndroid Build Coastguard Worker  * the equivalence of the automatons systematically.
276*2d543d20SAndroid Build Coastguard Worker  */
regex_cmp(struct regex_data * regex1,struct regex_data * regex2)277*2d543d20SAndroid Build Coastguard Worker int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
278*2d543d20SAndroid Build Coastguard Worker {
279*2d543d20SAndroid Build Coastguard Worker 	int rc;
280*2d543d20SAndroid Build Coastguard Worker 	size_t len1, len2;
281*2d543d20SAndroid Build Coastguard Worker 	rc = pcre2_pattern_info(regex1->regex, PCRE2_INFO_SIZE, &len1);
282*2d543d20SAndroid Build Coastguard Worker 	assert(rc == 0);
283*2d543d20SAndroid Build Coastguard Worker 	rc = pcre2_pattern_info(regex2->regex, PCRE2_INFO_SIZE, &len2);
284*2d543d20SAndroid Build Coastguard Worker 	assert(rc == 0);
285*2d543d20SAndroid Build Coastguard Worker 	if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1))
286*2d543d20SAndroid Build Coastguard Worker 		return SELABEL_INCOMPARABLE;
287*2d543d20SAndroid Build Coastguard Worker 
288*2d543d20SAndroid Build Coastguard Worker 	return SELABEL_EQUAL;
289*2d543d20SAndroid Build Coastguard Worker }
290*2d543d20SAndroid Build Coastguard Worker 
regex_data_create(void)291*2d543d20SAndroid Build Coastguard Worker struct regex_data *regex_data_create(void)
292*2d543d20SAndroid Build Coastguard Worker {
293*2d543d20SAndroid Build Coastguard Worker 	struct regex_data *regex_data =
294*2d543d20SAndroid Build Coastguard Worker 		(struct regex_data *)calloc(1, sizeof(struct regex_data));
295*2d543d20SAndroid Build Coastguard Worker 	if (!regex_data)
296*2d543d20SAndroid Build Coastguard Worker 		return NULL;
297*2d543d20SAndroid Build Coastguard Worker 
298*2d543d20SAndroid Build Coastguard Worker 	__pthread_mutex_lock(&key_mutex);
299*2d543d20SAndroid Build Coastguard Worker 	if (match_data_key_initialized < 0) {
300*2d543d20SAndroid Build Coastguard Worker 		match_data_key_initialized = !__selinux_key_create(
301*2d543d20SAndroid Build Coastguard Worker 							&match_data_key,
302*2d543d20SAndroid Build Coastguard Worker 							match_data_thread_free);
303*2d543d20SAndroid Build Coastguard Worker 	}
304*2d543d20SAndroid Build Coastguard Worker 	__pthread_mutex_unlock(&key_mutex);
305*2d543d20SAndroid Build Coastguard Worker 
306*2d543d20SAndroid Build Coastguard Worker 	return regex_data;
307*2d543d20SAndroid Build Coastguard Worker }
308*2d543d20SAndroid Build Coastguard Worker 
309*2d543d20SAndroid Build Coastguard Worker #else // !USE_PCRE2
regex_arch_string(void)310*2d543d20SAndroid Build Coastguard Worker char const *regex_arch_string(void)
311*2d543d20SAndroid Build Coastguard Worker {
312*2d543d20SAndroid Build Coastguard Worker 	return "N/A";
313*2d543d20SAndroid Build Coastguard Worker }
314*2d543d20SAndroid Build Coastguard Worker 
315*2d543d20SAndroid Build Coastguard Worker /* Prior to version 8.20, libpcre did not have pcre_free_study() */
316*2d543d20SAndroid Build Coastguard Worker #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
317*2d543d20SAndroid Build Coastguard Worker #define pcre_free_study pcre_free
318*2d543d20SAndroid Build Coastguard Worker #endif
319*2d543d20SAndroid Build Coastguard Worker 
320*2d543d20SAndroid Build Coastguard Worker struct regex_data {
321*2d543d20SAndroid Build Coastguard Worker 	int owned;   /*
322*2d543d20SAndroid Build Coastguard Worker 		      * non zero if regex and pcre_extra is owned by this
323*2d543d20SAndroid Build Coastguard Worker 		      * structure and thus must be freed on destruction.
324*2d543d20SAndroid Build Coastguard Worker 		      */
325*2d543d20SAndroid Build Coastguard Worker 	pcre *regex; /* compiled regular expression */
326*2d543d20SAndroid Build Coastguard Worker 	union {
327*2d543d20SAndroid Build Coastguard Worker 		pcre_extra *sd; /* pointer to extra compiled stuff */
328*2d543d20SAndroid Build Coastguard Worker 		pcre_extra lsd; /* used to hold the mmap'd version */
329*2d543d20SAndroid Build Coastguard Worker 	};
330*2d543d20SAndroid Build Coastguard Worker };
331*2d543d20SAndroid Build Coastguard Worker 
regex_prepare_data(struct regex_data ** regex,char const * pattern_string,struct regex_error_data * errordata)332*2d543d20SAndroid Build Coastguard Worker int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
333*2d543d20SAndroid Build Coastguard Worker 		       struct regex_error_data *errordata)
334*2d543d20SAndroid Build Coastguard Worker {
335*2d543d20SAndroid Build Coastguard Worker 	memset(errordata, 0, sizeof(struct regex_error_data));
336*2d543d20SAndroid Build Coastguard Worker 
337*2d543d20SAndroid Build Coastguard Worker 	*regex = regex_data_create();
338*2d543d20SAndroid Build Coastguard Worker 	if (!(*regex))
339*2d543d20SAndroid Build Coastguard Worker 		return -1;
340*2d543d20SAndroid Build Coastguard Worker 
341*2d543d20SAndroid Build Coastguard Worker 	(*regex)->regex =
342*2d543d20SAndroid Build Coastguard Worker 	    pcre_compile(pattern_string, PCRE_DOTALL, &errordata->error_buffer,
343*2d543d20SAndroid Build Coastguard Worker 			 &errordata->error_offset, NULL);
344*2d543d20SAndroid Build Coastguard Worker 	if (!(*regex)->regex)
345*2d543d20SAndroid Build Coastguard Worker 		goto err;
346*2d543d20SAndroid Build Coastguard Worker 
347*2d543d20SAndroid Build Coastguard Worker 	(*regex)->owned = 1;
348*2d543d20SAndroid Build Coastguard Worker 
349*2d543d20SAndroid Build Coastguard Worker 	(*regex)->sd = pcre_study((*regex)->regex, 0, &errordata->error_buffer);
350*2d543d20SAndroid Build Coastguard Worker 	if (!(*regex)->sd && errordata->error_buffer)
351*2d543d20SAndroid Build Coastguard Worker 		goto err;
352*2d543d20SAndroid Build Coastguard Worker 
353*2d543d20SAndroid Build Coastguard Worker 	return 0;
354*2d543d20SAndroid Build Coastguard Worker 
355*2d543d20SAndroid Build Coastguard Worker err:
356*2d543d20SAndroid Build Coastguard Worker 	regex_data_free(*regex);
357*2d543d20SAndroid Build Coastguard Worker 	*regex = NULL;
358*2d543d20SAndroid Build Coastguard Worker 	return -1;
359*2d543d20SAndroid Build Coastguard Worker }
360*2d543d20SAndroid Build Coastguard Worker 
regex_version(void)361*2d543d20SAndroid Build Coastguard Worker char const *regex_version(void)
362*2d543d20SAndroid Build Coastguard Worker {
363*2d543d20SAndroid Build Coastguard Worker 	return pcre_version();
364*2d543d20SAndroid Build Coastguard Worker }
365*2d543d20SAndroid Build Coastguard Worker 
regex_load_mmap(struct mmap_area * mmap_area,struct regex_data ** regex,int do_load_precompregex,bool * regex_compiled)366*2d543d20SAndroid Build Coastguard Worker int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
367*2d543d20SAndroid Build Coastguard Worker 		    int do_load_precompregex __attribute__((unused)), bool *regex_compiled)
368*2d543d20SAndroid Build Coastguard Worker {
369*2d543d20SAndroid Build Coastguard Worker 	int rc;
370*2d543d20SAndroid Build Coastguard Worker 	uint32_t entry_len;
371*2d543d20SAndroid Build Coastguard Worker 	size_t info_len;
372*2d543d20SAndroid Build Coastguard Worker 
373*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
374*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0 || !entry_len)
375*2d543d20SAndroid Build Coastguard Worker 		return -1;
376*2d543d20SAndroid Build Coastguard Worker 
377*2d543d20SAndroid Build Coastguard Worker 	*regex = regex_data_create();
378*2d543d20SAndroid Build Coastguard Worker 	if (!(*regex))
379*2d543d20SAndroid Build Coastguard Worker 		return -1;
380*2d543d20SAndroid Build Coastguard Worker 
381*2d543d20SAndroid Build Coastguard Worker 	(*regex)->owned = 0;
382*2d543d20SAndroid Build Coastguard Worker 	(*regex)->regex = (pcre *)mmap_area->next_addr;
383*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(NULL, mmap_area, entry_len);
384*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
385*2d543d20SAndroid Build Coastguard Worker 		goto err;
386*2d543d20SAndroid Build Coastguard Worker 
387*2d543d20SAndroid Build Coastguard Worker 	/*
388*2d543d20SAndroid Build Coastguard Worker 	 * Check that regex lengths match. pcre_fullinfo()
389*2d543d20SAndroid Build Coastguard Worker 	 * also validates its magic number.
390*2d543d20SAndroid Build Coastguard Worker 	 */
391*2d543d20SAndroid Build Coastguard Worker 	rc = pcre_fullinfo((*regex)->regex, NULL, PCRE_INFO_SIZE, &info_len);
392*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0 || info_len != entry_len)
393*2d543d20SAndroid Build Coastguard Worker 		goto err;
394*2d543d20SAndroid Build Coastguard Worker 
395*2d543d20SAndroid Build Coastguard Worker 	rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
396*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
397*2d543d20SAndroid Build Coastguard Worker 		goto err;
398*2d543d20SAndroid Build Coastguard Worker 
399*2d543d20SAndroid Build Coastguard Worker 	if (entry_len) {
400*2d543d20SAndroid Build Coastguard Worker 		(*regex)->lsd.study_data = (void *)mmap_area->next_addr;
401*2d543d20SAndroid Build Coastguard Worker 		(*regex)->lsd.flags |= PCRE_EXTRA_STUDY_DATA;
402*2d543d20SAndroid Build Coastguard Worker 		rc = next_entry(NULL, mmap_area, entry_len);
403*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
404*2d543d20SAndroid Build Coastguard Worker 			goto err;
405*2d543d20SAndroid Build Coastguard Worker 
406*2d543d20SAndroid Build Coastguard Worker 		/* Check that study data lengths match. */
407*2d543d20SAndroid Build Coastguard Worker 		rc = pcre_fullinfo((*regex)->regex, &(*regex)->lsd,
408*2d543d20SAndroid Build Coastguard Worker 				   PCRE_INFO_STUDYSIZE, &info_len);
409*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0 || info_len != entry_len)
410*2d543d20SAndroid Build Coastguard Worker 			goto err;
411*2d543d20SAndroid Build Coastguard Worker 	}
412*2d543d20SAndroid Build Coastguard Worker 
413*2d543d20SAndroid Build Coastguard Worker 	*regex_compiled = true;
414*2d543d20SAndroid Build Coastguard Worker 	return 0;
415*2d543d20SAndroid Build Coastguard Worker 
416*2d543d20SAndroid Build Coastguard Worker err:
417*2d543d20SAndroid Build Coastguard Worker 	regex_data_free(*regex);
418*2d543d20SAndroid Build Coastguard Worker 	*regex = NULL;
419*2d543d20SAndroid Build Coastguard Worker 	return -1;
420*2d543d20SAndroid Build Coastguard Worker }
421*2d543d20SAndroid Build Coastguard Worker 
get_pcre_extra(struct regex_data * regex)422*2d543d20SAndroid Build Coastguard Worker static inline pcre_extra *get_pcre_extra(struct regex_data *regex)
423*2d543d20SAndroid Build Coastguard Worker {
424*2d543d20SAndroid Build Coastguard Worker 	if (!regex) return NULL;
425*2d543d20SAndroid Build Coastguard Worker 	if (regex->owned) {
426*2d543d20SAndroid Build Coastguard Worker 		return regex->sd;
427*2d543d20SAndroid Build Coastguard Worker 	} else if (regex->lsd.study_data) {
428*2d543d20SAndroid Build Coastguard Worker 		return &regex->lsd;
429*2d543d20SAndroid Build Coastguard Worker 	} else {
430*2d543d20SAndroid Build Coastguard Worker 		return NULL;
431*2d543d20SAndroid Build Coastguard Worker 	}
432*2d543d20SAndroid Build Coastguard Worker }
433*2d543d20SAndroid Build Coastguard Worker 
regex_writef(struct regex_data * regex,FILE * fp,int do_write_precompregex)434*2d543d20SAndroid Build Coastguard Worker int regex_writef(struct regex_data *regex, FILE *fp,
435*2d543d20SAndroid Build Coastguard Worker 		 int do_write_precompregex __attribute__((unused)))
436*2d543d20SAndroid Build Coastguard Worker {
437*2d543d20SAndroid Build Coastguard Worker 	int rc;
438*2d543d20SAndroid Build Coastguard Worker 	size_t len;
439*2d543d20SAndroid Build Coastguard Worker 	uint32_t to_write;
440*2d543d20SAndroid Build Coastguard Worker 	size_t size;
441*2d543d20SAndroid Build Coastguard Worker 	pcre_extra *sd = get_pcre_extra(regex);
442*2d543d20SAndroid Build Coastguard Worker 
443*2d543d20SAndroid Build Coastguard Worker 	/* determine the size of the pcre data in bytes */
444*2d543d20SAndroid Build Coastguard Worker 	rc = pcre_fullinfo(regex->regex, NULL, PCRE_INFO_SIZE, &size);
445*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
446*2d543d20SAndroid Build Coastguard Worker 		return -1;
447*2d543d20SAndroid Build Coastguard Worker 
448*2d543d20SAndroid Build Coastguard Worker 	/* write the number of bytes in the pcre data */
449*2d543d20SAndroid Build Coastguard Worker 	to_write = size;
450*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&to_write, sizeof(uint32_t), 1, fp);
451*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
452*2d543d20SAndroid Build Coastguard Worker 		return -1;
453*2d543d20SAndroid Build Coastguard Worker 
454*2d543d20SAndroid Build Coastguard Worker 	/* write the actual pcre data as a char array */
455*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(regex->regex, 1, to_write, fp);
456*2d543d20SAndroid Build Coastguard Worker 	if (len != to_write)
457*2d543d20SAndroid Build Coastguard Worker 		return -1;
458*2d543d20SAndroid Build Coastguard Worker 
459*2d543d20SAndroid Build Coastguard Worker 	if (sd) {
460*2d543d20SAndroid Build Coastguard Worker 		/* determine the size of the pcre study info */
461*2d543d20SAndroid Build Coastguard Worker 		rc =
462*2d543d20SAndroid Build Coastguard Worker 		    pcre_fullinfo(regex->regex, sd, PCRE_INFO_STUDYSIZE, &size);
463*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
464*2d543d20SAndroid Build Coastguard Worker 			return -1;
465*2d543d20SAndroid Build Coastguard Worker 	} else
466*2d543d20SAndroid Build Coastguard Worker 		size = 0;
467*2d543d20SAndroid Build Coastguard Worker 
468*2d543d20SAndroid Build Coastguard Worker 	/* write the number of bytes in the pcre study data */
469*2d543d20SAndroid Build Coastguard Worker 	to_write = size;
470*2d543d20SAndroid Build Coastguard Worker 	len = fwrite(&to_write, sizeof(uint32_t), 1, fp);
471*2d543d20SAndroid Build Coastguard Worker 	if (len != 1)
472*2d543d20SAndroid Build Coastguard Worker 		return -1;
473*2d543d20SAndroid Build Coastguard Worker 
474*2d543d20SAndroid Build Coastguard Worker 	if (sd) {
475*2d543d20SAndroid Build Coastguard Worker 		/* write the actual pcre study data as a char array */
476*2d543d20SAndroid Build Coastguard Worker 		len = fwrite(sd->study_data, 1, to_write, fp);
477*2d543d20SAndroid Build Coastguard Worker 		if (len != to_write)
478*2d543d20SAndroid Build Coastguard Worker 			return -1;
479*2d543d20SAndroid Build Coastguard Worker 	}
480*2d543d20SAndroid Build Coastguard Worker 
481*2d543d20SAndroid Build Coastguard Worker 	return 0;
482*2d543d20SAndroid Build Coastguard Worker }
483*2d543d20SAndroid Build Coastguard Worker 
regex_data_free(struct regex_data * regex)484*2d543d20SAndroid Build Coastguard Worker void regex_data_free(struct regex_data *regex)
485*2d543d20SAndroid Build Coastguard Worker {
486*2d543d20SAndroid Build Coastguard Worker 	if (regex) {
487*2d543d20SAndroid Build Coastguard Worker 		if (regex->owned) {
488*2d543d20SAndroid Build Coastguard Worker 			if (regex->regex)
489*2d543d20SAndroid Build Coastguard Worker 				pcre_free(regex->regex);
490*2d543d20SAndroid Build Coastguard Worker 			if (regex->sd)
491*2d543d20SAndroid Build Coastguard Worker 				pcre_free_study(regex->sd);
492*2d543d20SAndroid Build Coastguard Worker 		}
493*2d543d20SAndroid Build Coastguard Worker 		free(regex);
494*2d543d20SAndroid Build Coastguard Worker 	}
495*2d543d20SAndroid Build Coastguard Worker }
496*2d543d20SAndroid Build Coastguard Worker 
regex_match(struct regex_data * regex,char const * subject,int partial)497*2d543d20SAndroid Build Coastguard Worker int regex_match(struct regex_data *regex, char const *subject, int partial)
498*2d543d20SAndroid Build Coastguard Worker {
499*2d543d20SAndroid Build Coastguard Worker 	int rc;
500*2d543d20SAndroid Build Coastguard Worker 
501*2d543d20SAndroid Build Coastguard Worker 	rc = pcre_exec(regex->regex, get_pcre_extra(regex),
502*2d543d20SAndroid Build Coastguard Worker 		       subject, strlen(subject), 0,
503*2d543d20SAndroid Build Coastguard Worker 		       partial ? PCRE_PARTIAL_SOFT : 0, NULL, 0);
504*2d543d20SAndroid Build Coastguard Worker 	switch (rc) {
505*2d543d20SAndroid Build Coastguard Worker 	case 0:
506*2d543d20SAndroid Build Coastguard Worker 		return REGEX_MATCH;
507*2d543d20SAndroid Build Coastguard Worker 	case PCRE_ERROR_PARTIAL:
508*2d543d20SAndroid Build Coastguard Worker 		return REGEX_MATCH_PARTIAL;
509*2d543d20SAndroid Build Coastguard Worker 	case PCRE_ERROR_NOMATCH:
510*2d543d20SAndroid Build Coastguard Worker 		return REGEX_NO_MATCH;
511*2d543d20SAndroid Build Coastguard Worker 	default:
512*2d543d20SAndroid Build Coastguard Worker 		return REGEX_ERROR;
513*2d543d20SAndroid Build Coastguard Worker 	}
514*2d543d20SAndroid Build Coastguard Worker }
515*2d543d20SAndroid Build Coastguard Worker 
516*2d543d20SAndroid Build Coastguard Worker /*
517*2d543d20SAndroid Build Coastguard Worker  * TODO Replace this compare function with something that actually compares the
518*2d543d20SAndroid Build Coastguard Worker  * regular expressions.
519*2d543d20SAndroid Build Coastguard Worker  * This compare function basically just compares the binary representations of
520*2d543d20SAndroid Build Coastguard Worker  * the automatons, and because this representation contains pointers and
521*2d543d20SAndroid Build Coastguard Worker  * metadata, it can only return a match if regex1 == regex2.
522*2d543d20SAndroid Build Coastguard Worker  * Preferably, this function would be replaced with an algorithm that computes
523*2d543d20SAndroid Build Coastguard Worker  * the equivalence of the automatons systematically.
524*2d543d20SAndroid Build Coastguard Worker  */
regex_cmp(struct regex_data * regex1,struct regex_data * regex2)525*2d543d20SAndroid Build Coastguard Worker int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
526*2d543d20SAndroid Build Coastguard Worker {
527*2d543d20SAndroid Build Coastguard Worker 	int rc;
528*2d543d20SAndroid Build Coastguard Worker 	size_t len1, len2;
529*2d543d20SAndroid Build Coastguard Worker 	rc = pcre_fullinfo(regex1->regex, NULL, PCRE_INFO_SIZE, &len1);
530*2d543d20SAndroid Build Coastguard Worker 	assert(rc == 0);
531*2d543d20SAndroid Build Coastguard Worker 	rc = pcre_fullinfo(regex2->regex, NULL, PCRE_INFO_SIZE, &len2);
532*2d543d20SAndroid Build Coastguard Worker 	assert(rc == 0);
533*2d543d20SAndroid Build Coastguard Worker 	if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1))
534*2d543d20SAndroid Build Coastguard Worker 		return SELABEL_INCOMPARABLE;
535*2d543d20SAndroid Build Coastguard Worker 
536*2d543d20SAndroid Build Coastguard Worker 	return SELABEL_EQUAL;
537*2d543d20SAndroid Build Coastguard Worker }
538*2d543d20SAndroid Build Coastguard Worker 
regex_data_create(void)539*2d543d20SAndroid Build Coastguard Worker struct regex_data *regex_data_create(void)
540*2d543d20SAndroid Build Coastguard Worker {
541*2d543d20SAndroid Build Coastguard Worker 	return (struct regex_data *)calloc(1, sizeof(struct regex_data));
542*2d543d20SAndroid Build Coastguard Worker }
543*2d543d20SAndroid Build Coastguard Worker 
544*2d543d20SAndroid Build Coastguard Worker #endif
545*2d543d20SAndroid Build Coastguard Worker 
regex_format_error(struct regex_error_data const * error_data,char * buffer,size_t buf_size)546*2d543d20SAndroid Build Coastguard Worker void regex_format_error(struct regex_error_data const *error_data, char *buffer,
547*2d543d20SAndroid Build Coastguard Worker 			size_t buf_size)
548*2d543d20SAndroid Build Coastguard Worker {
549*2d543d20SAndroid Build Coastguard Worker 	unsigned the_end_length = buf_size > 4 ? 4 : buf_size;
550*2d543d20SAndroid Build Coastguard Worker 	char *ptr = &buffer[buf_size - the_end_length];
551*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
552*2d543d20SAndroid Build Coastguard Worker 	size_t pos = 0;
553*2d543d20SAndroid Build Coastguard Worker 	if (!buffer || !buf_size)
554*2d543d20SAndroid Build Coastguard Worker 		return;
555*2d543d20SAndroid Build Coastguard Worker 	rc = snprintf(buffer, buf_size, "REGEX back-end error: ");
556*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
557*2d543d20SAndroid Build Coastguard Worker 		/*
558*2d543d20SAndroid Build Coastguard Worker 		 * If snprintf fails it constitutes a logical error that needs
559*2d543d20SAndroid Build Coastguard Worker 		 * fixing.
560*2d543d20SAndroid Build Coastguard Worker 		 */
561*2d543d20SAndroid Build Coastguard Worker 		abort();
562*2d543d20SAndroid Build Coastguard Worker 
563*2d543d20SAndroid Build Coastguard Worker 	pos += rc;
564*2d543d20SAndroid Build Coastguard Worker 	if (pos >= buf_size)
565*2d543d20SAndroid Build Coastguard Worker 		goto truncated;
566*2d543d20SAndroid Build Coastguard Worker 
567*2d543d20SAndroid Build Coastguard Worker 	/* Return early if there is no error to format */
568*2d543d20SAndroid Build Coastguard Worker #ifdef USE_PCRE2
569*2d543d20SAndroid Build Coastguard Worker 	if (!error_data->error_code) {
570*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(buffer + pos, buf_size - pos, "no error code");
571*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
572*2d543d20SAndroid Build Coastguard Worker 			abort();
573*2d543d20SAndroid Build Coastguard Worker 		pos += rc;
574*2d543d20SAndroid Build Coastguard Worker 		if (pos >= buf_size)
575*2d543d20SAndroid Build Coastguard Worker 			goto truncated;
576*2d543d20SAndroid Build Coastguard Worker 		return;
577*2d543d20SAndroid Build Coastguard Worker 	}
578*2d543d20SAndroid Build Coastguard Worker #else
579*2d543d20SAndroid Build Coastguard Worker 	if (!error_data->error_buffer) {
580*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(buffer + pos, buf_size - pos, "empty error");
581*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
582*2d543d20SAndroid Build Coastguard Worker 			abort();
583*2d543d20SAndroid Build Coastguard Worker 		pos += rc;
584*2d543d20SAndroid Build Coastguard Worker 		if (pos >= buf_size)
585*2d543d20SAndroid Build Coastguard Worker 			goto truncated;
586*2d543d20SAndroid Build Coastguard Worker 		return;
587*2d543d20SAndroid Build Coastguard Worker 	}
588*2d543d20SAndroid Build Coastguard Worker #endif
589*2d543d20SAndroid Build Coastguard Worker 
590*2d543d20SAndroid Build Coastguard Worker 	if (error_data->error_offset > 0) {
591*2d543d20SAndroid Build Coastguard Worker #ifdef USE_PCRE2
592*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(buffer + pos, buf_size - pos, "At offset %zu: ",
593*2d543d20SAndroid Build Coastguard Worker 			      error_data->error_offset);
594*2d543d20SAndroid Build Coastguard Worker #else
595*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(buffer + pos, buf_size - pos, "At offset %d: ",
596*2d543d20SAndroid Build Coastguard Worker 			      error_data->error_offset);
597*2d543d20SAndroid Build Coastguard Worker #endif
598*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
599*2d543d20SAndroid Build Coastguard Worker 			abort();
600*2d543d20SAndroid Build Coastguard Worker 		pos += rc;
601*2d543d20SAndroid Build Coastguard Worker 		if (pos >= buf_size)
602*2d543d20SAndroid Build Coastguard Worker 			goto truncated;
603*2d543d20SAndroid Build Coastguard Worker 	}
604*2d543d20SAndroid Build Coastguard Worker 
605*2d543d20SAndroid Build Coastguard Worker #ifdef USE_PCRE2
606*2d543d20SAndroid Build Coastguard Worker 	rc = pcre2_get_error_message(error_data->error_code,
607*2d543d20SAndroid Build Coastguard Worker 				     (PCRE2_UCHAR *)(buffer + pos),
608*2d543d20SAndroid Build Coastguard Worker 				     buf_size - pos);
609*2d543d20SAndroid Build Coastguard Worker 	if (rc == PCRE2_ERROR_NOMEMORY)
610*2d543d20SAndroid Build Coastguard Worker 		goto truncated;
611*2d543d20SAndroid Build Coastguard Worker #else
612*2d543d20SAndroid Build Coastguard Worker 	rc = snprintf(buffer + pos, buf_size - pos, "%s",
613*2d543d20SAndroid Build Coastguard Worker 		      error_data->error_buffer);
614*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
615*2d543d20SAndroid Build Coastguard Worker 		abort();
616*2d543d20SAndroid Build Coastguard Worker 
617*2d543d20SAndroid Build Coastguard Worker 	if ((size_t)rc < strlen(error_data->error_buffer))
618*2d543d20SAndroid Build Coastguard Worker 		goto truncated;
619*2d543d20SAndroid Build Coastguard Worker #endif
620*2d543d20SAndroid Build Coastguard Worker 
621*2d543d20SAndroid Build Coastguard Worker 	return;
622*2d543d20SAndroid Build Coastguard Worker 
623*2d543d20SAndroid Build Coastguard Worker truncated:
624*2d543d20SAndroid Build Coastguard Worker 	/* replace end of string with "..." to indicate that it was truncated */
625*2d543d20SAndroid Build Coastguard Worker 	switch (the_end_length) {
626*2d543d20SAndroid Build Coastguard Worker 	/* no break statements, fall-through is intended */
627*2d543d20SAndroid Build Coastguard Worker 	case 4:
628*2d543d20SAndroid Build Coastguard Worker 		*ptr++ = '.';
629*2d543d20SAndroid Build Coastguard Worker 		/* FALLTHRU */
630*2d543d20SAndroid Build Coastguard Worker 	case 3:
631*2d543d20SAndroid Build Coastguard Worker 		*ptr++ = '.';
632*2d543d20SAndroid Build Coastguard Worker 		/* FALLTHRU */
633*2d543d20SAndroid Build Coastguard Worker 	case 2:
634*2d543d20SAndroid Build Coastguard Worker 		*ptr++ = '.';
635*2d543d20SAndroid Build Coastguard Worker 		/* FALLTHRU */
636*2d543d20SAndroid Build Coastguard Worker 	case 1:
637*2d543d20SAndroid Build Coastguard Worker 		*ptr++ = '\0';
638*2d543d20SAndroid Build Coastguard Worker 		/* FALLTHRU */
639*2d543d20SAndroid Build Coastguard Worker 	default:
640*2d543d20SAndroid Build Coastguard Worker 		break;
641*2d543d20SAndroid Build Coastguard Worker 	}
642*2d543d20SAndroid Build Coastguard Worker 	return;
643*2d543d20SAndroid Build Coastguard Worker }
644