From 86db06180a48999b9f1883dd8bf871c882dbf075 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 28 Apr 2011 15:24:18 +0200 Subject: [PATCH] drbd: Wrong use of RCU in receive_protocol() It is not enough to grab net_conf->integrity_alg under rcu_read_lock() and access it outside of it; the entire net_conf object may be gone by then. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6da7aeb..98f03b1 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2998,7 +2998,6 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p; int p_want_lose, p_two_primaries, cf; char p_integrity_alg[SHARED_SECRET_MAX] = ""; - unsigned char *my_alg; struct net_conf *nc; p_proto = be32_to_cpu(p->protocol); @@ -3009,6 +3008,18 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) cf = be32_to_cpu(p->conn_flags); p_want_lose = cf & CF_WANT_LOSE; + if (tconn->agreed_pro_version >= 87) { + int err; + + if (pi->size > sizeof(p_integrity_alg)) + return -EIO; + err = drbd_recv_all(tconn, p_integrity_alg, pi->size); + if (err) + return err; + + p_integrity_alg[SHARED_SECRET_MAX-1] = 0; + } + clear_bit(CONN_DRY_RUN, &tconn->flags); if (cf & CF_DRY_RUN) @@ -3047,23 +3058,18 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) goto disconnect_rcu_unlock; } - my_alg = nc->integrity_alg; - rcu_read_unlock(); - if (tconn->agreed_pro_version >= 87) { - int err; - - err = drbd_recv_all(tconn, p_integrity_alg, pi->size); - if (err) - return err; - - p_integrity_alg[SHARED_SECRET_MAX-1] = 0; - if (strcmp(p_integrity_alg, my_alg)) { + if (strcmp(p_integrity_alg, nc->integrity_alg)) { conn_err(tconn, "incompatible setting of the data-integrity-alg\n"); goto disconnect; } + } + + rcu_read_unlock(); + + if (tconn->agreed_pro_version >= 87) { conn_info(tconn, "data-integrity-alg: %s\n", - my_alg[0] ? my_alg : (unsigned char *)""); + nc->integrity_alg[0] ? nc->integrity_alg : (unsigned char *)""); } return 0; -- 2.7.4