diff options
author | Andreas Gruenbacher <agruen@linbit.com> | 2011-04-28 09:24:18 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:52:57 -0500 |
commit | 86db06180a48999b9f1883dd8bf871c882dbf075 (patch) | |
tree | f4d4481a642853beccb23a899142d47a6c471535 | |
parent | acb104c396f915a46a0ff5e0bd588764fcbbf1ab (diff) |
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 6da7aebde8df..98f03b143b38 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) | |||
2998 | int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p; | 2998 | int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p; |
2999 | int p_want_lose, p_two_primaries, cf; | 2999 | int p_want_lose, p_two_primaries, cf; |
3000 | char p_integrity_alg[SHARED_SECRET_MAX] = ""; | 3000 | char p_integrity_alg[SHARED_SECRET_MAX] = ""; |
3001 | unsigned char *my_alg; | ||
3002 | struct net_conf *nc; | 3001 | struct net_conf *nc; |
3003 | 3002 | ||
3004 | p_proto = be32_to_cpu(p->protocol); | 3003 | p_proto = be32_to_cpu(p->protocol); |
@@ -3009,6 +3008,18 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) | |||
3009 | cf = be32_to_cpu(p->conn_flags); | 3008 | cf = be32_to_cpu(p->conn_flags); |
3010 | p_want_lose = cf & CF_WANT_LOSE; | 3009 | p_want_lose = cf & CF_WANT_LOSE; |
3011 | 3010 | ||
3011 | if (tconn->agreed_pro_version >= 87) { | ||
3012 | int err; | ||
3013 | |||
3014 | if (pi->size > sizeof(p_integrity_alg)) | ||
3015 | return -EIO; | ||
3016 | err = drbd_recv_all(tconn, p_integrity_alg, pi->size); | ||
3017 | if (err) | ||
3018 | return err; | ||
3019 | |||
3020 | p_integrity_alg[SHARED_SECRET_MAX-1] = 0; | ||
3021 | } | ||
3022 | |||
3012 | clear_bit(CONN_DRY_RUN, &tconn->flags); | 3023 | clear_bit(CONN_DRY_RUN, &tconn->flags); |
3013 | 3024 | ||
3014 | if (cf & CF_DRY_RUN) | 3025 | if (cf & CF_DRY_RUN) |
@@ -3047,23 +3058,18 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) | |||
3047 | goto disconnect_rcu_unlock; | 3058 | goto disconnect_rcu_unlock; |
3048 | } | 3059 | } |
3049 | 3060 | ||
3050 | my_alg = nc->integrity_alg; | ||
3051 | rcu_read_unlock(); | ||
3052 | |||
3053 | if (tconn->agreed_pro_version >= 87) { | 3061 | if (tconn->agreed_pro_version >= 87) { |
3054 | int err; | 3062 | if (strcmp(p_integrity_alg, nc->integrity_alg)) { |
3055 | |||
3056 | err = drbd_recv_all(tconn, p_integrity_alg, pi->size); | ||
3057 | if (err) | ||
3058 | return err; | ||
3059 | |||
3060 | p_integrity_alg[SHARED_SECRET_MAX-1] = 0; | ||
3061 | if (strcmp(p_integrity_alg, my_alg)) { | ||
3062 | conn_err(tconn, "incompatible setting of the data-integrity-alg\n"); | 3063 | conn_err(tconn, "incompatible setting of the data-integrity-alg\n"); |
3063 | goto disconnect; | 3064 | goto disconnect; |
3064 | } | 3065 | } |
3066 | } | ||
3067 | |||
3068 | rcu_read_unlock(); | ||
3069 | |||
3070 | if (tconn->agreed_pro_version >= 87) { | ||
3065 | conn_info(tconn, "data-integrity-alg: %s\n", | 3071 | conn_info(tconn, "data-integrity-alg: %s\n", |
3066 | my_alg[0] ? my_alg : (unsigned char *)"<not-used>"); | 3072 | nc->integrity_alg[0] ? nc->integrity_alg : (unsigned char *)"<not-used>"); |
3067 | } | 3073 | } |
3068 | 3074 | ||
3069 | return 0; | 3075 | return 0; |