-
Notifications
You must be signed in to change notification settings - Fork 7.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ZOOKEEPER-4020: Fix memory leak from ssl cert in c client #2209
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not look right. I think it is zookeeper_close
's job to free cert->ca
.
@kezhuw Please review. |
zhandle_t *zookeeper_init_ssl(const char *host, const char *cert, watcher_fn watcher,
int recv_timeout, const clientid_t *clientid, void *context, int flags)
{
zcert_t zcert;
zcert.certstr = strdup(cert);
zcert.ca = strtok(strdup(cert), ",");
zcert.cert = strtok(NULL, ",");
zcert.key = strtok(NULL, ",");
zcert.passwd = strtok(NULL, ",");
return zookeeper_init_internal(host, watcher, recv_timeout, clientid, context, flags, NULL, &zcert, NULL);
} After checking above code, I suggest we fix like following. - zcert.ca = strtok(strdup(cert), ",");
+ zcert.ca = strtok(zcert.certstr, ","); Given the "Possible implementation" in https://en.cppreference.com/w/cpp/string/byte/strtok and also after evaluting |
@kezhuw zcert.ca = strtok(strdup(cert), ","); -- this will point to the first token (i.e., 'ca') in the allocated memory. |
zookeeper/zookeeper-client/zookeeper-client-c/tests/TestReadOnlyClient.cc Lines 144 to 158 in 9d52264
zcert_t zcert_new(const char *certstr) {
zcert_t zcert;
zcert.certstr = strdup(cert);
zcert.ca = strtok(zcert.certstr, ",");
zcert.cert = strtok(NULL, ",");
zcert.key = strtok(NULL, ",");
zcert.passwd = strtok(NULL, ",");
return zcert;
}
void zcert_destroy(zert_t *zcert) {
free(zcert->certstr);
}
const char* zcert_get_ca(zcert_t *zcert) {
return zcert->ca;
}
// api to retrieve `cert`, `key` and `passwd` but not `certstr`. |
void testReadOnlyWithSSL() {
certstr = "/tmp/certs/server.crt,/tmp/certs/client.crt,/tmp/certs/clientkey.pem,password" server.crt is the server's certificate stored in zcert.ca, client.crt is the client's certificate stored in zcert.cert, followed by zcert.key and zcert.password storing the client's private key and password to protect it. With the suggested change, both zcert.certstr and zcert.ca will point to 'server.crt', as follows, certstr = /tmp/certs/server.crt We should either completely remove certstr from struct zcert_t or keep it to store the SSL parameters. I strongly recommend keeping the existing implementation to store the original SSL parameters. |
Does it matter if we never use The problem of current aproach is that it will corrupt program only after zookeeper_close with cert str ",,,/tmp/certs/server.crt,/tmp/certs/client.crt,/tmp/certs/clientkey.pem,password"(be aware of the leading ",") as I think there are several ways to fix this:
I prefer to the first as it demands no api semantic changes.
If you are going to this approach, please ensure |
Quoted from #2209 (comment) |
This is the original implementation, zcert_t zcert; zcert.ca is pointing to malloc'd memory created by strdup() (https://man7.org/linux/man-pages/man3/strdup.3.html). strtok() returns a pointer to the first token in the heap allocated string (it points to the address returned by strdup() allocated in heap memory). Since zcert.ca is allocated by malloc, it has to be explicitly freed, it leads to memory leak otherwise. |
@kezhuw Awaiting your approval to merge. Please let me know if the changes look good. |
Could you test it with cert str ",,,/tmp/certs/server.crt,/tmp/certs/client.crt,/tmp/certs/clientkey.pem,password" ? I tested with an online repl, it crashed. Though I think crash is ok sometimes, but I don't think this is the case:
|
Here is the reference.
|
Fixing memory leak by freeing memory allocated by strdup in cert_t.