libc: fix page fault in socket_fs_plugin

In the error case of socket_fs_accept() the Unconfirmed utility was
incompletely applied with the result of executing the cleanup routines
in the wrong order.

Fixes #4417
This commit is contained in:
Johannes Schlatow 2022-02-10 13:47:14 +01:00 committed by Norman Feske
parent 50c7104e22
commit 392a2cba66
2 changed files with 1 additions and 45 deletions

View File

@ -1,41 +0,0 @@
/*
* \brief Utility to automatically unroll unconfirmed operations
* \author Christian Helmuth
* \date 2020-07-31
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _LIBC__INTERNAL__UNCONFIRMED_H_
#define _LIBC__INTERNAL__UNCONFIRMED_H_
namespace Libc {
template <typename> struct Unconfirmed;
template <typename FUNC>
Unconfirmed<FUNC> make_unconfirmed(FUNC const &cleanup)
{
return { cleanup };
}
};
template <typename FUNC>
struct Libc::Unconfirmed
{
bool confirmed { false };
FUNC const &cleanup;
Unconfirmed(FUNC const &cleanup) : cleanup(cleanup) { }
~Unconfirmed() { if (!confirmed) cleanup(); }
void confirm() { confirmed = true; }
};
#endif /* _LIBC__INTERNAL__UNCONFIRMED_H_ */

View File

@ -43,7 +43,6 @@
#include <internal/init.h>
#include <internal/suspend.h>
#include <internal/pthread.h>
#include <internal/unconfirmed.h>
namespace Libc {
@ -604,12 +603,11 @@ extern "C" int socket_fs_accept(int libc_fd, sockaddr *addr, socklen_t *addrlen)
return Errno(EMFILE);
}
auto _accept_fd = make_unconfirmed([&] { file_descriptor_allocator()->free(accept_fd); });
if (addr && addrlen) {
Socket_fs::Remote_functor func(*accept_context, false);
int ret = read_sockaddr_in(func, (sockaddr_in *)addr, addrlen);
if (ret == -1) {
file_descriptor_allocator()->free(accept_fd);
Libc::Allocator alloc { };
destroy(alloc, accept_context);
return ret;
@ -619,7 +617,6 @@ extern "C" int socket_fs_accept(int libc_fd, sockaddr *addr, socklen_t *addrlen)
/* inherit the O_NONBLOCK flag if set */
accept_context->fd_flags(listen_context->fd_flags());
_accept_fd.confirm();
return accept_fd->libc_fd;
}