On Tue, Jul 22, 2014 at 07:02:03PM +0800, Yanchuan Nian wrote: > On Tue, Jul 15, 2014 at 05:47:18PM +0200, Pablo Neira Ayuso wrote: > > This patch reworks the batching logic in several aspects: > > > > 1) New batch pages are now always added into the batch page list in > > first place. Then, in the send path, if the last batch page is > > empty, it is removed from the batch list. > > > > 2) nft_batch_page_add() is only called if the current batch page is > > full. Therefore, it is guaranteed to find a valid netlink message > > in the batch page when moving the tail that didn't fit into a new > > batch page. > > > > 3) The batch paging is initialized and released from the nft_netlink() > > path. > > > > 4) No more global struct mnl_nlmsg_batch *batch that points to the > > current batch page. Instead, it is retrieved from the tail of the > > batch list, which indicates the current batch page. > > > > This patch fixes a crash due to access of uninitialized memory area in > > due to calling batch_page_add() with an empty batch in the send path, > > and the memleak of the batch page contents. Reported in: > > > > http://patchwork.ozlabs.org/patch/367085/ > > http://patchwork.ozlabs.org/patch/367774/ > > > > The patch is larger, but this save the zeroing of the batch page area. > > Tested, it works find. Just a little question: is it better to release > all batches but the current after each message sending? > My misunderstanding. No questions now. > > > > Reported-by: Yanchuan Nian <ycnian@xxxxxxxxx> > > Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> > > --- > > src/main.c | 14 +++++----- > > src/mnl.c | 82 ++++++++++++++++++++++++++++++++------------------------- > > src/netlink.c | 1 - > > 3 files changed, 54 insertions(+), 43 deletions(-) > > > > diff --git a/src/main.c b/src/main.c > > index 30ea2c6..552a35d 100644 > > --- a/src/main.c > > +++ b/src/main.c > > @@ -173,6 +173,8 @@ static int nft_netlink(struct parser_state *state, struct list_head *msgs) > > bool batch_supported = netlink_batch_supported(); > > int ret = 0; > > > > + mnl_batch_init(); > > + > > batch_seqnum = mnl_batch_begin(); > > list_for_each_entry(cmd, &state->cmds, list) { > > memset(&ctx, 0, sizeof(ctx)); > > @@ -182,16 +184,14 @@ static int nft_netlink(struct parser_state *state, struct list_head *msgs) > > init_list_head(&ctx.list); > > ret = do_command(&ctx, cmd); > > if (ret < 0) > > - return ret; > > + goto out; > > } > > mnl_batch_end(); > > > > - if (mnl_batch_ready()) > > - ret = netlink_batch_send(&err_list); > > - else { > > - mnl_batch_reset(); > > + if (!mnl_batch_ready()) > > goto out; > > - } > > + > > + ret = netlink_batch_send(&err_list); > > > > list_for_each_entry_safe(err, tmp, &err_list, head) { > > list_for_each_entry(cmd, &state->cmds, list) { > > @@ -208,6 +208,8 @@ static int nft_netlink(struct parser_state *state, struct list_head *msgs) > > } > > } > > out: > > + mnl_batch_reset(); > > + > > list_for_each_entry_safe(cmd, next, &state->cmds, list) { > > list_del(&cmd->list); > > cmd_free(cmd); > > diff --git a/src/mnl.c b/src/mnl.c > > index e4f0339..42b11f5 100644 > > --- a/src/mnl.c > > +++ b/src/mnl.c > > @@ -82,8 +82,6 @@ nft_mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len, > > */ > > #define BATCH_PAGE_SIZE getpagesize() * 32 > > > > -static struct mnl_nlmsg_batch *batch; > > - > > static struct mnl_nlmsg_batch *mnl_batch_alloc(void) > > { > > static char *buf; > > @@ -93,11 +91,6 @@ static struct mnl_nlmsg_batch *mnl_batch_alloc(void) > > return mnl_nlmsg_batch_start(buf, BATCH_PAGE_SIZE); > > } > > > > -void mnl_batch_init(void) > > -{ > > - batch = mnl_batch_alloc(); > > -} > > - > > static LIST_HEAD(batch_page_list); > > static int batch_num_pages; > > > > @@ -106,35 +99,53 @@ struct batch_page { > > struct mnl_nlmsg_batch *batch; > > }; > > > > +void mnl_batch_init(void) > > +{ > > + struct batch_page *batch_page; > > + > > + batch_page = xmalloc(sizeof(struct batch_page)); > > + batch_page->batch = mnl_batch_alloc(); > > + batch_num_pages++; > > + list_add_tail(&batch_page->head, &batch_page_list); > > +} > > + > > +static struct batch_page *nft_batch_page_current(void) > > +{ > > + return list_entry(batch_page_list.prev, struct batch_page, head); > > +} > > + > > static void *nft_nlmsg_batch_current(void) > > { > > - return mnl_nlmsg_batch_current(batch); > > + return mnl_nlmsg_batch_current(nft_batch_page_current()->batch); > > } > > > > -static void mnl_batch_page_add(void) > > +static void nft_batch_page_add(void) > > { > > - struct batch_page *batch_page; > > struct nlmsghdr *last_nlh; > > > > /* Get the last message not fitting in the batch */ > > last_nlh = nft_nlmsg_batch_current(); > > - > > - batch_page = xmalloc(sizeof(struct batch_page)); > > - batch_page->batch = batch; > > - list_add_tail(&batch_page->head, &batch_page_list); > > - batch_num_pages++; > > - batch = mnl_batch_alloc(); > > - > > + /* Add new batch page */ > > + mnl_batch_init(); > > /* Copy the last message not fitting to the new batch page */ > > memcpy(nft_nlmsg_batch_current(), last_nlh, last_nlh->nlmsg_len); > > /* No overflow may happen as this is a new empty batch page */ > > - mnl_nlmsg_batch_next(batch); > > + mnl_nlmsg_batch_next(nft_batch_page_current()->batch); > > +} > > + > > +static void nft_batch_page_release(struct batch_page *batch_page) > > +{ > > + list_del(&batch_page->head); > > + xfree(mnl_nlmsg_batch_head(batch_page->batch)); > > + mnl_nlmsg_batch_stop(batch_page->batch); > > + xfree(batch_page); > > + batch_num_pages--; > > } > > > > static void nft_batch_continue(void) > > { > > - if (!mnl_nlmsg_batch_next(batch)) > > - mnl_batch_page_add(); > > + if (!mnl_nlmsg_batch_next(nft_batch_page_current()->batch)) > > + nft_batch_page_add(); > > } > > > > static uint32_t mnl_batch_put(int type) > > @@ -171,12 +182,16 @@ bool mnl_batch_ready(void) > > /* Check if the batch only contains the initial and trailing batch > > * messages. In that case, the batch is empty. > > */ > > - return mnl_nlmsg_batch_size(batch) != (NLMSG_HDRLEN+sizeof(struct nfgenmsg)) * 2; > > + return mnl_nlmsg_batch_size(nft_batch_page_current()->batch) != > > + (NLMSG_HDRLEN+sizeof(struct nfgenmsg)) * 2; > > } > > > > void mnl_batch_reset(void) > > { > > - mnl_nlmsg_batch_reset(batch); > > + struct batch_page *batch_page, *next; > > + > > + list_for_each_entry_safe(batch_page, next, &batch_page_list, head) > > + nft_batch_page_release(batch_page); > > } > > > > static void mnl_err_list_node_add(struct list_head *err_list, int error, > > @@ -226,12 +241,12 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) > > .msg_iov = iov, > > .msg_iovlen = batch_num_pages, > > }; > > - struct batch_page *batch_page, *next; > > + struct batch_page *batch_page; > > int i = 0; > > > > mnl_set_sndbuffer(nl); > > > > - list_for_each_entry_safe(batch_page, next, &batch_page_list, head) { > > + list_for_each_entry(batch_page, &batch_page_list, head) { > > iov[i].iov_base = mnl_nlmsg_batch_head(batch_page->batch); > > iov[i].iov_len = mnl_nlmsg_batch_size(batch_page->batch); > > i++; > > @@ -243,10 +258,6 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) > > sizeof(struct nfgenmsg)); > > } > > #endif > > - list_del(&batch_page->head); > > - xfree(batch_page->batch); > > - xfree(batch_page); > > - batch_num_pages--; > > } > > > > return sendmsg(mnl_socket_get_fd(nl), &msg, 0); > > @@ -262,12 +273,13 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) > > .tv_usec = 0 > > }; > > > > - if (!mnl_nlmsg_batch_is_empty(batch)) > > - mnl_batch_page_add(); > > + /* Remove last page from the batch if it's empty */ > > + if (mnl_nlmsg_batch_is_empty(nft_batch_page_current()->batch)) > > + nft_batch_page_release(nft_batch_page_current()); > > > > ret = mnl_nft_socket_sendmsg(nl); > > if (ret == -1) > > - goto err; > > + return -1; > > > > FD_ZERO(&readfds); > > FD_SET(fd, &readfds); > > @@ -275,14 +287,14 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) > > /* receive and digest all the acknowledgments from the kernel. */ > > ret = select(fd+1, &readfds, NULL, NULL, &tv); > > if (ret == -1) > > - goto err; > > + return -1; > > > > while (ret > 0 && FD_ISSET(fd, &readfds)) { > > struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf; > > > > ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf)); > > if (ret == -1) > > - goto err; > > + return -1; > > > > ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL); > > /* Continue on error, make sure we get all acknowledgments */ > > @@ -291,13 +303,11 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) > > > > ret = select(fd+1, &readfds, NULL, NULL, &tv); > > if (ret == -1) > > - goto err; > > + return -1; > > > > FD_ZERO(&readfds); > > FD_SET(fd, &readfds); > > } > > -err: > > - mnl_nlmsg_batch_reset(batch); > > return ret; > > } > > > > diff --git a/src/netlink.c b/src/netlink.c > > index afad5a4..0176cb4 100644 > > --- a/src/netlink.c > > +++ b/src/netlink.c > > @@ -59,7 +59,6 @@ static void __init netlink_open_sock(void) > > { > > nf_sock = nfsock_open(); > > fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK); > > - mnl_batch_init(); > > } > > > > static void __exit netlink_close_sock(void) > > -- > > 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html