Fix potential use-after-free: connected subchannel gets destroyed after its been picked by an lbpolicy

reviewable/pr8239/r9
Craig Tiller 8 years ago
parent 7a4089769d
commit 693d3949b4
  1. 4
      src/core/ext/client_channel/client_channel.c
  2. 3
      src/core/ext/client_channel/subchannel.c
  3. 2
      src/core/ext/client_channel/subchannel.h
  4. 6
      src/core/ext/lb_policy/pick_first/pick_first.c
  5. 13
      src/core/ext/lb_policy/round_robin/round_robin.c

@ -1022,6 +1022,10 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
gpr_mu_destroy(&calld->mu); gpr_mu_destroy(&calld->mu);
GPR_ASSERT(calld->waiting_ops_count == 0); GPR_ASSERT(calld->waiting_ops_count == 0);
if (calld->connected_subchannel != NULL) {
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, calld->connected_subchannel,
"picked");
}
gpr_free(calld->waiting_ops); gpr_free(calld->waiting_ops);
gpr_free(and_free_memory); gpr_free(and_free_memory);
} }

@ -183,9 +183,10 @@ static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
gpr_free(c); gpr_free(c);
} }
void grpc_connected_subchannel_ref( grpc_connected_subchannel *grpc_connected_subchannel_ref(
grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON); GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
return c;
} }
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,

@ -97,7 +97,7 @@ grpc_subchannel *grpc_subchannel_weak_ref(
void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel grpc_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS); GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_connected_subchannel_ref( grpc_connected_subchannel *grpc_connected_subchannel_ref(
grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
grpc_connected_subchannel *channel grpc_connected_subchannel *channel

@ -209,7 +209,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
/* Check atomically for a selected channel */ /* Check atomically for a selected channel */
grpc_connected_subchannel *selected = GET_SELECTED(p); grpc_connected_subchannel *selected = GET_SELECTED(p);
if (selected != NULL) { if (selected != NULL) {
*target = selected; *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
return 1; return 1;
} }
@ -218,7 +218,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
selected = GET_SELECTED(p); selected = GET_SELECTED(p);
if (selected) { if (selected) {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
*target = selected; *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
return 1; return 1;
} else { } else {
if (!p->started_picking) { if (!p->started_picking) {
@ -310,7 +310,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
/* update any calls that were waiting for a pick */ /* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = selected; *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp); gpr_free(pp);
} }

@ -397,7 +397,9 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) { if ((selected = peek_next_connected_locked(p))) {
/* readily available, report right away */ /* readily available, report right away */
*target = grpc_subchannel_get_connected_subchannel(selected->subchannel); *target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel),
"picked");
if (user_data != NULL) { if (user_data != NULL) {
*user_data = selected->user_data; *user_data = selected->user_data;
@ -463,8 +465,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel); grpc_subchannel_get_connected_subchannel(selected->subchannel),
"picked");
if (pp->user_data != NULL) { if (pp->user_data != NULL) {
*pp->user_data = selected->user_data; *pp->user_data = selected->user_data;
} }
@ -578,7 +581,9 @@ static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) { if ((selected = peek_next_connected_locked(p))) {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
target = grpc_subchannel_get_connected_subchannel(selected->subchannel); target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel),
"picked");
grpc_connected_subchannel_ping(exec_ctx, target, closure); grpc_connected_subchannel_ping(exec_ctx, target, closure);
} else { } else {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);

Loading…
Cancel
Save