Browse Source

[Fix] Switch to refcounts to avoid more races

Issue: #550
Reported by: @moisseev
tags/1.2.0
Vsevolod Stakhov 8 years ago
parent
commit
2279095eb2
2 changed files with 34 additions and 36 deletions
  1. 30
    35
      src/libutil/map.c
  2. 4
    1
      src/libutil/map_private.h

+ 30
- 35
src/libutil/map.c View File



rspamd_http_connection_write_message (cbd->conn, msg, cbd->data->host, rspamd_http_connection_write_message (cbd->conn, msg, cbd->data->host,
NULL, cbd, cbd->fd, &cbd->tv, cbd->ev_base); NULL, cbd, cbd->fd, &cbd->tv, cbd->ev_base);
REF_RETAIN (cbd);
} }
else { else {
msg_err_pool ("cannot connect to %s: %s", cbd->data->host, msg_err_pool ("cannot connect to %s: %s", cbd->data->host,
strerror (errno)); strerror (errno));
REF_RELEASE (cbd);
} }
} }




msg_err_pool ("connection with http server terminated incorrectly: %s", msg_err_pool ("connection with http server terminated incorrectly: %s",
err->message); err->message);
free_http_cbdata (cbd);
REF_RELEASE (cbd);
} }


static int static int
if (cbd->out_fd == -1) { if (cbd->out_fd == -1) {
msg_err_pool ("cannot open pubkey file %s for writing: %s", msg_err_pool ("cannot open pubkey file %s for writing: %s",
fpath, strerror (errno)); fpath, strerror (errno));
free_http_cbdata (cbd);

return 0;
goto end;
} }


rspamd_http_connection_reset (cbd->conn); rspamd_http_connection_reset (cbd->conn);
write_http_request (cbd); write_http_request (cbd);


return 0;
goto end;
} }
else { else {
/* Unsinged version - just open file */ /* Unsinged version - just open file */
if (in == NULL) { if (in == NULL) {
msg_err_pool ("cannot read tempfile %s: %s", cbd->tmpfile, msg_err_pool ("cannot read tempfile %s: %s", cbd->tmpfile,
strerror (errno)); strerror (errno));
free_http_cbdata (cbd);

return 0;
goto end;
} }
} }
} }
if (fstat (cbd->out_fd, &st) == -1) { if (fstat (cbd->out_fd, &st) == -1) {
msg_err_pool ("cannot stat pubkey file %s: %s", msg_err_pool ("cannot stat pubkey file %s: %s",
fpath, strerror (errno)); fpath, strerror (errno));
free_http_cbdata (cbd);

return 0;
goto end;
} }


aux_data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, aux_data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED,
if (aux_data == MAP_FAILED) { if (aux_data == MAP_FAILED) {
msg_err_pool ("cannot map pubkey file %s: %s", msg_err_pool ("cannot map pubkey file %s: %s",
fpath, strerror (errno)); fpath, strerror (errno));
free_http_cbdata (cbd);

return 0;
goto end;
} }


cbd->pk = rspamd_pubkey_from_base32 (aux_data, st.st_size, cbd->pk = rspamd_pubkey_from_base32 (aux_data, st.st_size,
if (cbd->pk == NULL) { if (cbd->pk == NULL) {
msg_err_pool ("cannot load pubkey file %s: bad pubkey", msg_err_pool ("cannot load pubkey file %s: bad pubkey",
fpath); fpath);
free_http_cbdata (cbd);

return 0;
goto end;
} }


rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", cbd->tmpfile); rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", cbd->tmpfile);
if (cbd->out_fd == -1) { if (cbd->out_fd == -1) {
msg_err_pool ("cannot open signature file %s for writing: %s", msg_err_pool ("cannot open signature file %s for writing: %s",
fpath, strerror (errno)); fpath, strerror (errno));
free_http_cbdata (cbd);

return 0;
goto end;
} }


cbd->stage = map_load_signature; cbd->stage = map_load_signature;
rspamd_http_connection_reset (cbd->conn); rspamd_http_connection_reset (cbd->conn);
write_http_request (cbd); write_http_request (cbd);


return 0;
goto end;
} }
else if (cbd->stage == map_load_signature) { else if (cbd->stage == map_load_signature) {
/* We can now check signature */ /* We can now check signature */
if (in == NULL) { if (in == NULL) {
msg_err_pool ("cannot read tempfile %s: %s", cbd->tmpfile, msg_err_pool ("cannot read tempfile %s: %s", cbd->tmpfile,
strerror (errno)); strerror (errno));
free_http_cbdata (cbd);

return 0;
goto end;
} }


if (!rspamd_map_check_sig_pk (cbd->tmpfile, map, in, inlen, cbd->pk)) { if (!rspamd_map_check_sig_pk (cbd->tmpfile, map, in, inlen, cbd->pk)) {
free_http_cbdata (cbd);

return 0;
goto end;
} }
} }


map->uri, cbd->data->host, msg->code); map->uri, cbd->data->host, msg->code);
} }


free_http_cbdata (cbd);
end:
REF_RELEASE (cbd);


return 0; return 0;
} }


if (write (cbd->out_fd, chunk, len) == -1) { if (write (cbd->out_fd, chunk, len) == -1) {
msg_err_pool ("cannot write to %s: %s", cbd->tmpfile, strerror (errno)); msg_err_pool ("cannot write to %s: %s", cbd->tmpfile, strerror (errno));
free_http_cbdata (cbd);
REF_RELEASE (cbd);


return -1; return -1;
} }
else { else {
/* We could not resolve host, so cowardly fail here */ /* We could not resolve host, so cowardly fail here */
msg_err_pool ("cannot resolve %s", cbd->data->host); msg_err_pool ("cannot resolve %s", cbd->data->host);
free_http_cbdata (cbd);
} }
} }

REF_RELEASE (cbd);
} }


/** /**
cbd->cbdata.map = cbd->map; cbd->cbdata.map = cbd->map;
cbd->stage = map_resolve_host2; cbd->stage = map_resolve_host2;
double_to_tv (map->cfg->map_timeout, &cbd->tv); double_to_tv (map->cfg->map_timeout, &cbd->tv);
REF_INIT_RETAIN (cbd, free_http_cbdata);


msg_debug_pool ("reading map data from %s", data->host); msg_debug_pool ("reading map data from %s", data->host);
/* Send both A and AAAA requests */ /* Send both A and AAAA requests */
if (map->r->r) { if (map->r->r) {
rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd,
if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd,
map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1,
data->host, RDNS_REQUEST_A);
rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd,
data->host, RDNS_REQUEST_A)) {
REF_RETAIN (cbd);
}
if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd,
map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1,
data->host, RDNS_REQUEST_AAAA);
data->host, RDNS_REQUEST_AAAA)) {
REF_RETAIN (cbd);
}
jitter_timeout_event (map, FALSE, FALSE, FALSE); jitter_timeout_event (map, FALSE, FALSE, FALSE);
} }
else { else {
msg_warn_pool ("cannot load map: DNS resolver is not initialized"); msg_warn_pool ("cannot load map: DNS resolver is not initialized");
free_http_cbdata (cbd);
jitter_timeout_event (map, FALSE, FALSE, TRUE); jitter_timeout_event (map, FALSE, FALSE, TRUE);
} }

/* We don't need own ref as it is now refcounted by DNS requests */
REF_RELEASE (cbd);
} }


/* Start watching event for all maps */ /* Start watching event for all maps */

+ 4
- 1
src/libutil/map_private.h View File

#include "mem_pool.h" #include "mem_pool.h"
#include "keypair.h" #include "keypair.h"
#include "unix-std.h" #include "unix-std.h"
#include "ref.h"


enum fetch_proto { enum fetch_proto {
MAP_PROTO_FILE, MAP_PROTO_FILE,
struct http_map_data *data; struct http_map_data *data;
struct map_cb_data cbdata; struct map_cb_data cbdata;
struct rspamd_cryptobox_pubkey *pk; struct rspamd_cryptobox_pubkey *pk;
gchar *tmpfile;


enum { enum {
map_resolve_host2 = 0, /* 2 requests sent */ map_resolve_host2 = 0, /* 2 requests sent */
map_load_signature map_load_signature
} stage; } stage;
gint out_fd; gint out_fd;
gchar *tmpfile;
gint fd; gint fd;

ref_entry_t ref;
}; };


#endif /* SRC_LIBUTIL_MAP_PRIVATE_H_ */ #endif /* SRC_LIBUTIL_MAP_PRIVATE_H_ */

Loading…
Cancel
Save