The ppc arch packs the work request struct 1.0 in such a way that a straight memcpy won't work. Instead, break the copy out into chunks whenever the sizes don't match for given portions of the struct.
Found by built in gcc memcpy buffer overflow checks. Help on the right fix provided by Jakub Jelinek from the gcc team inside Red Hat. Signed-off-by: Doug Ledford <dledf...@redhat.com> --- src/compat-1_0.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/compat-1_0.c b/src/compat-1_0.c index fff6412..36884bb 100644 --- a/src/compat-1_0.c +++ b/src/compat-1_0.c @@ -353,8 +353,46 @@ static int post_send_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_send_wr_1_0 * real_wr->wr_id = w->wr_id; real_wr->next = NULL; - memcpy(&real_wr->sg_list, &w->sg_list, - sizeof *w - offsetof(struct ibv_send_wr, sg_list)); +#define TEST_SIZE_2_POINT(f1, f2) \ +((offsetof(struct ibv_send_wr, f1) - offsetof(struct ibv_send_wr, f2)) \ +== offsetof(struct ibv_send_wr_1_0, f1) - offsetof(struct ibv_send_wr_1_0, f2)) +#define TEST_SIZE_TO_END(f1) \ +((sizeof(struct ibv_send_wr) - offsetof(struct ibv_send_wr, f1)) == \ + (sizeof(struct ibv_send_wr_1_0) - offsetof(struct ibv_send_wr_1_0, f1))) + + if (TEST_SIZE_TO_END (sg_list)) + memcpy(&real_wr->sg_list, &w->sg_list, sizeof *real_wr + - offsetof(struct ibv_send_wr, sg_list)); + else if (TEST_SIZE_2_POINT (imm_data, sg_list) && + TEST_SIZE_TO_END (wr)) { + /* we have alignment up to wr, but padding between + * imm_data and wr, and we know wr itself is the + * same size */ + memcpy(&real_wr->sg_list, &w->sg_list, + offsetof(struct ibv_send_wr, imm_data) - + offsetof(struct ibv_send_wr, sg_list) + + sizeof real_wr->imm_data); + memcpy(&real_wr->wr, &w->wr, sizeof real_wr->wr); + } else { + real_wr->sg_list = w->sg_list; + real_wr->num_sge = w->num_sge; + real_wr->opcode = w->opcode; + real_wr->send_flags = w->send_flags; + real_wr->imm_data = w->imm_data; + if (TEST_SIZE_TO_END (wr)) + memcpy(&real_wr->wr, &w->wr, + sizeof real_wr->wr); + else { + real_wr->wr.atomic.remote_addr = + w->wr.atomic.remote_addr; + real_wr->wr.atomic.compare_add = + w->wr.atomic.compare_add; + real_wr->wr.atomic.swap = + w->wr.atomic.swap; + real_wr->wr.atomic.rkey = + w->wr.atomic.rkey; + } + } if (is_ud) real_wr->wr.ud.ah = w->wr.ud.ah->real_ah; -- 1.7.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html