Fix memleak and double free in varlink methods (#43431)

This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-08-19 10:58:40 +02:00
committed by GitHub
11 changed files with 69 additions and 27 deletions
+4
View File
@@ -142,6 +142,10 @@ static int follow_state_setup(sd_varlink *link, sd_journal *_j /* donated! */) {
assert(link);
assert(j);
/* The varlink connection already requested the follow mode. Refusing. */
if (sd_varlink_get_userdata(link))
return -EBUSY;
sd_varlink_server *server = ASSERT_PTR(sd_varlink_get_server(link));
sd_event *event = ASSERT_PTR(sd_varlink_server_get_event(server));
+2 -2
View File
@@ -1873,7 +1873,7 @@ static int manager_schedule_sync(Manager *m, int priority) {
}
if (!m->event || sd_event_get_state(m->event) == SD_EVENT_FINISHED) {
/* Shutting down the server? Let's sync immediately. */
/* Shutting down the manager? Let's sync immediately. */
manager_sync(m, /* wait= */ false);
return 0;
}
@@ -2133,7 +2133,7 @@ int manager_unlink_seqnum_file(Manager *m, const char *fname) {
static bool manager_is_idle(Manager *m) {
assert(m);
/* The server for the main namespace is never idle */
/* The manager for the main namespace is never idle */
if (!m->namespace)
return false;
+3 -3
View File
@@ -687,7 +687,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
if (revents != EPOLLIN)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Got invalid event from epoll for stdout server fd: %" PRIx32,
"Got invalid event from epoll for stdout fd: %" PRIx32,
revents);
fd = accept4(m->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
@@ -926,11 +926,11 @@ int manager_open_stdout_socket(Manager *m, const char *stdout_socket) {
r = sd_event_add_io(m->event, &m->stdout_event_source, m->stdout_fd, EPOLLIN, stdout_stream_new, m);
if (r < 0)
return log_error_errno(r, "Failed to add stdout server fd to event source: %m");
return log_error_errno(r, "Failed to add stdout fd to event source: %m");
r = sd_event_source_set_priority(m->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+5);
if (r < 0)
return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
return log_error_errno(r, "Failed to adjust priority of stdout event source: %m");
return 0;
}
+1 -1
View File
@@ -17,7 +17,7 @@
#include "socket-netlink.h"
#include "time-util.h"
StreamSyncReq *stream_sync_req_free(StreamSyncReq *ssr) {
StreamSyncReq* stream_sync_req_free(StreamSyncReq *ssr) {
if (!ssr)
return NULL;
+1 -1
View File
@@ -37,7 +37,7 @@ typedef struct SyncReq {
unsigned boottime_prioq_idx;
} SyncReq;
StreamSyncReq *stream_sync_req_free(StreamSyncReq *ssr);
StreamSyncReq* stream_sync_req_free(StreamSyncReq *ssr);
DEFINE_TRIVIAL_CLEANUP_FUNC(StreamSyncReq*, stream_sync_req_free);
void stream_sync_req_advance_revalidate(StreamSyncReq *ssr, size_t p);
+10 -3
View File
@@ -40,11 +40,17 @@ static int vl_method_synchronize(sd_varlink *link, sd_json_variant *parameters,
{}
};
Manager *m = ASSERT_PTR(userdata);
int r;
assert(link);
/* Here, userdata may not be a pointer to the Manager object. Obtain the manager from the server. */
Manager *m = ASSERT_PTR(sd_varlink_server_get_userdata(sd_varlink_get_server(link)));
/* The varlink connection already requested to sync journals. Refusing. */
if (sd_varlink_get_userdata(link) != m)
return -EBUSY;
r = sd_varlink_dispatch(link, parameters, dispatch_table, &offline);
if (r != 0)
return r;
@@ -168,10 +174,11 @@ static void vl_disconnect(sd_varlink_server *server, sd_varlink *link, void *use
void *u = sd_varlink_get_userdata(link);
if (u != m) {
/* If this is a Varlink connection that does not have the Server object as userdata, then it has a SyncReq object instead. Let's finish it. */
/* If this is a Varlink connection that does not have the Manager object as userdata, then
* it has a SyncReq object instead. Let's finish it. */
SyncReq *req = u;
sd_varlink_set_userdata(link, m); /* reinstall server object */
sd_varlink_set_userdata(link, m); /* reinstall the manager object */
sync_req_free(req);
}
+4
View File
@@ -236,6 +236,10 @@ static int vl_method_mute(
assert(link);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
/* Refuse multiple requests per connection. */
if (sd_varlink_get_userdata(link))
return -EBUSY;
_cleanup_free_ Context *nc = new(Context, 1);
if (!nc)
return -ENOMEM;
@@ -169,6 +169,10 @@ int vl_method_list_candidate_devices(
_cleanup_(list_candidate_devices_context_freep) ListCandidateDevicesContext *c = NULL;
if (p.subscribe) {
/* Refuse multiple requests per connection. */
if (sd_varlink_get_userdata(link))
return -EBUSY;
/* Start the monitor *before* the initial enumeration so we don't lose events that fire
* during the enumeration window. Duplicate add events for the same device are
* legitimate and documented; clients upsert by identifier. */
+24 -17
View File
@@ -726,27 +726,30 @@ static int mdns_next_query_schedule(sd_event_source *s, uint64_t usec, void *use
assert(userdata);
assert_se(sb = dns_service_browser_ref(userdata));
/* Enable the answer from the cache for the very first query */
if (sb->delay == 0)
SET_FLAG(sb->flags, SD_RESOLVED_NO_CACHE, false);
/* If the varlink connection has a userdata, then that means the previous query has not been finished. */
if (!sd_varlink_get_userdata(sb->link)) {
/* Set the flag indicating that the query is continuous.
* RFC 6762 Section 5.2 outlines timing requirements for continuous queries.
*/
sb->flags |= SD_RESOLVED_QUERY_CONTINUOUS;
/* Enable the answer from the cache for the very first query */
if (sb->delay == 0)
SET_FLAG(sb->flags, SD_RESOLVED_NO_CACHE, false);
r = dns_query_new(sb->manager, &q, sb->question_utf8, sb->question_idna, NULL, sb->ifindex, sb->flags);
if (r < 0)
return log_error_errno(r, "Failed to create new DNS query: %m");
/* Set the flag indicating that the query is continuous.
* RFC 6762 Section 5.2 outlines timing requirements for continuous queries. */
sb->flags |= SD_RESOLVED_QUERY_CONTINUOUS;
q->complete = mdns_browse_service_query_complete;
q->service_browser_request = dns_service_browser_ref(sb);
q->varlink_request = sd_varlink_ref(sb->link);
sd_varlink_set_userdata(sb->link, q);
r = dns_query_new(sb->manager, &q, sb->question_utf8, sb->question_idna, NULL, sb->ifindex, sb->flags);
if (r < 0)
return log_error_errno(r, "Failed to create new DNS query: %m");
r = dns_query_go(q);
if (r < 0)
return log_error_errno(r, "Failed to send DNS query: %m");
q->complete = mdns_browse_service_query_complete;
q->service_browser_request = dns_service_browser_ref(sb);
q->varlink_request = sd_varlink_ref(sb->link);
sd_varlink_set_userdata(sb->link, q);
r = dns_query_go(q);
if (r < 0)
return log_error_errno(r, "Failed to send DNS query: %m");
}
/* Calculate the next query delay */
sb->delay = mdns_calculate_next_query_delay(sb->delay);
@@ -811,6 +814,10 @@ int dns_subscribe_browse_service(
assert(m);
assert(link);
/* Refuse multiple requests. */
if (hashmap_contains(m->dns_service_browsers, link))
return -EBUSY;
if (ifindex < 0)
return sd_varlink_error_invalid_parameter_name(link, "ifindex");
+12
View File
@@ -363,6 +363,9 @@ static int vl_method_resolve_hostname(sd_varlink *link, sd_json_variant *paramet
assert(link);
if (sd_varlink_get_userdata(link))
return -EBUSY;
m = sd_varlink_server_get_userdata(sd_varlink_get_server(link));
assert(m);
@@ -490,6 +493,9 @@ static int vl_method_resolve_address(sd_varlink *link, sd_json_variant *paramete
assert(link);
if (sd_varlink_get_userdata(link))
return -EBUSY;
m = sd_varlink_server_get_userdata(sd_varlink_get_server(link));
assert(m);
@@ -973,6 +979,9 @@ static int vl_method_resolve_service(sd_varlink* link, sd_json_variant* paramete
assert(link);
if (sd_varlink_get_userdata(link))
return -EBUSY;
m = sd_varlink_server_get_userdata(sd_varlink_get_server(link));
assert(m);
@@ -1124,6 +1133,9 @@ static int vl_method_resolve_record(sd_varlink *link, sd_json_variant *parameter
assert(link);
if (sd_varlink_get_userdata(link))
return -EBUSY;
m = ASSERT_PTR(sd_varlink_server_get_userdata(sd_varlink_get_server(link)));
if (FLAGS_SET(flags, SD_VARLINK_METHOD_ONEWAY))
+4
View File
@@ -1822,6 +1822,10 @@ static int vl_method_list_candidate_devices(
assert(link);
/* Refuse multiple requests */
if (sd_varlink_get_userdata(link))
return -EBUSY;
sd_varlink_server *varlink_server = sd_varlink_get_server(link);
sd_event *event = sd_varlink_server_get_event(varlink_server);
Hashmap **polkit_registry = ASSERT_PTR(sd_varlink_server_get_userdata(varlink_server));