The branch, master has been updated via 7e2358fcf7b ctdb-common: Only respect CTDB_SOCKET in CTDB_TEST_MODE via 4c12a36eb5b ctdb-common: Factor out checking of CTDB_TEST_MODE via c4794e40529 ctdb-pmda: Do not directly support CTDB_SOCKET environment variable via cf162bcbd27 ctdb-ib: Replace uses of sprintf() from b36c49e43e9 s4:kdc:sdb_to_hdb: Fix CID 1665466
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 7e2358fcf7be177d6e5de6e26f9d7c5af4acbb0c Author: Martin Schwenke <mschwe...@ddn.com> Date: Fri Aug 15 15:01:58 2025 +1000 ctdb-common: Only respect CTDB_SOCKET in CTDB_TEST_MODE At the moment CTDB_SOCKET can be used outside of test mode even though nobody should do this. So, no longer allow this. This means ensuring CTDB_TEST_MODE is set in the in the "clusteredmember" selftest environment, so that CTDB_SOCKET is respected there.. Details... The associated use of chown(2) and chmod(2), used to secure the socket in ctdb_daemon.c:ux_socket_bind(), potentially enables a symlink race attack. However, the chown(2) is currently not done in test mode, so restricting the use of CTDB_SOCKET to test mode solves the potential security issue. Also, sprinkle warnings about use of CTDB_TEST_MODE in appropriate places, just to attempt to limit unwanted behaviour. An alternative could be to use the socket file descriptor with fchown(2) and fchmod(2). However, these system calls are not well defined on sockets. Still, this was previously done in CTDB's early days (using the poorly documented method where they are allowed in Linux (only?) before calling bind(2)). It was removed (due to portability issues, via commits cf1056df94943ddcc3d547d4533b4bc04f57f265 and 2da3fe1b175a468fdff4aa4f65627facd2c28394) and replaced with the current post-bind chown(2) and chmod(2). I would like to remove the CTDB_SOCKET environment variable entirely, since setting CTDB_TEST_MODE and CTDB_BASE covers all reasonable test environments. However, I have a feeling that people use it for interactive testing, and that can still be done in CTDB_TEST_MODE. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15921 Signed-off-by: Martin Schwenke <mschwe...@ddn.com> Reported-by: *GUIAR OQBA * <techo...@gmail.com> Reviewed-by: Volker Lendecke <v...@samba.org> Autobuild-User(master): Volker Lendecke <v...@samba.org> Autobuild-Date(master): Thu Sep 25 09:02:06 UTC 2025 on atb-devel-224 commit 4c12a36eb5b44fb08d0461e6fa77fcdb4a128433 Author: Martin Schwenke <mschwe...@ddn.com> Date: Fri Aug 15 14:59:49 2025 +1000 ctdb-common: Factor out checking of CTDB_TEST_MODE For use elsewhere. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15921 Signed-off-by: Martin Schwenke <mschwe...@ddn.com> commit c4794e40529c63c696ecc3f8f27c810c22dd63a5 Author: Martin Schwenke <mschwe...@ddn.com> Date: Fri Aug 15 12:08:47 2025 +1000 ctdb-pmda: Do not directly support CTDB_SOCKET environment variable Always use whatever CTDB uses in the current environment. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15921 Signed-off-by: Martin Schwenke <mschwe...@ddn.com> Reviewed-by: Volker Lendecke <v...@samba.org> commit cf162bcbd27031dae43ce6d04de1b1fd2999b2db Author: Martin Schwenke <mschwe...@ddn.com> Date: Thu Sep 18 15:24:32 2025 +1000 ctdb-ib: Replace uses of sprintf() An unbounded sprintf() into ibw_lasterr (a 512-byte static data buffer) can potentially cause overflow into other BSS data. However, the risk is effectively minimised to zero due to: * This code not being executed at all in ctdbd. It is only executed in the accompanying test code: - The function ibw_process_init_attrs() can cause a buffer overflow if its 2nd argument, nattr, is non-zero and one of the structs in the array pointed to by its 1st argument, attr, contains a name member that is too long. - ibw_process_init_attrs() is only called by ibw_init(), which also has attr and nattr as its 1st and 2nd args, and it just passes them straight through. - ibw_init() is called in 2 places: 1. In ibwrapper_test.c, which is targeted test code. 2. In ibw_ctdb_init.c:ctdb_ibw_init(), which is the initialisation function use to initialise the IB transport in ctdbd. Here, NULL and 0 are passed as the relevant arguments to ibw_init(). Both arguments are flagged with TODO comments. :-) * This code is not built by default (--enable-infiniband is required). It appears that Debian and Red Hat family Linux distributions have never distributed binaries with this enabled. * Documentation (ctdb(7) and the wiki) recommends that private addresses are configured on a private network that is separate from client networks. So, even if the TODOs were done and the relevant arguments could come off the wire, the attack surface should be very small. Only the instance with %s in the format is potentially problematic. The others can not overflow the current 512 byte buffer. However, it makes sense to change them all in case someone foolishly reduces the size of the buffer and makes other changes so that the buffer can be overflowed in ctdbd. Now, will static analysers complain that the result of snprintf() is not checked even though snprintf() always NUL-terminates? Signed-off-by: Martin Schwenke <mschwe...@ddn.com> Reported-by: Marcos “Tr0p” Tolosa <marcos.tol...@owasp.org> Reviewed-by: Volker Lendecke <v...@samba.org> ----------------------------------------------------------------------- Summary of changes: ctdb/common/path.c | 35 +++++-- ctdb/ib/ibwrapper.c | 243 ++++++++++++++++++++++++++++++++++---------- ctdb/server/ctdbd.c | 7 ++ ctdb/tests/README | 10 +- ctdb/utils/pmda/pmda_ctdb.c | 13 +-- selftest/target/Samba.pm | 1 + selftest/target/Samba3.pm | 1 + 7 files changed, 241 insertions(+), 69 deletions(-) Changeset truncated at 500 lines: diff --git a/ctdb/common/path.c b/ctdb/common/path.c index ea3b08f4b2e..0d935429460 100644 --- a/ctdb/common/path.c +++ b/ctdb/common/path.c @@ -45,16 +45,30 @@ struct { .vardir = CTDB_VARDIR, }; -static void path_set_basedir(void) +static void path_set_test_mode(void) { - const char *t; - + const char *t = NULL; + + /* + * Do not use CTDB_TEST_MODE outside a test environment to + * attempt to (for example) improve installation flexibility. + * This is unsupported, may cause unwanted security issues and + * may break in future releases. + */ t = getenv("CTDB_TEST_MODE"); if (t == NULL) { - goto done; + return; } ctdb_paths.test_mode = true; +} + +static void path_set_basedir(void) +{ + path_set_test_mode(); + if (!ctdb_paths.test_mode) { + goto done; + } ctdb_paths.basedir = getenv("CTDB_BASE"); if (ctdb_paths.basedir == NULL) { @@ -188,11 +202,14 @@ char *path_config(TALLOC_CTX *mem_ctx) char *path_socket(TALLOC_CTX *mem_ctx, const char *daemon) { - if (strcmp(daemon, "ctdbd") == 0) { - const char *t = getenv("CTDB_SOCKET"); - - if (t != NULL) { - return talloc_strdup(mem_ctx, t); + path_set_test_mode(); + if (ctdb_paths.test_mode) { + if (strcmp(daemon, "ctdbd") == 0) { + const char *t = getenv("CTDB_SOCKET"); + + if (t != NULL) { + return talloc_strdup(mem_ctx, t); + } } } diff --git a/ctdb/ib/ibwrapper.c b/ctdb/ib/ibwrapper.c index cf4efa579e2..24fb301824a 100644 --- a/ctdb/ib/ibwrapper.c +++ b/ctdb/ib/ibwrapper.c @@ -61,13 +61,17 @@ static void *ibw_alloc_mr(struct ibw_ctx_priv *pctx, struct ibw_conn_priv *pconn DEBUG(DEBUG_DEBUG, ("ibw_alloc_mr(cmid=%p, n=%u)\n", pconn->cm_id, n)); buf = memalign(pctx->pagesize, n); if (!buf) { - sprintf(ibw_lasterr, "couldn't allocate memory\n"); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "couldn't allocate memory\n"); return NULL; } *ppmr = ibv_reg_mr(pconn->pd, buf, n, IBV_ACCESS_LOCAL_WRITE); if (!*ppmr) { - sprintf(ibw_lasterr, "couldn't allocate mr\n"); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "couldn't allocate mr\n"); free(buf); return NULL; } @@ -100,14 +104,18 @@ static int ibw_init_memory(struct ibw_conn *conn) pconn->buf_send = ibw_alloc_mr(pctx, pconn, opts->max_send_wr * opts->recv_bufsize, &pconn->mr_send); if (!pconn->buf_send) { - sprintf(ibw_lasterr, "couldn't allocate work send buf\n"); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "couldn't allocate work send buf\n"); return -1; } pconn->buf_recv = ibw_alloc_mr(pctx, pconn, opts->max_recv_wr * opts->recv_bufsize, &pconn->mr_recv); if (!pconn->buf_recv) { - sprintf(ibw_lasterr, "couldn't allocate work recv buf\n"); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "couldn't allocate work recv buf\n"); return -1; } @@ -253,7 +261,10 @@ static int ibw_setup_cq_qp(struct ibw_conn *conn) /* init verbs */ pconn->verbs_channel = ibv_create_comp_channel(pconn->cm_id->verbs); if (!pconn->verbs_channel) { - sprintf(ibw_lasterr, "ibv_create_comp_channel failed %d\n", errno); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ibv_create_comp_channel failed %d\n", + errno); return -1; } DEBUG(DEBUG_DEBUG, ("created channel %p\n", pconn->verbs_channel)); @@ -263,7 +274,10 @@ static int ibw_setup_cq_qp(struct ibw_conn *conn) pconn->pd = ibv_alloc_pd(pconn->cm_id->verbs); if (!pconn->pd) { - sprintf(ibw_lasterr, "ibv_alloc_pd failed %d\n", errno); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ibv_alloc_pd failed %d\n", + errno); return -1; } DEBUG(DEBUG_DEBUG, ("created pd %p\n", pconn->pd)); @@ -277,13 +291,18 @@ static int ibw_setup_cq_qp(struct ibw_conn *conn) pctx->opts.max_recv_wr + pctx->opts.max_send_wr, conn, pconn->verbs_channel, 0); if (pconn->cq==NULL) { - sprintf(ibw_lasterr, "ibv_create_cq failed\n"); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ibv_create_cq failed\n"); return -1; } rc = ibv_req_notify_cq(pconn->cq, 0); if (rc) { - sprintf(ibw_lasterr, "ibv_req_notify_cq failed with %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ibv_req_notify_cq failed with %d\n", + rc); return rc; } @@ -299,14 +318,20 @@ static int ibw_setup_cq_qp(struct ibw_conn *conn) rc = rdma_create_qp(pconn->cm_id, pconn->pd, &init_attr); if (rc) { - sprintf(ibw_lasterr, "rdma_create_qp failed with %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_create_qp failed with %d\n", + rc); return rc; } /* elase result is in pconn->cm_id->qp */ rc = ibv_query_qp(pconn->cm_id->qp, &attr, IBV_QP_PATH_MTU, &init_attr); if (rc) { - sprintf(ibw_lasterr, "ibv_query_qp failed with %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ibv_query_qp failed with %d\n", + rc); return rc; } @@ -338,7 +363,10 @@ static int ibw_refill_cq_recv(struct ibw_conn *conn) rc = ibv_post_recv(pconn->cm_id->qp, &wr, &bad_wr); if (rc) { - sprintf(ibw_lasterr, "refill/ibv_post_recv failed with %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "refill/ibv_post_recv failed with %d\n", + rc); DEBUG(DEBUG_ERR, ("%s", ibw_lasterr)); return -2; } @@ -372,7 +400,10 @@ static int ibw_fill_cq(struct ibw_conn *conn) rc = ibv_post_recv(pconn->cm_id->qp, &wr, &bad_wr); if (rc) { - sprintf(ibw_lasterr, "fill/ibv_post_recv failed with %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "fill/ibv_post_recv failed with %d\n", + rc); DEBUG(DEBUG_ERR, ("%s", ibw_lasterr)); return -2; } @@ -400,7 +431,10 @@ static int ibw_manage_connect(struct ibw_conn *conn) rc = rdma_connect(pconn->cm_id, &conn_param); if (rc) - sprintf(ibw_lasterr, "rdma_connect error %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_connect error %d\n", + rc); return rc; } @@ -422,7 +456,10 @@ static void ibw_event_handler_cm(struct tevent_context *ev, if (rc) { ctx->state = IBWS_ERROR; event = NULL; - sprintf(ibw_lasterr, "rdma_get_cm_event error %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_get_cm_event error %d\n", + rc); goto error; } cma_id = event->id; @@ -436,7 +473,10 @@ static void ibw_event_handler_cm(struct tevent_context *ev, /* continuing from ibw_connect ... */ rc = rdma_resolve_route(cma_id, 2000); if (rc) { - sprintf(ibw_lasterr, "rdma_resolve_route error %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_resolve_route error %d\n", + rc); goto error; } /* continued at RDMA_CM_EVENT_ROUTE_RESOLVED */ @@ -501,19 +541,34 @@ static void ibw_event_handler_cm(struct tevent_context *ev, break; case RDMA_CM_EVENT_ADDR_ERROR: - sprintf(ibw_lasterr, "RDMA_CM_EVENT_ADDR_ERROR, error %d\n", event->status); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "RDMA_CM_EVENT_ADDR_ERROR, error %d\n", + event->status); goto error; case RDMA_CM_EVENT_ROUTE_ERROR: - sprintf(ibw_lasterr, "RDMA_CM_EVENT_ROUTE_ERROR, error %d\n", event->status); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "RDMA_CM_EVENT_ROUTE_ERROR, error %d\n", + event->status); goto error; case RDMA_CM_EVENT_CONNECT_ERROR: - sprintf(ibw_lasterr, "RDMA_CM_EVENT_CONNECT_ERROR, error %d\n", event->status); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "RDMA_CM_EVENT_CONNECT_ERROR, error %d\n", + event->status); goto error; case RDMA_CM_EVENT_UNREACHABLE: - sprintf(ibw_lasterr, "RDMA_CM_EVENT_UNREACHABLE, error %d\n", event->status); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "RDMA_CM_EVENT_UNREACHABLE, error %d\n", + event->status); goto error; case RDMA_CM_EVENT_REJECTED: - sprintf(ibw_lasterr, "RDMA_CM_EVENT_REJECTED, error %d\n", event->status); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "RDMA_CM_EVENT_REJECTED, error %d\n", + event->status); DEBUG(DEBUG_INFO, ("cm event handler: %s", ibw_lasterr)); conn = talloc_get_type(cma_id->context, struct ibw_conn); if (conn) { @@ -542,16 +597,24 @@ static void ibw_event_handler_cm(struct tevent_context *ev, break; case RDMA_CM_EVENT_DEVICE_REMOVAL: - sprintf(ibw_lasterr, "cma detected device removal!\n"); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "cma detected device removal!\n"); goto error; default: - sprintf(ibw_lasterr, "unknown event %d\n", event->event); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "unknown event %d\n", + event->event); goto error; } if (event!=NULL && (rc=rdma_ack_cm_event(event))) { - sprintf(ibw_lasterr, "rdma_ack_cm_event failed with %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_ack_cm_event failed with %d\n", + rc); goto error; } @@ -596,23 +659,36 @@ static void ibw_event_handler_verbs(struct tevent_context *ev, /* TODO: check whether if it's good to have more channels here... */ rc = ibv_get_cq_event(pconn->verbs_channel, &ev_cq, &ev_ctx); if (rc) { - sprintf(ibw_lasterr, "Failed to get cq_event with %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "Failed to get cq_event with %d\n", + rc); goto error; } if (ev_cq != pconn->cq) { - sprintf(ibw_lasterr, "ev_cq(%p) != pconn->cq(%p)\n", ev_cq, pconn->cq); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ev_cq(%p) != pconn->cq(%p)\n", + ev_cq, + pconn->cq); goto error; } rc = ibv_req_notify_cq(pconn->cq, 0); if (rc) { - sprintf(ibw_lasterr, "Couldn't request CQ notification (%d)\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "Couldn't request CQ notification (%d)\n", + rc); goto error; } while((rc=ibv_poll_cq(pconn->cq, 1, &wc))==1) { if (wc.status) { - sprintf(ibw_lasterr, "cq completion failed status=%d, opcode=%d, rc=%d\n", - wc.status, wc.opcode, rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "cq completion failed status=%d, opcode=%d, rc=%d\n", + wc.status, wc.opcode, + rc); goto error; } @@ -638,12 +714,18 @@ static void ibw_event_handler_verbs(struct tevent_context *ev, break; default: - sprintf(ibw_lasterr, "unknown completion %d\n", wc.opcode); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "unknown completion %d\n", + wc.opcode); goto error; } } if (rc!=0) { - sprintf(ibw_lasterr, "ibv_poll_cq error %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ibv_poll_cq error %d\n", + rc); goto error; } @@ -737,8 +819,11 @@ static int ibw_wc_send(struct ibw_conn *conn, struct ibv_wc *wc) if ((p->wr_id + pctx->opts.max_recv_wr)==(int)wc->wr_id) break; if (p==NULL) { - sprintf(ibw_lasterr, "failed to find wr_id %d\n", (int)wc->wr_id); - return -1; + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "failed to find wr_id %d\n", + (int)wc->wr_id); + return -1; } if (p->ref_cnt) { p->ref_cnt--; @@ -764,8 +849,11 @@ static int ibw_append_to_part(struct ibw_conn_priv *pconn, assert(part->len==0); part->buf = talloc_size(pconn, add_len); if (part->buf==NULL) { - sprintf(ibw_lasterr, "recv talloc_size error (%u) #%d\n", - add_len, info); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "recv talloc_size error (%u) #%d\n", + add_len, + info); return -1; } part->bufsize = add_len; @@ -773,8 +861,12 @@ static int ibw_append_to_part(struct ibw_conn_priv *pconn, part->buf = talloc_realloc_size(pconn, part->buf, part->len + add_len); if (part->buf==NULL) { - sprintf(ibw_lasterr, "recv realloc error (%u + %u) #%d\n", - part->len, add_len, info); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "recv realloc error (%u + %u) #%d\n", + part->len, + add_len, + info); return -1; } } @@ -802,7 +894,9 @@ static int ibw_wc_mem_threshold(struct ibw_conn_priv *pconn, talloc_free(part->buf); part->buf = talloc_size(pconn, threshold); if (part->buf==NULL) { - sprintf(ibw_lasterr, "talloc_size failed\n"); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "talloc_size failed\n"); return -1; } part->bufsize = threshold; @@ -841,7 +935,10 @@ static int ibw_wc_recv(struct ibw_conn *conn, struct ibv_wc *wc) /* set it again now... */ part->to_read = *((uint32_t *)(part->buf)); /* TODO: ntohl */ if (part->to_read<sizeof(uint32_t)) { - sprintf(ibw_lasterr, "got msglen=%u #2\n", part->to_read); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "got msglen=%u #2\n", + part->to_read); goto error; } part->to_read -= sizeof(uint32_t); /* it's already read */ @@ -859,7 +956,10 @@ static int ibw_wc_recv(struct ibw_conn *conn, struct ibv_wc *wc) if (remain>=sizeof(uint32_t)) { uint32_t msglen = *(uint32_t *)p; /* TODO: ntohl */ if (msglen<sizeof(uint32_t)) { - sprintf(ibw_lasterr, "got msglen=%u\n", msglen); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "got msglen=%u\n", + msglen); goto error; } @@ -925,7 +1025,10 @@ static int ibw_process_init_attrs(struct ibw_initattr *attr, int nattr, struct i else if (strcmp(name, "recv_threshold")==0) opts->recv_threshold = atoi(value); else { - sprintf(ibw_lasterr, "ibw_init: unknown name %s\n", name); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "ibw_init: unknown name %s\n", + name); return -1; } } @@ -969,7 +1072,10 @@ struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr, /* init cm */ pctx->cm_channel = rdma_create_event_channel(); if (!pctx->cm_channel) { - sprintf(ibw_lasterr, "rdma_create_event_channel error %d\n", errno); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_create_event_channel error %d\n", + errno); goto cleanup; } @@ -983,7 +1089,10 @@ struct ibw_ctx *ibw_init(struct ibw_initattr *attr, int nattr, #endif if (rc) { rc = errno; - sprintf(ibw_lasterr, "rdma_create_id error %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_create_id error %d\n", + rc); goto cleanup; } DEBUG(DEBUG_DEBUG, ("created cm_id %p\n", pctx->cm_id)); @@ -1030,7 +1139,10 @@ int ibw_bind(struct ibw_ctx *ctx, struct sockaddr_in *my_addr) inet_ntoa(my_addr->sin_addr), ntohs(my_addr->sin_port))); rc = rdma_bind_addr(pctx->cm_id, (struct sockaddr *) my_addr); if (rc) { - sprintf(ibw_lasterr, "rdma_bind_addr error %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_bind_addr error %d\n", + rc); DEBUG(DEBUG_ERR, ("%s", ibw_lasterr)); return rc; } @@ -1047,7 +1159,10 @@ int ibw_listen(struct ibw_ctx *ctx, int backlog) DEBUG(DEBUG_DEBUG, ("ibw_listen\n")); rc = rdma_listen(pctx->cm_id, backlog); if (rc) { - sprintf(ibw_lasterr, "rdma_listen failed: %d\n", rc); + snprintf(ibw_lasterr, + sizeof(ibw_lasterr), + "rdma_listen failed: %d\n", + rc); DEBUG(DEBUG_ERR, ("%s", ibw_lasterr)); return rc; -- Samba Shared Repository