Skip to content

Commit f5ec179

Browse files
committed
_ebpf_object_load_native: wait until service is deleted on error
ebpf-go loads native images via ebpf_object_load_native_by_fds. Contrary to ebpf_object_load_native this function requires the caller to provide memory for map and program fds. If the caller doesn't provide enough space, EBPF_NO_MEMORY is returned along with a sizing hint. The caller is expected to retry with a larger buffer. This behaviour currently breaks for two reasons: first, the error recovery path of _ebpf_object_load_native stops and deletes the service, but does not wait for deletion to complete. This is a problem because each native image can currently only be loaded once. This causes an error when ebpf-go retries the load with larger buffers. Second, the check which issues the EBPF_NO_MEMORY result happens at a point where we can't reliably delete the service since we don't know its name. Fix this by waiting for a service to be deleted on the error path and by pushing the EBPF_NO_MEMORY condition down into _ebpf_object_load_native. The latter requires some creative semantics for count_of_maps and count_of_programs: they now specify the maximum number the caller is willing to accept.
1 parent 49f7e99 commit f5ec179

File tree

4 files changed

+68
-59
lines changed

4 files changed

+68
-59
lines changed

libs/api/ebpf_api.cpp

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef unsigned char boolean;
3838

3939
#include <algorithm>
4040
#include <codecvt>
41+
#include <cstdint>
4142
#include <fcntl.h>
4243
#include <io.h>
4344
#include <mutex>
@@ -3755,9 +3756,9 @@ _Must_inspect_result_ ebpf_result_t
37553756
_ebpf_object_load_native(
37563757
_In_z_ const char* file_name,
37573758
_Out_ ebpf_handle_t* native_module_handle,
3758-
_Out_ size_t* count_of_maps,
3759+
_Inout_ size_t* count_of_maps,
37593760
_Outptr_result_buffer_all_maybenull_(*count_of_maps) ebpf_handle_t** map_handles,
3760-
_Out_ size_t* count_of_programs,
3761+
_Inout_ size_t* count_of_programs,
37613762
_Outptr_result_buffer_all_maybenull_(*count_of_programs) ebpf_handle_t** program_handles) NO_EXCEPT_TRY
37623763
{
37633764
EBPF_LOG_ENTRY();
@@ -3779,11 +3780,11 @@ _ebpf_object_load_native(
37793780
std::wstring service_path(SERVICE_PATH_PREFIX);
37803781
std::wstring parameters_path(PARAMETERS_PATH_PREFIX);
37813782
ebpf_protocol_buffer_t request_buffer;
3783+
size_t real_count_of_maps = 0;
3784+
size_t real_count_of_programs = 0;
37823785

37833786
*native_module_handle = ebpf_handle_invalid;
3784-
*count_of_maps = 0;
37853787
*map_handles = nullptr;
3786-
*count_of_programs = 0;
37873788
*program_handles = nullptr;
37883789

37893790
if (UuidCreate(&service_name_guid) != RPC_S_OK) {
@@ -3852,7 +3853,7 @@ _ebpf_object_load_native(
38523853

38533854
service_path = service_path + service_name.c_str();
38543855
result = _load_native_module(
3855-
service_path, &provider_module_id, native_module_handle, count_of_maps, count_of_programs);
3856+
service_path, &provider_module_id, native_module_handle, &real_count_of_maps, &real_count_of_programs);
38563857
if (result != EBPF_SUCCESS) {
38573858
EBPF_LOG_MESSAGE_WSTRING(
38583859
EBPF_TRACELOG_LEVEL_ERROR,
@@ -3862,8 +3863,19 @@ _ebpf_object_load_native(
38623863
goto Done;
38633864
}
38643865

3866+
if (*count_of_maps < real_count_of_maps || *count_of_programs < real_count_of_programs) {
3867+
result = EBPF_NO_MEMORY;
3868+
}
3869+
3870+
*count_of_maps = real_count_of_maps;
3871+
*count_of_programs = real_count_of_programs;
3872+
3873+
if (result != EBPF_SUCCESS) {
3874+
goto Done;
3875+
}
3876+
38653877
result = _load_native_programs(
3866-
&provider_module_id, *count_of_maps, map_handles, *count_of_programs, program_handles);
3878+
&provider_module_id, real_count_of_maps, map_handles, real_count_of_programs, program_handles);
38673879
if (result != EBPF_SUCCESS) {
38683880
EBPF_LOG_MESSAGE_STRING(
38693881
EBPF_TRACELOG_LEVEL_ERROR,
@@ -3882,14 +3894,15 @@ _ebpf_object_load_native(
38823894

38833895
Done:
38843896
if (result != EBPF_SUCCESS) {
3885-
_ebpf_free_handles(*count_of_maps, *map_handles);
3886-
_ebpf_free_handles(*count_of_programs, *program_handles);
3897+
_ebpf_free_handles(real_count_of_maps, *map_handles);
3898+
_ebpf_free_handles(real_count_of_programs, *program_handles);
38873899

38883900
if (*native_module_handle != ebpf_handle_invalid) {
38893901
Platform::CloseHandle(*native_module_handle);
38903902
}
38913903

3892-
Platform::_stop_service(service_handle);
3904+
Platform::_stop_and_delete_service(service_handle, service_name.c_str());
3905+
EBPF_RETURN_RESULT(result);
38933906
}
38943907

38953908
// Workaround: Querying service status hydrates service reference count in SCM.
@@ -3926,29 +3939,17 @@ ebpf_object_load_native_by_fds(
39263939
ebpf_handle_t native_module_handle;
39273940
ebpf_handle_t* map_handles = nullptr;
39283941
ebpf_handle_t* program_handles = nullptr;
3929-
size_t real_count_of_maps = 0;
3930-
size_t real_count_of_programs = 0;
39313942

39323943
ebpf_result_t result = _ebpf_object_load_native(
3933-
file_name, &native_module_handle, &real_count_of_maps, &map_handles, &real_count_of_programs, &program_handles);
3944+
file_name, &native_module_handle, count_of_maps, &map_handles, count_of_programs, &program_handles);
39343945
if (result != EBPF_SUCCESS) {
39353946
EBPF_RETURN_RESULT(result);
39363947
}
39373948

39383949
Platform::CloseHandle(native_module_handle);
39393950

3940-
if (*count_of_maps < real_count_of_maps || *count_of_programs < real_count_of_programs) {
3941-
*count_of_maps = real_count_of_maps;
3942-
*count_of_programs = real_count_of_programs;
3943-
_ebpf_free_handles(real_count_of_maps, map_handles);
3944-
_ebpf_free_handles(real_count_of_programs, program_handles);
3945-
EBPF_RETURN_RESULT(EBPF_NO_MEMORY);
3946-
}
3947-
3948-
*count_of_maps = real_count_of_maps;
3949-
*count_of_programs = real_count_of_programs;
3950-
3951-
for (int i = 0; i < real_count_of_maps; i++) {
3951+
__analysis_assume(*count_of_maps == 0 || map_handles != nullptr);
3952+
for (int i = 0; i < *count_of_maps; i++) {
39523953
map_fds[i] = _create_file_descriptor_for_handle(map_handles[i]);
39533954
if (map_fds[i] == ebpf_fd_invalid) {
39543955
result = EBPF_NO_MEMORY;
@@ -3957,7 +3958,8 @@ ebpf_object_load_native_by_fds(
39573958
}
39583959
}
39593960

3960-
for (int i = 0; i < real_count_of_programs; i++) {
3961+
__analysis_assume(*count_of_programs == 0 || program_handles != nullptr);
3962+
for (int i = 0; i < *count_of_programs; i++) {
39613963
program_fds[i] = _create_file_descriptor_for_handle(program_handles[i]);
39623964
if (program_fds[i] == ebpf_fd_invalid) {
39633965
result = EBPF_NO_MEMORY;
@@ -3968,7 +3970,7 @@ ebpf_object_load_native_by_fds(
39683970

39693971
if (result != EBPF_SUCCESS) {
39703972
if (map_fds != nullptr) {
3971-
for (int i = 0; i < real_count_of_maps; i++) {
3973+
for (int i = 0; i < *count_of_maps; i++) {
39723974
if (map_fds[i] != ebpf_fd_invalid) {
39733975
Platform::_close(map_fds[i]);
39743976
map_fds[i] = ebpf_fd_invalid;
@@ -3977,7 +3979,7 @@ ebpf_object_load_native_by_fds(
39773979
}
39783980

39793981
if (program_fds != nullptr) {
3980-
for (int i = 0; i < real_count_of_programs; i++) {
3982+
for (int i = 0; i < *count_of_programs; i++) {
39813983
if (program_fds[i] != ebpf_fd_invalid) {
39823984
Platform::_close(program_fds[i]);
39833985
program_fds[i] = ebpf_fd_invalid;
@@ -3986,8 +3988,8 @@ ebpf_object_load_native_by_fds(
39863988
}
39873989
}
39883990

3989-
_ebpf_free_handles(real_count_of_maps, map_handles);
3990-
_ebpf_free_handles(real_count_of_programs, program_handles);
3991+
_ebpf_free_handles(*count_of_maps, map_handles);
3992+
_ebpf_free_handles(*count_of_programs, program_handles);
39913993

39923994
EBPF_RETURN_RESULT(result);
39933995
}
@@ -4006,8 +4008,8 @@ _ebpf_program_load_native(
40064008
ebpf_handle_t native_module_handle = ebpf_handle_invalid;
40074009
ebpf_handle_t* map_handles = nullptr;
40084010
ebpf_handle_t* program_handles = nullptr;
4009-
size_t count_of_maps = 0;
4010-
size_t count_of_programs = 0;
4011+
size_t count_of_maps = SIZE_MAX;
4012+
size_t count_of_programs = SIZE_MAX;
40114013

40124014
try {
40134015
result = _ebpf_object_load_native(

libs/thunk/mock/mock.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,13 @@ _query_service_status(SC_HANDLE service_handle, _Inout_ SERVICE_STATUS* status)
180180
}
181181

182182
uint32_t
183-
_stop_service(SC_HANDLE service_handle)
183+
_stop_and_delete_service(SC_HANDLE service_handle, const wchar_t* service_name)
184184
{
185185
// TODO: (Issue# 852) Just a stub currently in order to compile.
186186
// Will be replaced by a proper mock.
187187

188188
UNREFERENCED_PARAMETER(service_handle);
189+
UNREFERENCED_PARAMETER(service_name);
189190
return ERROR_SUCCESS;
190191
}
191192

libs/thunk/platform.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ uint32_t
7979
_delete_service(SC_HANDLE service_handle);
8080

8181
uint32_t
82-
_stop_service(SC_HANDLE service_handle);
82+
_stop_and_delete_service(SC_HANDLE service_handle, const wchar_t* service_name);
8383

8484
bool
8585
_query_service_status(SC_HANDLE service_handle, _Inout_ SERVICE_STATUS* status);

libs/thunk/windows/platform.cpp

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -182,33 +182,36 @@ _update_registry_value(
182182
return error;
183183
}
184184

185-
static bool
186-
_check_service_state(SC_HANDLE service_handle, unsigned long expected_state, _Out_ unsigned long* final_state)
185+
static DWORD
186+
_check_service_deleted(const wchar_t* service_name)
187187
{
188188
#define MAX_RETRY_COUNT 20
189189
#define WAIT_TIME_IN_MS 500
190190

191-
int retry_count = 0;
192-
bool status = false;
193-
int error;
194-
SERVICE_STATUS service_status = {0};
191+
SC_HANDLE scm_handle = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
192+
if (scm_handle == nullptr) {
193+
return GetLastError();
194+
}
195195

196-
// Query service state.
197-
while (retry_count < MAX_RETRY_COUNT) {
198-
if (!QueryServiceStatus(service_handle, &service_status)) {
196+
DWORD error = ERROR_SERVICE_REQUEST_TIMEOUT;
197+
for (int retry_count = 0; retry_count < MAX_RETRY_COUNT; retry_count++) {
198+
SC_HANDLE service_handle = OpenService(scm_handle, service_name, SERVICE_QUERY_STATUS);
199+
200+
if (service_handle == nullptr) {
199201
error = GetLastError();
200202
break;
201-
} else if (service_status.dwCurrentState == expected_state) {
202-
status = true;
203-
break;
204-
} else {
205-
Sleep(WAIT_TIME_IN_MS);
206-
retry_count++;
207203
}
204+
205+
CloseServiceHandle(service_handle);
206+
Sleep(WAIT_TIME_IN_MS);
207+
}
208+
209+
if (error == ERROR_SERVICE_DOES_NOT_EXIST) {
210+
error = ERROR_SUCCESS;
208211
}
209212

210-
*final_state = service_status.dwCurrentState;
211-
return status;
213+
CloseServiceHandle(scm_handle);
214+
return error;
212215
}
213216

214217
uint32_t
@@ -285,27 +288,30 @@ _delete_service(SC_HANDLE service_handle)
285288
}
286289

287290
uint32_t
288-
_stop_service(SC_HANDLE service_handle)
291+
_stop_and_delete_service(SC_HANDLE service_handle, const wchar_t* service_name)
289292
{
290293
SERVICE_STATUS status;
291-
bool service_stopped = false;
292-
unsigned long service_state;
293-
int error = ERROR_SUCCESS;
294+
DWORD error = ERROR_SUCCESS;
294295

295296
if (service_handle == nullptr) {
296297
return EBPF_INVALID_ARGUMENT;
297298
}
298299

299300
if (!ControlService(service_handle, SERVICE_CONTROL_STOP, &status)) {
300-
return GetLastError();
301+
error = GetLastError();
302+
if (error != ERROR_SERVICE_NOT_ACTIVE) {
303+
return error;
304+
}
305+
306+
// Service is already stopped.
301307
}
302308

303-
service_stopped = _check_service_state(service_handle, SERVICE_STOPPED, &service_state);
304-
if (!service_stopped) {
305-
error = ERROR_SERVICE_REQUEST_TIMEOUT;
309+
error = _delete_service(service_handle);
310+
if (error != ERROR_SUCCESS) {
311+
return error;
306312
}
307313

308-
return error;
314+
return _check_service_deleted(service_name);
309315
}
310316

311317
} // namespace Platform

0 commit comments

Comments
 (0)