CVE-2023-31470 (C, published 2023-04-28T21:15Z)
Description: value: SmartDNS through 41 before 56d0332 allows an out-of-bounds write because of a stack-based buffer overflow in the _dns_encode_domain function in the dns.c file, via a crafted DNS request.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-787 \u2014 Out-of-bounds Write
The product writes data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/pymumu/smartdns
Files changed:
src/dns.c
src/dns.h
src/util.c
Commit message: dns: fix crash issue


Vulnerable code:
int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, void *data, int data_len)
	int target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1;
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_A_LEN], int addr_num)
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_AAAA_LEN], int addr_num)
struct dns_https_param *dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl,
													int *priority, char *target, int target_size)
		return NULL;
		return NULL;
		return NULL;
		return NULL;
	if (rr_len <= 0) {
		return NULL;
	return (struct dns_https_param *)data;
	param = dns_get_HTTPS_svcparm_start(rrs, domain, DNS_MAX_CNAME_LEN, &ttl, &priority, target, DNS_MAX_CNAME_LEN);
	if (param == NULL) {
		tlog(TLOG_ERROR, "get https param failed.");
		return -1;
int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, void *data, int data_len);
int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port);
int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn);
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_A_LEN], int addr_num);
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_AAAA_LEN], int addr_num);
struct dns_https_param *dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl,
													int *priority, char *target, int target_size);
				p = dns_get_HTTPS_svcparm_start(rrs, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
				if (p == NULL) {
						printf("  HTTPS: alpn: %s\n", p->value);

Fixed code:
			if (_dns_left_len(context) < 2) {
				return -1;
			}

	if (_dns_left_len(context) < 1) {
		return -1;
	}

int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, const void *data, int data_len)
	/* NO SVC keys, reset ptr */
	if (len <= 14) {
		rr_nested->context.ptr = rr_nested->rr_start;
		return 0;
	}

	int target_len = 0;
	if (target == NULL) {
		target = "";
	}

	target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1;
int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn, int alpn_len)
{
	if (_dns_left_len(&svcparam->context) < 2 + 2 + alpn_len) {
		return -1;
	}

	unsigned short value = DNS_HTTPS_T_ALPN;
	dns_add_rr_nested_memcpy(svcparam, &value, 2);

	value = alpn_len;
	dns_add_rr_nested_memcpy(svcparam, &value, 2);
	dns_add_rr_nested_memcpy(svcparam, alpn, alpn_len);

	return 0;
}

int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num)

int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num)
int dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, struct dns_https_param **https_param, char *domain, int maxsize,
								int *ttl, int *priority, char *target, int target_size)
		return -1;
		return -1;
		return -1;
		return -1;
	if (rr_len < 0) {
		return -1;
	}

	if (rr_len == 0) {
		*https_param = NULL;
		return 0;
	*https_param = (struct dns_https_param *)data;

	return 0;
	ret =
		dns_get_HTTPS_svcparm_start(rrs, &param, domain, DNS_MAX_CNAME_LEN, &ttl, &priority, target, DNS_MAX_CNAME_LEN);
	if (ret < 0) {
		tlog(TLOG_DEBUG, "get https param failed.");
		return 0;
	qtype = DNS_T_HTTPS;
	qclass = DNS_C_IN;

		if (param->len + 4 > _dns_left_len(context)) {
			return -1;
		}

	if (_dns_left_len(context) < 2) {
		return -1;
	}

#define DNS_MAX_ALPN_LEN 32
#define DNS_MAX_ECH_LEN 256
int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, const void *data, int data_len);
/* the key must be added in orders, or dig will report FORMERR */
/* key 1, alph */
int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn, int alpn_len);
/* key 2, no default alph */
/* key 3, port */
int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port);
/* key 4, ipv4 */
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num);
/* key 5, ech */
/* key 6, ipv6*/
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num);
int dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, struct dns_https_param **https_param, char *domain, int maxsize,
								int *ttl, int *priority, char *target, int target_size);
				int ret = 0;
				ret = dns_get_HTTPS_svcparm_start(rrs, &p, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
				if (ret != 0) {
						char alph[64] = {0};
						int total_alph_len = 0;
						char *ptr = (char *)p->value;
						do {
							int alphlen = *ptr;
							memcpy(alph + total_alph_len, ptr + 1, alphlen);
							total_alph_len += alphlen;
							ptr += alphlen + 1;
							alph[total_alph_len] = ',';
							total_alph_len++;
							alph[total_alph_len] = ' ';
							total_alph_len++;
						} while (ptr - (char *)p->value < p->len);
						if (total_alph_len > 2) {
							alph[total_alph_len - 2] = '\0';
						}
						printf("  HTTPS: alpn: %s\n", alph);