Re: ypldap: tighten up parsing of paged search controls

Jan Klemkow <[email protected]>
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
On Fri, Jul 03, 2026 at 05:10:54PM +1000, Jonathan Matthew wrote:
> Several of the swival reports related to the code in aldap.c for
> parsing the paging control in ldap search results, which is overly
> trusting that the response from the server will be properly formed.
> 
> I hacked up an ldap proxy to make it send bad paging controls back to
> the client and that pointed out a few more checks we should add in
> addition to what the swival reports suggested.  The same diff can also
> be applied to the copies of aldap.c in libexec/login_ldap/ and
> usr.bin/ldap/.
> 
> If it can't parse the paging control, ypldap will stop the search
> there, so it'll only have the first page of results.
> 
> ok?

One comment about formatting in line.

But, anyway OK jan@

> Index: aldap.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ypldap/aldap.c,v
> diff -u -p -r1.50 aldap.c
> --- aldap.c	30 Jun 2026 18:20:28 -0000	1.50
> +++ aldap.c	3 Jul 2026 07:01:49 -0000
> @@ -387,7 +387,7 @@ aldap_parse(struct aldap *ldap)
>  	unsigned int		 type;
>  	long long		 msgid = 0;
>  	struct aldap_message	*m;
> -	struct ber_element	*a = NULL, *ep;
> +	struct ber_element	*a = NULL, *ep, *ctl;
>  	char			 rbuf[512];
>  	int			 ret, retry;
>  
> @@ -454,9 +454,15 @@ aldap_parse(struct aldap *ldap)
>  		if (m->msg->be_sub) {
>  			for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) {
>  				ober_scanf_elements(ep, "t", &class, &type);
> -				if (class == 2 && type == 0)
> -					m->page = aldap_parse_page_control(ep->be_sub->be_sub,
> -					    ep->be_sub->be_sub->be_len);
> +				if (class == 2 && type == 0) {
> +					if (ep->be_sub == NULL ||
> +					    ep->be_sub->be_sub == NULL)
> +						goto parsefail;
> +
> +					ctl = ep->be_sub->be_sub;
> +					m->page = aldap_parse_page_control(ctl,
> +					    ctl->be_len);
> +				}

The ctl varibale, it not needed and doesn't improve the readability.
I would favor the following format:

				if (class != 2 || type != 0)
					continue;

				if (ep->be_sub == NULL ||
				    ep->be_sub->be_sub == NULL)
					goto parsefail;

				m->page = aldap_parse_page_control(
				    ep->be_sub->be_sub,
				    ep->be_sub->be_sub->be_len);

>  			}
>  		} else
>  			m->page = NULL;
> @@ -492,36 +498,39 @@ aldap_parse_page_control(struct ber_elem
>  	char *oid, *s;
>  	char *encoded;
>  	struct ber b;
> -	struct ber_element *elm;
> -	struct aldap_page_control *page;
> +	struct ber_element *elm = NULL;
> +	struct aldap_page_control *page = NULL;
>  
>  	b.br_wbuf = NULL;
> -	ober_scanf_elements(control, "ss", &oid, &encoded);
> +	if (ober_scanf_elements(control, "ss", &oid, &encoded) == -1)
> +		goto failed;
> +
>  	ober_set_readbuf(&b, encoded, control->be_next->be_len);
>  	elm = ober_read_elements(&b, NULL);
> +	if (elm == NULL)
> +		goto failed;
>  
> -	if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
> -		if (elm != NULL)
> -			ober_free_elements(elm);
> -		ober_free(&b);
> -		return NULL;
> -	}
> +	if ((page = malloc(sizeof(struct aldap_page_control))) == NULL)
> +		goto failed;

Good point.  Its a much better version than my suggested fix here:
https://marc.info/?l=openbsd-tech&m=178307924516706

> +
> +	if (ober_scanf_elements(elm->be_sub, "is", &page->size, &s) == -1)
> +		goto failed;
>  
> -	ober_scanf_elements(elm->be_sub, "is", &page->size, &s);
>  	page->cookie_len = elm->be_sub->be_next->be_len;
> +	if ((page->cookie = malloc(page->cookie_len)) == NULL)
> +		goto failed;
>  
> -	if ((page->cookie = malloc(page->cookie_len)) == NULL) {
> -		if (elm != NULL)
> -			ober_free_elements(elm);
> -		ober_free(&b);
> -		free(page);
> -		return NULL;
> -	}
>  	memcpy(page->cookie, s, page->cookie_len);
>  
>  	ober_free_elements(elm);
>  	ober_free(&b);
>  	return page;
> + failed:
> +	LDAP_DEBUG("couldn't parse paging control", control);
> +	ober_free_elements(elm);
> +	ober_free(&b);
> +	free(page);
> +	return NULL;
>  }
>  
>  void
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.