The branch main has been updated by brooks: URL: https://cgit.FreeBSD.org/src/commit/?id=e17d7ab869bbfe3fa5a7da4b74d9f4fa51a0d69f
commit e17d7ab869bbfe3fa5a7da4b74d9f4fa51a0d69f Author: Brooks Davis <[email protected]> AuthorDate: 2026-01-23 10:35:55 +0000 Commit: Brooks Davis <[email protected]> CommitDate: 2026-01-23 10:35:55 +0000 xdr_string: don't leak strings with xdr_free Historically (and in a small amount of older software such as OpenAFS), developers would attempt to free XDR strings with xdr_free((xdrproc_t)xdr_string, &string) This resulted in xdr_free calling xdr_string with only two intentional arguments and whatever was left in the third argument register. If the register held a sufficently small number, xdr_string would return FALSE and not free the string (no one checks the return values). Software should instead free strings with: xdr_free((xdrproc_t)xdr_wrapstring, &string) Because buggy software exists in the wild, act as though xdr_wrapstring was used in the XDR_FREE case and plug these leaks. Reviewed by: kib MFC after: 3 days Effort: CHERI upstreaming Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D54825 --- lib/libc/xdr/xdr.c | 7 +++++++ sys/xdr/xdr.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/lib/libc/xdr/xdr.c b/lib/libc/xdr/xdr.c index 59a843405abf..47aafea4bc30 100644 --- a/lib/libc/xdr/xdr.c +++ b/lib/libc/xdr/xdr.c @@ -696,6 +696,13 @@ xdr_string(XDR *xdrs, char **cpp, u_int maxsize) if (sp == NULL) { return(TRUE); /* already free */ } + /* + * XXX: buggy software may call this without a third + * argument via xdr_free(). Ignore maxsize since it may + * be invalid. Otherwise, if it's very small, we might + * fail to free the string. + */ + maxsize = RPC_MAXDATASIZE; /* FALLTHROUGH */ case XDR_ENCODE: size = strlen(sp); diff --git a/sys/xdr/xdr.c b/sys/xdr/xdr.c index 81d238ebf19f..f983a474abdd 100644 --- a/sys/xdr/xdr.c +++ b/sys/xdr/xdr.c @@ -620,6 +620,13 @@ xdr_string(XDR *xdrs, char **cpp, u_int maxsize) if (sp == NULL) { return(TRUE); /* already free */ } + /* + * XXX: buggy software may call this without a third + * argument via xdr_free(). Ignore maxsize since it may + * be invalid. Otherwise, if it's very small, we might + * fail to free the string. + */ + maxsize = RPC_MAXDATASIZE; /* FALLTHROUGH */ case XDR_ENCODE: size = strlen(sp);
