diff options
author | Andreas Gruenbacher <agruen@linbit.com> | 2011-04-28 13:24:18 (GMT) |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 15:52:57 (GMT) |
commit | 86db06180a48999b9f1883dd8bf871c882dbf075 (patch) | |
tree | f4d4481a642853beccb23a899142d47a6c471535 | |
parent | acb104c396f915a46a0ff5e0bd588764fcbbf1ab (diff) | |
download | linux-fsl-qoriq-86db06180a48999b9f1883dd8bf871c882dbf075.tar.xz |
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 <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 32 |
1 files 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 *)"<not-used>"); + nc->integrity_alg[0] ? nc->integrity_alg : (unsigned char *)"<not-used>"); } return 0; |