CVE-2018-25103 (C, published 2024-06-17T18:15Z)
Description: value: There exists use-after-free vulnerabilities in lighttpd <= 1.4.50 request parsing which might read from invalid pointers to memory used in the same request, not from other requests.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/lighttpd/lighttpd1.4
Files changed:
src/request.c
Commit message: [core,security] process headers after combining folded headers

- this fixes various use-after-free scenarios (reported by Or Peles of
  VDOO): when parse_single_header stores pointers to header values in
  con->request, those pointers are not updated if the header value is
  reallocated when folded header lines are appended.
- also remove trailing white-space from folded lines


Vulnerable code:
					data_string *ds = NULL;
						/**
						 * we use a evil hack to handle the line-folding
						 * 
						 * As array_insert_unique() deletes 'ds' in the case of a duplicate
						 * ds points somewhere and we get a evil crash. As a solution we keep the old
						 * "key" and get the current value from the hash and append us
						 *
						 * */

						if (!key || !key_len) {
						if (NULL != (ds = (data_string *)array_get_element_klen(con->request.headers, key, key_len))) {
							buffer_append_string(ds->value, value);
						}
						int s_len;
						key = con->parse_request->ptr + first;

						s_len = cur - value;

						/* strip trailing white-spaces */
						for (; s_len > 0 && 
								(value[s_len - 1] == ' ' || 
									value[s_len - 1] == '\t'); s_len--);

						value[s_len] = '\0';

						if (s_len > 0) {
							if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
								ds = data_string_init();
							}
							buffer_copy_string_len(ds->key, key, key_len);
							buffer_copy_string_len(ds->value, value, s_len);

						} else {
							/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
#if 0
					/**
					 * for Bug 1230 keep the key_len a live
					 */
#endif

Fixed code:
	/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
	if (buffer_string_is_empty(ds->value)) {
		goto drop_header;
	}

	data_string *current_header = NULL;
					int value_len;

					value_len = cur - value;

					/* strip trailing white-spaces */
					while (value_len > 0 && (value[value_len - 1] == ' ' || value[value_len - 1] == '\t')) {
						--value_len;
					}

						if (!current_header) {
						buffer_append_string_len(current_header->value, value, value_len);
						/* process previous header */
						if (current_header) {
							data_string *ds = current_header;
							current_header = NULL;

						key = con->parse_request->ptr + first;

						if (NULL == (current_header = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
							current_header = data_string_init();
						}

						buffer_copy_string_len(current_header->key, key, key_len);
						buffer_copy_string_len(current_header->value, value, value_len);
	/* process last header */
	if (current_header) {
		data_string* ds = current_header;
		current_header = NULL;
		if (!parse_single_header(srv, con, &state, ds)) {
			/* parse_single_header should already have logged it */
			goto failure;
		}
	}

	if (current_header) current_header->free((data_unset *)current_header);