James Raphael Tiovalen <[email protected]> writes:
> This commit addresses several high and medium-impact Coverity defects by
> fixing several possible null-pointer dereferences and potentially
> uninitialized variables.
>
> There were cases when crashes were encountered when some null pointers
> were dereferenced. Null pointer checks and alternative code paths have
> been added to prevent unwanted crashes. For impossible conditions,
> non-null assertions are added. Additionally, some struct variables were
> not initialized. Zero-initializations have been added to prevent
> potential data leaks or undefined behavior.
>
> Some variables would always be initialized by either the code flow or
> the compiler and some pointers would never be null. Thus, some Coverity
> reports might be false positives. That said, it is still considered best
> practice to perform null pointer checks and initialize variables upfront
> just in case to ensure the overall resilience and security of OVS, as
> long as they do not impact performance-critical code. As a bonus, it
> would also make static analyzer tools, such as Coverity, happy.
>
> Unit tests have been successfully executed via `make check` and they
> successfully passed.
>
> Signed-off-by: James Raphael Tiovalen <[email protected]>
> ---
Sorry to comment on this so late - one thing I would also say can help
with review is to separate the logical changes. For example, each flag
from Coverity could be a separate patch in a cleanup series. It could
help to keep things organized. Comments to follow.
> v6:
> - Convert some explicit null pointer checks to assertions since they are
> checking for impossible conditions.
> - Use `nullable_memset()` and `nullable_memcpy()` instead of manually
> performing null checks for `memset()` and `memcpy()`.
>
> v5:
> Improve commit message to better describe the intent of this patch.
>
> v4:
> - Fix some apply-robot checkpatch errors and warnings.
> - Fix github-robot build failure: linux clang test asan.
>
> v3:
> Fix some apply-robot checkpatch errors and warnings.
>
> v2:
> Fix some apply-robot checkpatch errors and warnings.
> ---
> lib/dp-packet.c | 22 ++++++++++++-------
> lib/dpctl.c | 16 +++++++++-----
> lib/json.c | 22 ++++++++++++-------
> lib/latch-unix.c | 2 +-
> lib/memory.c | 12 ++++++-----
> lib/netdev-native-tnl.c | 17 +++++++++------
> lib/odp-execute.c | 4 ++++
> lib/pcap-file.c | 4 +++-
> lib/rtnetlink.c | 5 +++++
> lib/sflow_agent.c | 6 ++++++
> lib/shash.c | 5 ++++-
> lib/sset.c | 2 ++
> ovsdb/condition.c | 10 ++++++++-
> ovsdb/file.c | 21 ++++++++++++++----
> ovsdb/jsonrpc-server.c | 6 +++++-
> ovsdb/monitor.c | 36 +++++++++++++++++++++++++++----
> ovsdb/ovsdb-client.c | 46 +++++++++++++++++++++++++++-------------
> ovsdb/ovsdb-server.c | 17 +++++++++------
> ovsdb/ovsdb-util.c | 9 ++++++++
> ovsdb/ovsdb.c | 8 ++++++-
> ovsdb/query.c | 2 ++
> ovsdb/replication.c | 15 +++++++------
> ovsdb/row.c | 4 +++-
> ovsdb/table.c | 2 +-
> ovsdb/transaction.c | 2 ++
> utilities/ovs-vsctl.c | 47 ++++++++++++++++++++++++++++-------------
> vtep/vtep-ctl.c | 10 ++++++---
> 27 files changed, 259 insertions(+), 93 deletions(-)
>
> diff --git a/lib/dp-packet.c b/lib/dp-packet.c
> index ae8ab5800..f9c58a72f 100644
> --- a/lib/dp-packet.c
> +++ b/lib/dp-packet.c
> @@ -171,6 +171,7 @@ dp_packet_new_with_headroom(size_t size, size_t headroom)
> struct dp_packet *
> dp_packet_clone(const struct dp_packet *buffer)
> {
> + ovs_assert(buffer != NULL);
> return dp_packet_clone_with_headroom(buffer, 0);
> }
>
> @@ -183,9 +184,12 @@ dp_packet_clone_with_headroom(const struct dp_packet
> *buffer, size_t headroom)
> struct dp_packet *new_buffer;
> uint32_t mark;
>
> - new_buffer = dp_packet_clone_data_with_headroom(dp_packet_data(buffer),
> - dp_packet_size(buffer),
> - headroom);
> + const void *data_dp = dp_packet_data(buffer);
> + ovs_assert(data_dp != NULL);
There's a bit of intermingling of null checks here. Please stick to
one style. Throughout the dp-packet.c file, there are positive tests
(ie 'ovs_assert(data_dp)' would match the style more).
> +
> + new_buffer = dp_packet_clone_data_with_headroom(data_dp,
> + dp_packet_size(buffer),
> + headroom);
> /* Copy the following fields into the returned buffer: l2_pad_size,
> * l2_5_ofs, l3_ofs, l4_ofs, cutlen, packet_type and md. */
> memcpy(&new_buffer->l2_pad_size, &buffer->l2_pad_size,
> @@ -323,7 +327,9 @@ dp_packet_shift(struct dp_packet *b, int delta)
>
> if (delta != 0) {
> char *dst = (char *) dp_packet_data(b) + delta;
> - memmove(dst, dp_packet_data(b), dp_packet_size(b));
> + const void *data_dp = dp_packet_data(b);
> + ovs_assert(data_dp != NULL);
Probably better to check this before we use dp_packet_data() in a
calculation. It seems odd to check after we've set up dst.
> + memmove(dst, data_dp, dp_packet_size(b));
> dp_packet_set_data(b, dst);
> }
> }
> @@ -348,7 +354,7 @@ void *
> dp_packet_put_zeros(struct dp_packet *b, size_t size)
> {
> void *dst = dp_packet_put_uninit(b, size);
> - memset(dst, 0, size);
> + nullable_memset(dst, 0, size);
> return dst;
> }
>
> @@ -359,7 +365,7 @@ void *
> dp_packet_put(struct dp_packet *b, const void *p, size_t size)
> {
> void *dst = dp_packet_put_uninit(b, size);
> - memcpy(dst, p, size);
> + nullable_memcpy(dst, p, size);
> return dst;
> }
>
> @@ -431,7 +437,7 @@ void *
> dp_packet_push_zeros(struct dp_packet *b, size_t size)
> {
> void *dst = dp_packet_push_uninit(b, size);
> - memset(dst, 0, size);
> + nullable_memset(dst, 0, size);
> return dst;
> }
>
> @@ -442,7 +448,7 @@ void *
> dp_packet_push(struct dp_packet *b, const void *p, size_t size)
> {
> void *dst = dp_packet_push_uninit(b, size);
> - memcpy(dst, p, size);
> + nullable_memcpy(dst, p, size);
> return dst;
> }
>
> diff --git a/lib/dpctl.c b/lib/dpctl.c
> index c501a0cd7..1833d3ba3 100644
> --- a/lib/dpctl.c
> +++ b/lib/dpctl.c
> @@ -336,6 +336,8 @@ dpctl_add_if(int argc OVS_UNUSED, const char *argv[],
> value = "";
> }
>
> + ovs_assert(key != NULL);
> +
> if (!strcmp(key, "type")) {
> type = value;
> } else if (!strcmp(key, "port_no")) {
> @@ -454,6 +456,8 @@ dpctl_set_if(int argc, const char *argv[], struct
> dpctl_params *dpctl_p)
> value = "";
> }
>
> + ovs_assert(key != NULL);
> +
> if (!strcmp(key, "type")) {
> if (strcmp(value, type)) {
> dpctl_error(dpctl_p, 0,
> @@ -693,12 +697,14 @@ show_dpif(struct dpif *dpif, struct dpctl_params
> *dpctl_p)
> error = netdev_get_config(netdev, &config);
> if (!error) {
> const struct smap_node **nodes = smap_sort(&config);
> - for (size_t j = 0; j < smap_count(&config); j++) {
> - const struct smap_node *node = nodes[j];
> - dpctl_print(dpctl_p, "%c %s=%s", j ? ',' : ':',
> - node->key, node->value);
> + if (nodes) {
> + for (size_t j = 0; j < smap_count(&config); j++) {
> + const struct smap_node *node = nodes[j];
> + dpctl_print(dpctl_p, "%c %s=%s", j ? ',' : ':',
> + node->key, node->value);
> + }
> + free(nodes);
Rather than another level of indentation here, can we not change the
test condition to be:
for(size_t j = 0; (nodes &&
j < smap_count(&config)); j++) {
}
Similar comment in other places.
An alternative is to change smap_count() to return '0' if smap is NULL,
or assert there (and we can do this for shash as well).
> }
> - free(nodes);
> } else {
> dpctl_print(dpctl_p, ", could not retrieve configuration
> "
> "(%s)", ovs_strerror(error));
> diff --git a/lib/json.c b/lib/json.c
> index aded8bb01..11471f42a 100644
> --- a/lib/json.c
> +++ b/lib/json.c
> @@ -498,12 +498,15 @@ json_hash_object(const struct shash *object, size_t
> basis)
>
> nodes = shash_sort(object);
> n = shash_count(object);
> - for (i = 0; i < n; i++) {
> - const struct shash_node *node = nodes[i];
> - basis = hash_string(node->name, basis);
> - basis = json_hash(node->data, basis);
> +
> + if (nodes) {
> + for (i = 0; i < n; i++) {
> + const struct shash_node *node = nodes[i];
> + basis = hash_string(node->name, basis);
> + basis = json_hash(node->data, basis);
> + }
> + free(nodes);
> }
> - free(nodes);
> return basis;
> }
>
> @@ -1655,10 +1658,13 @@ json_serialize_object(const struct shash *object,
> struct json_serializer *s)
>
> nodes = shash_sort(object);
> n = shash_count(object);
> - for (i = 0; i < n; i++) {
> - json_serialize_object_member(i, nodes[i], s);
> +
> + if (nodes) {
> + for (i = 0; i < n; i++) {
> + json_serialize_object_member(i, nodes[i], s);
> + }
> + free(nodes);
> }
> - free(nodes);
> } else {
> struct shash_node *node;
> size_t i;
> diff --git a/lib/latch-unix.c b/lib/latch-unix.c
> index f4d10c39a..262f111e4 100644
> --- a/lib/latch-unix.c
> +++ b/lib/latch-unix.c
> @@ -71,7 +71,7 @@ latch_set(struct latch *latch)
> bool
> latch_is_set(const struct latch *latch)
> {
> - struct pollfd pfd;
> + struct pollfd pfd = {0, 0, 0};
> int retval;
>
> pfd.fd = latch->fds[0];
> diff --git a/lib/memory.c b/lib/memory.c
> index da97476c6..d3bd8c295 100644
> --- a/lib/memory.c
> +++ b/lib/memory.c
> @@ -24,6 +24,7 @@
> #include "simap.h"
> #include "timeval.h"
> #include "unixctl.h"
> +#include "util.h"
> #include "openvswitch/vlog.h"
>
> VLOG_DEFINE_THIS_MODULE(memory);
> @@ -116,13 +117,14 @@ compose_report(const struct simap *usage, struct ds *s)
> size_t n = simap_count(usage);
> size_t i;
>
> - for (i = 0; i < n; i++) {
> - const struct simap_node *node = nodes[i];
> -
> - ds_put_format(s, "%s:%u ", node->name, node->data);
> + if (nodes) {
> + for (i = 0; i < n; i++) {
> + const struct simap_node *node = nodes[i];
> + ds_put_format(s, "%s:%u ", node->name, node->data);
> + }
> + free(nodes);
> }
> ds_chomp(s, ' ');
> - free(nodes);
> }
>
> /* Logs the contents of 'usage', as a collection of name-count pairs.
> diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
> index b89dfdd52..b2283988b 100644
> --- a/lib/netdev-native-tnl.c
> +++ b/lib/netdev-native-tnl.c
> @@ -43,6 +43,7 @@
> #include "seq.h"
> #include "unaligned.h"
> #include "unixctl.h"
> +#include "util.h"
> #include "openvswitch/vlog.h"
>
> VLOG_DEFINE_THIS_MODULE(native_tnl);
> @@ -221,12 +222,13 @@ netdev_tnl_calc_udp_csum(struct udp_header *udp, struct
> dp_packet *packet,
> {
> uint32_t csum;
>
> - if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) {
> - csum = packet_csum_pseudoheader6(netdev_tnl_ipv6_hdr(
> - dp_packet_data(packet)));
> + void *data_dp = dp_packet_data(packet);
> + ovs_assert(data_dp != NULL);
> +
> + if (netdev_tnl_is_header_ipv6(data_dp)) {
> + csum = packet_csum_pseudoheader6(netdev_tnl_ipv6_hdr(data_dp));
> } else {
> - csum = packet_csum_pseudoheader(netdev_tnl_ip_hdr(
> - dp_packet_data(packet)));
> + csum = packet_csum_pseudoheader(netdev_tnl_ip_hdr(data_dp));
> }
>
> csum = csum_continue(csum, udp, ip_tot_size);
> @@ -425,7 +427,10 @@ netdev_gre_pop_header(struct dp_packet *packet)
> struct flow_tnl *tnl = &md->tunnel;
> int hlen = sizeof(struct eth_header) + 4;
>
> - hlen += netdev_tnl_is_header_ipv6(dp_packet_data(packet)) ?
> + const void *data_dp = dp_packet_data(packet);
> + ovs_assert(data_dp != NULL);
> +
> + hlen += netdev_tnl_is_header_ipv6(data_dp) ?
> IPV6_HEADER_LEN : IP_HEADER_LEN;
>
> pkt_metadata_init_tnl(md);
> diff --git a/lib/odp-execute.c b/lib/odp-execute.c
> index 5cf6fbec0..97f950c60 100644
> --- a/lib/odp-execute.c
> +++ b/lib/odp-execute.c
> @@ -147,6 +147,8 @@ odp_set_ipv4(struct dp_packet *packet, const struct
> ovs_key_ipv4 *key,
> uint8_t new_tos;
> uint8_t new_ttl;
>
> + ovs_assert(nh != NULL);
> +
> if (mask->ipv4_src) {
> ip_src_nh = get_16aligned_be32(&nh->ip_src);
> new_ip_src = key->ipv4_src | (ip_src_nh & ~mask->ipv4_src);
> @@ -276,6 +278,8 @@ set_arp(struct dp_packet *packet, const struct
> ovs_key_arp *key,
> {
> struct arp_eth_header *arp = dp_packet_l3(packet);
>
> + ovs_assert(arp != NULL);
> +
> if (!mask) {
> arp->ar_op = key->arp_op;
> arp->ar_sha = key->arp_sha;
> diff --git a/lib/pcap-file.c b/lib/pcap-file.c
> index 3ed7ea488..bedfaae14 100644
> --- a/lib/pcap-file.c
> +++ b/lib/pcap-file.c
> @@ -291,7 +291,9 @@ ovs_pcap_write(struct pcap_file *p_file, struct dp_packet
> *buf)
> prh.incl_len = dp_packet_size(buf);
> prh.orig_len = dp_packet_size(buf);
> ignore(fwrite(&prh, sizeof prh, 1, p_file->file));
> - ignore(fwrite(dp_packet_data(buf), dp_packet_size(buf), 1,
> p_file->file));
> + const void *data_dp = dp_packet_data(buf);
> + ovs_assert(data_dp != NULL);
This can be expressed closer to the first assert in the function:
assert(dp_packet_data(buf));
Or possibly(? untested) change the assert from dp_packet_is_eth to
assert(dp_packet_eth(buf));
> + ignore(fwrite(data_dp, dp_packet_size(buf), 1, p_file->file));
> fflush(p_file->file);
> }
>
> diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c
> index f67352603..d2b2f85af 100644
> --- a/lib/rtnetlink.c
> +++ b/lib/rtnetlink.c
> @@ -26,6 +26,7 @@
> #include "netlink-notifier.h"
> #include "openvswitch/ofpbuf.h"
> #include "packets.h"
> +#include "util.h"
>
> #if IFLA_INFO_MAX < 5
> #define IFLA_INFO_SLAVE_KIND 4
> @@ -131,6 +132,8 @@ rtnetlink_parse(struct ofpbuf *buf, struct
> rtnetlink_change *change)
> change->irrelevant = true;
> }
>
> + ovs_assert(ifinfo != NULL);
> +
Can we instead change the ofpbuf_at to ofpbuf_at_assert() ?
> change->nlmsg_type = nlmsg->nlmsg_type;
> change->if_index = ifinfo->ifi_index;
> change->ifname = nl_attr_get_string(attrs[IFLA_IFNAME]);
> @@ -177,6 +180,8 @@ rtnetlink_parse(struct ofpbuf *buf, struct
> rtnetlink_change *change)
>
> ifaddr = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifaddr);
>
> + ovs_assert(ifaddr != NULL);
> +
Same here
> change->nlmsg_type = nlmsg->nlmsg_type;
> change->if_index = ifaddr->ifa_index;
> change->ifname = (attrs[IFA_LABEL]
> diff --git a/lib/sflow_agent.c b/lib/sflow_agent.c
> index c95f654a5..2199b52a5 100644
> --- a/lib/sflow_agent.c
> +++ b/lib/sflow_agent.c
> @@ -153,6 +153,8 @@ void sfl_agent_tick(SFLAgent *agent, time_t now)
> SFLReceiver *sfl_agent_addReceiver(SFLAgent *agent)
> {
> SFLReceiver *rcv = (SFLReceiver *)sflAlloc(agent, sizeof(SFLReceiver));
> + ovs_assert(rcv != NULL);
> + memset(rcv, 0, sizeof(*rcv));
Maybe instead of this, we should change the SFL_ALLOC define to be
xzalloc which will guarantee a zero'd buffer that is != NULL and simply
leave the assert.
> sfl_receiver_init(rcv, agent);
> /* add to end of list - to preserve the receiver index numbers for
> existing receivers */
> {
> @@ -203,6 +205,8 @@ SFLSampler *sfl_agent_addSampler(SFLAgent *agent,
> SFLDataSource_instance *pdsi)
>
> {
> SFLSampler *newsm = (SFLSampler *)sflAlloc(agent, sizeof(SFLSampler));
> + ovs_assert(newsm != NULL);
> + memset(newsm, 0, sizeof(*newsm));
Indentation on this is wrong.
> sfl_sampler_init(newsm, agent, pdsi);
> if(prev) prev->nxt = newsm;
> else agent->samplers = newsm;
> @@ -242,6 +246,8 @@ SFLPoller *sfl_agent_addPoller(SFLAgent *agent,
> /* either we found the insert point, or reached the end of the list... */
> {
> SFLPoller *newpl = (SFLPoller *)sflAlloc(agent, sizeof(SFLPoller));
> + ovs_assert(newpl != NULL);
> + memset(newpl, 0, sizeof(*newpl));
Same here.
> sfl_poller_init(newpl, agent, pdsi, magic, getCountersFn);
> if(prev) prev->nxt = newpl;
> else agent->pollers = newpl;
> diff --git a/lib/shash.c b/lib/shash.c
> index a7b2c6458..070bc3e82 100644
> --- a/lib/shash.c
> +++ b/lib/shash.c
> @@ -17,6 +17,7 @@
> #include <config.h>
> #include "openvswitch/shash.h"
> #include "hash.h"
> +#include "util.h"
>
> static struct shash_node *shash_find__(const struct shash *,
> const char *name, size_t name_len,
> @@ -194,7 +195,9 @@ shash_replace_nocopy(struct shash *sh, char *name, const
> void *data)
> void
> shash_delete(struct shash *sh, struct shash_node *node)
> {
> - free(shash_steal(sh, node));
> + if (node) {
> + free(shash_steal(sh, node));
> + }
Consider we should move this type of check to shash steal, or possibly
change shash_steal to assert node != NULL (although, shash_steal doesn't
seem to have any other users in-tree but it is a published API).
> }
>
> /* Deletes 'node' from 'sh'. Neither the node's name nor its data is freed;
> diff --git a/lib/sset.c b/lib/sset.c
> index aa1790020..81cacefc1 100644
> --- a/lib/sset.c
> +++ b/lib/sset.c
> @@ -20,6 +20,7 @@
>
> #include "openvswitch/dynamic-string.h"
> #include "hash.h"
> +#include "util.h"
>
> static uint32_t
> hash_name__(const char *name, size_t length)
> @@ -261,6 +262,7 @@ char *
> sset_pop(struct sset *set)
> {
> const char *name = SSET_FIRST(set);
> + ovs_assert(name != NULL);
> char *copy = xstrdup(name);
> sset_delete(set, SSET_NODE_FROM_NAME(name));
> return copy;
> diff --git a/ovsdb/condition.c b/ovsdb/condition.c
> index d0016fa7f..ada8f50dc 100644
> --- a/ovsdb/condition.c
> +++ b/ovsdb/condition.c
> @@ -47,7 +47,15 @@ ovsdb_clause_from_json(const struct ovsdb_table_schema *ts,
>
> /* Column and arg fields are not being used with boolean functions.
> * Use dummy values */
> - clause->column = ovsdb_table_schema_get_column(ts, "_uuid");
> + const struct ovsdb_column *uuid_column =
> + ovsdb_table_schema_get_column(ts, "_uuid");
> + if (uuid_column) {
> + clause->column = uuid_column;
> + } else {
> + return ovsdb_syntax_error(json,
> + "unknown column",
> + "No column _uuid in table schema.");
> + }
> clause->index = clause->column->index;
> ovsdb_datum_init_default(&clause->arg, &clause->column->type);
> return NULL;
> diff --git a/ovsdb/file.c b/ovsdb/file.c
> index 2d887e53e..85de6295a 100644
> --- a/ovsdb/file.c
> +++ b/ovsdb/file.c
> @@ -522,9 +522,16 @@ ovsdb_file_txn_add_row(struct ovsdb_file_txn *ftxn,
> }
>
> if (row) {
> - struct ovsdb_table *table = new ? new->table : old->table;
> + struct ovsdb_table *table = NULL;
> + if (new) {
> + table = new->table;
> + } else if (old) {
> + table = old->table;
> + }
> char uuid[UUID_LEN + 1];
>
> + ovs_assert(table != NULL);
> +
> if (table != ftxn->table) {
> /* Create JSON object for transaction overall. */
> if (!ftxn->json) {
> @@ -538,9 +545,15 @@ ovsdb_file_txn_add_row(struct ovsdb_file_txn *ftxn,
> }
>
> /* Add row to transaction for this table. */
> - snprintf(uuid, sizeof uuid,
> - UUID_FMT, UUID_ARGS(ovsdb_row_get_uuid(new ? new : old)));
> - json_object_put(ftxn->table_json, uuid, row);
> + if (new) {
> + snprintf(uuid, sizeof uuid,
> + UUID_FMT, UUID_ARGS(ovsdb_row_get_uuid(new)));
> + json_object_put(ftxn->table_json, uuid, row);
> + } else if (old) {
> + snprintf(uuid, sizeof uuid,
> + UUID_FMT, UUID_ARGS(ovsdb_row_get_uuid(old)));
> + json_object_put(ftxn->table_json, uuid, row);
> + }
> }
> }
>
> diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
> index 17868f5b7..a3ca48a7b 100644
> --- a/ovsdb/jsonrpc-server.c
> +++ b/ovsdb/jsonrpc-server.c
> @@ -1038,7 +1038,7 @@ ovsdb_jsonrpc_session_got_request(struct
> ovsdb_jsonrpc_session *s,
> request->id);
> } else if (!strcmp(request->method, "get_schema")) {
> struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
> - if (!reply) {
> + if (db && !reply) {
> reply = jsonrpc_create_reply(ovsdb_schema_to_json(db->schema),
> request->id);
> }
> @@ -1131,6 +1131,8 @@ static void
> ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, struct ovsdb
> *db,
> struct jsonrpc_msg *request)
> {
> + ovs_assert(db);
> +
> /* Check for duplicate ID. */
> size_t hash = json_hash(request->id, 0);
> struct ovsdb_jsonrpc_trigger *t
> @@ -1391,6 +1393,8 @@ ovsdb_jsonrpc_monitor_create(struct
> ovsdb_jsonrpc_session *s, struct ovsdb *db,
> enum ovsdb_monitor_version version,
> const struct json *request_id)
> {
> + ovs_assert(db);
> +
> struct ovsdb_jsonrpc_monitor *m = NULL;
> struct ovsdb_monitor *dbmon = NULL;
> struct json *monitor_id, *monitor_requests;
> diff --git a/ovsdb/monitor.c b/ovsdb/monitor.c
> index 191befcae..7d70a39b9 100644
> --- a/ovsdb/monitor.c
> +++ b/ovsdb/monitor.c
> @@ -478,7 +478,9 @@ ovsdb_monitor_add_column(struct ovsdb_monitor *dbmon,
> struct ovsdb_monitor_column *c;
>
> mt = shash_find_data(&dbmon->tables, table->schema->name);
> -
> + if (!mt) {
> + return NULL;
> + }
> /* Check for column duplication. Return duplicated column name. */
> if (mt->columns_index_map[column->index] != -1) {
> return column->name;
> @@ -781,11 +783,15 @@ ovsdb_monitor_table_condition_update(
> const struct json *cond_json)
> {
> if (!condition) {
> - return NULL;
> + return ovsdb_syntax_error(cond_json, NULL,
> + "Parse error, condition empty.");
> }
>
> struct ovsdb_monitor_table_condition *mtc =
> shash_find_data(&condition->tables, table->schema->name);
> + if (!mtc) {
> + return NULL;
> + }
> struct ovsdb_error *error;
> struct ovsdb_condition cond = OVSDB_CONDITION_INITIALIZER(&cond);
>
> @@ -1279,6 +1285,7 @@ ovsdb_monitor_table_add_select(struct ovsdb_monitor
> *dbmon,
> struct ovsdb_monitor_table * mt;
>
> mt = shash_find_data(&dbmon->tables, table->schema->name);
> + ovs_assert(mt != NULL);
> mt->select |= select;
> }
>
> @@ -1329,8 +1336,23 @@ ovsdb_monitor_changes_update(const struct ovsdb_row
> *old,
> const struct ovsdb_monitor_table *mt,
> struct ovsdb_monitor_change_set_for_table *mcst)
> {
> - const struct uuid *uuid = ovsdb_row_get_uuid(new ? new : old);
> - struct ovsdb_monitor_row *change;
> + const struct uuid *uuid = NULL;
> +
> + if (!new && !old) {
> + return;
> + } else {
> + if (new) {
> + uuid = ovsdb_row_get_uuid(new);
> + } else if (old) {
> + uuid = ovsdb_row_get_uuid(old);
> + }
> + }
> +
> + if (!uuid) {
> + return;
> + }
> +
> + struct ovsdb_monitor_row *change = NULL;
>
> change = ovsdb_monitor_changes_row_find(mcst, uuid);
> if (!change) {
> @@ -1657,9 +1679,15 @@ ovsdb_monitor_hash(const struct ovsdb_monitor *dbmon,
> size_t basis)
> nodes = shash_sort(&dbmon->tables);
> n = shash_count(&dbmon->tables);
>
> + if (!nodes) {
> + return basis;
> + }
> +
> for (i = 0; i < n; i++) {
> struct ovsdb_monitor_table *mt = nodes[i]->data;
>
> + ovs_assert(mt != NULL);
> +
> basis = hash_pointer(mt->table, basis);
> basis = hash_3words(mt->select, mt->n_columns, basis);
>
> diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
> index f1b8d6491..a93913ed5 100644
> --- a/ovsdb/ovsdb-client.c
> +++ b/ovsdb/ovsdb-client.c
> @@ -1223,17 +1223,26 @@ parse_monitor_columns(char *arg, const char *server,
> const char *database,
>
> n = shash_count(&table->columns);
> nodes = shash_sort(&table->columns);
> - for (i = 0; i < n; i++) {
> - const struct ovsdb_column *column = nodes[i]->data;
> - if (column->index != OVSDB_COL_UUID
> - && column->index != OVSDB_COL_VERSION) {
> - add_column(server, column, columns, columns_json);
> +
> + if (nodes) {
> + for (i = 0; i < n; i++) {
> + const struct ovsdb_column *column = nodes[i]->data;
> + if (column->index != OVSDB_COL_UUID
> + && column->index != OVSDB_COL_VERSION) {
> + add_column(server, column, columns, columns_json);
> + }
> }
> + free(nodes);
> }
> - free(nodes);
>
> - add_column(server, ovsdb_table_schema_get_column(table, "_version"),
> - columns, columns_json);
> + const struct ovsdb_column *version_column =
> + ovsdb_table_schema_get_column(table, "_version");
> +
> + if (version_column) {
> + add_column(server, version_column, columns, columns_json);
> + } else {
> + VLOG_ERR("Table does not contain _version column.");
> + }
> }
>
> if (!initial || !insert || !delete || !modify) {
> @@ -1439,14 +1448,16 @@ do_monitor__(struct jsonrpc *rpc, const char
> *database,
> ovs_fatal(0, "ALL tables are not allowed with condition");
> }
>
> - for (i = 0; i < n; i++) {
> - struct ovsdb_table_schema *table = nodes[i]->data;
> + if (nodes) {
> + for (i = 0; i < n; i++) {
> + struct ovsdb_table_schema *table = nodes[i]->data;
>
> - add_monitored_table(argc, argv, server, database, NULL, table,
> - monitor_requests,
> - &mts, &n_mts, &allocated_mts);
> + add_monitored_table(argc, argv, server, database, NULL,
> table,
> + monitor_requests,
> + &mts, &n_mts, &allocated_mts);
> + }
> + free(nodes);
> }
> - free(nodes);
> }
>
> send_db_change_aware(rpc);
> @@ -1870,6 +1881,10 @@ do_dump(struct jsonrpc *rpc, const char *database,
> n_tables = shash_count(&schema->tables);
> }
>
> + if (!tables) {
> + goto end;
> + }
> +
> /* Construct transaction to retrieve entire database. */
> transaction = json_array_create_1(json_string_create(database));
> for (i = 0; i < n_tables; i++) {
> @@ -1929,8 +1944,9 @@ do_dump(struct jsonrpc *rpc, const char *database,
> }
>
> jsonrpc_msg_destroy(reply);
> - shash_destroy(&custom_columns);
> free(tables);
> +end:
> + shash_destroy(&custom_columns);
> ovsdb_schema_destroy(schema);
> }
>
> diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
> index 33ca4910d..69b151548 100644
> --- a/ovsdb/ovsdb-server.c
> +++ b/ovsdb/ovsdb-server.c
> @@ -1784,14 +1784,17 @@ ovsdb_server_list_databases(struct unixctl_conn
> *conn, int argc OVS_UNUSED,
> ds_init(&s);
>
> nodes = shash_sort(all_dbs);
> - for (i = 0; i < shash_count(all_dbs); i++) {
> - const struct shash_node *node = nodes[i];
> - struct db *db = node->data;
> - if (db->db) {
> - ds_put_format(&s, "%s\n", node->name);
> +
> + if (nodes) {
> + for (i = 0; i < shash_count(all_dbs); i++) {
> + const struct shash_node *node = nodes[i];
> + struct db *db = node->data;
> + if (db->db) {
> + ds_put_format(&s, "%s\n", node->name);
> + }
> }
> + free(nodes);
> }
> - free(nodes);
>
> unixctl_command_reply(conn, ds_cstr(&s));
> ds_destroy(&s);
> @@ -2191,6 +2194,8 @@ save_config(struct server_config *config)
> static void
> sset_from_json(struct sset *sset, const struct json *array)
> {
> + ovs_assert(array);
> +
> size_t i;
>
> sset_clear(sset);
> diff --git a/ovsdb/ovsdb-util.c b/ovsdb/ovsdb-util.c
> index 303191dc8..148230da8 100644
> --- a/ovsdb/ovsdb-util.c
> +++ b/ovsdb/ovsdb-util.c
> @@ -291,6 +291,15 @@ ovsdb_util_write_string_string_column(struct ovsdb_row
> *row,
> size_t i;
>
> column = ovsdb_table_schema_get_column(row->table->schema, column_name);
> + if (!column) {
> + VLOG_ERR("No %s column present in the %s table",
> + column_name, row->table->schema->name);
> + for (i = 0; i < n; i++) {
> + free(keys[i]);
> + free(values[i]);
> + }
> + return;
> + }
> datum = ovsdb_util_get_datum(row, column_name, OVSDB_TYPE_STRING,
> OVSDB_TYPE_STRING, UINT_MAX);
> if (!datum) {
> diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c
> index afec96264..8152f9e41 100644
> --- a/ovsdb/ovsdb.c
> +++ b/ovsdb/ovsdb.c
> @@ -39,6 +39,7 @@
> #include "transaction.h"
> #include "transaction-forward.h"
> #include "trigger.h"
> +#include "util.h"
>
> #include "openvswitch/vlog.h"
> VLOG_DEFINE_THIS_MODULE(ovsdb);
> @@ -195,7 +196,7 @@ root_set_size(const struct ovsdb_schema *schema)
> struct ovsdb_error *
> ovsdb_schema_from_json(const struct json *json, struct ovsdb_schema
> **schemap)
> {
> - struct ovsdb_schema *schema;
> + struct ovsdb_schema *schema = NULL;
> const struct json *name, *tables, *version_json, *cksum;
> struct ovsdb_error *error;
> struct shash_node *node;
> @@ -215,6 +216,9 @@ ovsdb_schema_from_json(const struct json *json, struct
> ovsdb_schema **schemap)
> return error;
> }
>
> + ovs_assert(name != NULL);
> + ovs_assert(tables != NULL);
> +
> if (version_json) {
> version = json_string(version_json);
> if (!ovsdb_is_valid_version(version)) {
> @@ -248,6 +252,8 @@ ovsdb_schema_from_json(const struct json *json, struct
> ovsdb_schema **schemap)
> shash_add(&schema->tables, table->name, table);
> }
>
> + ovs_assert(schema != NULL);
> +
> /* "isRoot" was not part of the original schema definition. Before it
> was
> * added, there was no support for garbage collection. So, for backward
> * compatibility, if the root set is empty then assume that every table
> is
> diff --git a/ovsdb/query.c b/ovsdb/query.c
> index eebe56412..b4f818b41 100644
> --- a/ovsdb/query.c
> +++ b/ovsdb/query.c
> @@ -21,6 +21,7 @@
> #include "condition.h"
> #include "row.h"
> #include "table.h"
> +#include "util.h"
>
> void
> ovsdb_query(struct ovsdb_table *table, const struct ovsdb_condition *cnd,
> @@ -91,6 +92,7 @@ ovsdb_query_distinct(struct ovsdb_table *table,
> struct ovsdb_row_hash hash;
>
> ovsdb_row_hash_init(&hash, columns);
> + ovs_assert(condition != NULL);
> ovsdb_query(table, condition, query_distinct_cb, &hash);
> HMAP_FOR_EACH (node, hmap_node, &hash.rows) {
> ovsdb_row_set_add_row(results, node->row);
> diff --git a/ovsdb/replication.c b/ovsdb/replication.c
> index 477c69d70..da82e08c5 100644
> --- a/ovsdb/replication.c
> +++ b/ovsdb/replication.c
> @@ -35,6 +35,7 @@
> #include "table.h"
> #include "transaction.h"
> #include "uuid.h"
> +#include "util.h"
>
> VLOG_DEFINE_THIS_MODULE(replication);
>
> @@ -575,15 +576,17 @@ create_monitor_request(struct ovsdb_schema *schema)
> size_t n = shash_count(&schema->tables);
> const struct shash_node **nodes = shash_sort(&schema->tables);
>
> - for (int j = 0; j < n; j++) {
> - struct ovsdb_table_schema *table = nodes[j]->data;
> + if (nodes) {
> + for (int j = 0; j < n; j++) {
> + struct ovsdb_table_schema *table = nodes[j]->data;
>
> - /* Monitor all tables not excluded. */
> - if (!excluded_tables_find(db_name, table->name)) {
> - add_monitored_table(table, monitor_request);
> + /* Monitor all tables not excluded. */
> + if (!excluded_tables_find(db_name, table->name)) {
> + add_monitored_table(table, monitor_request);
> + }
> }
> + free(nodes);
> }
> - free(nodes);
>
> /* Create a monitor request. */
> monitor = json_array_create_3(
> diff --git a/ovsdb/row.c b/ovsdb/row.c
> index d7bfbdd36..9f87c832a 100644
> --- a/ovsdb/row.c
> +++ b/ovsdb/row.c
> @@ -399,7 +399,9 @@ ovsdb_row_set_add_row(struct ovsdb_row_set *set, const
> struct ovsdb_row *row)
> set->rows = x2nrealloc(set->rows, &set->allocated_rows,
> sizeof *set->rows);
> }
> - set->rows[set->n_rows++] = row;
> + if (set->rows) {
> + set->rows[set->n_rows++] = row;
> + }
> }
>
> struct json *
> diff --git a/ovsdb/table.c b/ovsdb/table.c
> index 66071ce2f..990d49ea4 100644
> --- a/ovsdb/table.c
> +++ b/ovsdb/table.c
> @@ -158,7 +158,7 @@ ovsdb_table_schema_from_json(const struct json *json,
> const char *name,
> n_max_rows = UINT_MAX;
> }
>
> - if (shash_is_empty(json_object(columns))) {
> + if (!columns || shash_is_empty(json_object(columns))) {
> return ovsdb_syntax_error(json, NULL,
> "table must have at least one column");
> }
> diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c
> index 03541af85..72a6b29cb 100644
> --- a/ovsdb/transaction.c
> +++ b/ovsdb/transaction.c
> @@ -34,6 +34,7 @@
> #include "storage.h"
> #include "table.h"
> #include "uuid.h"
> +#include "util.h"
>
> VLOG_DEFINE_THIS_MODULE(transaction);
>
> @@ -576,6 +577,7 @@ ovsdb_txn_update_weak_refs(struct ovsdb_txn *txn
> OVS_UNUSED,
> dst_row = CONST_CAST(struct ovsdb_row *,
> ovsdb_table_get_row(weak->dst_table, &weak->dst));
>
> + ovs_assert(dst_row != NULL);
> ovs_assert(!ovsdb_row_find_weak_ref(dst_row, weak));
> hmap_insert(&dst_row->dst_refs, &weak->dst_node,
> ovsdb_weak_ref_hash(weak));
> diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
> index 2f5ac1a26..baa308661 100644
> --- a/utilities/ovs-vsctl.c
> +++ b/utilities/ovs-vsctl.c
> @@ -334,6 +334,7 @@ parse_options(int argc, char *argv[], struct shash
> *local_options)
> exit(EXIT_SUCCESS);
>
> case 't':
> + ovs_assert(optarg != NULL);
> if (!str_to_uint(optarg, 10, &timeout) || !timeout) {
> ctl_fatal("value %s on -t or --timeout is invalid", optarg);
> }
> @@ -349,10 +350,12 @@ parse_options(int argc, char *argv[], struct shash
> *local_options)
> STREAM_SSL_OPTION_HANDLERS
>
> case OPT_PEER_CA_CERT:
> + ovs_assert(optarg != NULL);
> stream_ssl_set_peer_ca_cert_file(optarg);
> break;
>
> case OPT_BOOTSTRAP_CA_CERT:
> + ovs_assert(optarg != NULL);
> stream_ssl_set_ca_cert_file(optarg, true);
> break;
>
> @@ -575,7 +578,7 @@ add_bridge_to_cache(struct vsctl_context *vsctl_ctx,
> struct ovsrec_bridge *br_cfg, const char *name,
> struct vsctl_bridge *parent, int vlan)
> {
> - struct vsctl_bridge *br = xmalloc(sizeof *br);
> + struct vsctl_bridge *br = xzalloc(sizeof *br);
> br->br_cfg = br_cfg;
> br->name = xstrdup(name);
> ovs_list_init(&br->ports);
> @@ -659,7 +662,7 @@ static struct vsctl_port *
> add_port_to_cache(struct vsctl_context *vsctl_ctx, struct vsctl_bridge
> *parent,
> struct ovsrec_port *port_cfg)
> {
> - struct vsctl_port *port;
> + struct vsctl_port *port = xzalloc(sizeof *port);
>
> if (port_cfg->tag
> && *port_cfg->tag >= 0 && *port_cfg->tag <= 4095) {
> @@ -671,7 +674,7 @@ add_port_to_cache(struct vsctl_context *vsctl_ctx, struct
> vsctl_bridge *parent,
> }
> }
>
> - port = xmalloc(sizeof *port);
> + ovs_assert(parent != NULL);
> ovs_list_push_back(&parent->ports, &port->ports_node);
> ovs_list_init(&port->ifaces);
> port->port_cfg = port_cfg;
> @@ -818,6 +821,7 @@ vsctl_context_populate_cache(struct ctl_context *ctx)
> continue;
> }
> br = shash_find_data(&vsctl_ctx->bridges, br_cfg->name);
> + ovs_assert(br != NULL);
> for (j = 0; j < br_cfg->n_ports; j++) {
> struct ovsrec_port *port_cfg = br_cfg->ports[j];
> struct vsctl_port *port;
> @@ -844,6 +848,7 @@ vsctl_context_populate_cache(struct ctl_context *ctx)
> }
>
> port = add_port_to_cache(vsctl_ctx, br, port_cfg);
> + ovs_assert(port != NULL);
> for (k = 0; k < port_cfg->n_interfaces; k++) {
> struct ovsrec_interface *iface_cfg = port_cfg->interfaces[k];
> struct vsctl_iface *iface;
> @@ -889,14 +894,23 @@ check_conflicts(struct vsctl_context *vsctl_ctx, const
> char *name,
>
> port = shash_find_data(&vsctl_ctx->ports, name);
> if (port) {
> - ctl_fatal("%s because a port named %s already exists on "
> - "bridge %s", msg, name, port->bridge->name);
> + if (port->bridge) {
> + ctl_fatal("%s because a port named %s already exists on "
> + "bridge %s", msg, name, port->bridge->name);
> + } else {
> + ctl_fatal("%s because a port named %s already exists", msg,
> name);
> + }
> }
>
> iface = shash_find_data(&vsctl_ctx->ifaces, name);
> if (iface) {
> - ctl_fatal("%s because an interface named %s already exists "
> - "on bridge %s", msg, name, iface->port->bridge->name);
> + if (iface->port->bridge) {
> + ctl_fatal("%s because an interface named %s already exists "
> + "on bridge %s", msg, name, iface->port->bridge->name);
> + } else {
> + ctl_fatal("%s because an interface named %s already exists", msg,
> + name);
> + }
> }
>
> free(msg);
> @@ -936,7 +950,7 @@ find_port(struct vsctl_context *vsctl_ctx, const char
> *name, bool must_exist)
> ovs_assert(vsctl_ctx->cache_valid);
>
> port = shash_find_data(&vsctl_ctx->ports, name);
> - if (port && !strcmp(name, port->bridge->name)) {
> + if (port && port->bridge && !strcmp(name, port->bridge->name)) {
> port = NULL;
> }
> if (must_exist && !port) {
> @@ -954,7 +968,8 @@ find_iface(struct vsctl_context *vsctl_ctx, const char
> *name, bool must_exist)
> ovs_assert(vsctl_ctx->cache_valid);
>
> iface = shash_find_data(&vsctl_ctx->ifaces, name);
> - if (iface && !strcmp(name, iface->port->bridge->name)) {
> + if (iface && iface->port->bridge &&
> + !strcmp(name, iface->port->bridge->name)) {
> iface = NULL;
> }
> if (must_exist && !iface) {
> @@ -1679,14 +1694,16 @@ get_external_id(struct smap *smap, const char
> *prefix, const char *key,
> size_t prefix_len = strlen(prefix);
> size_t i;
>
> - for (i = 0; i < smap_count(smap); i++) {
> - const struct smap_node *node = sorted[i];
> - if (!strncmp(node->key, prefix, prefix_len)) {
> - ds_put_format(output, "%s=%s\n", node->key + prefix_len,
> - node->value);
> + if (sorted) {
> + for (i = 0; i < smap_count(smap); i++) {
> + const struct smap_node *node = sorted[i];
> + if (!strncmp(node->key, prefix, prefix_len)) {
> + ds_put_format(output, "%s=%s\n", node->key + prefix_len,
> + node->value);
> + }
> }
> + free(sorted);
> }
> - free(sorted);
> }
> }
>
> diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c
> index e5d99714d..765355726 100644
> --- a/vtep/vtep-ctl.c
> +++ b/vtep/vtep-ctl.c
> @@ -250,6 +250,7 @@ parse_options(int argc, char *argv[], struct shash
> *local_options)
> exit(EXIT_SUCCESS);
>
> case 't':
> + ovs_assert(optarg != NULL);
I wonder how coverity's model broke here. It seems to inconsistently
flag the optarg tests? I didn't check every last one but it does seem
that some which are marked "required_arg" should should be generating
the correct flags for getopt are skipped and some aren't. Maybe this
needs some additional investigation?
> if (!str_to_uint(optarg, 10, &timeout) || !timeout) {
> ctl_fatal("value %s on -t or --timeout is invalid", optarg);
> }
> @@ -1065,6 +1066,7 @@ vtep_ctl_context_populate_cache(struct ctl_context *ctx)
> continue;
> }
> ps = shash_find_data(&vtepctl_ctx->pswitches, ps_cfg->name);
> + ovs_assert(ps != NULL);
> for (j = 0; j < ps_cfg->n_ports; j++) {
> struct vteprec_physical_port *port_cfg = ps_cfg->ports[j];
> struct vtep_ctl_port *port;
> @@ -1087,7 +1089,7 @@ vtep_ctl_context_populate_cache(struct ctl_context *ctx)
> }
>
> port = add_port_to_cache(vtepctl_ctx, ps, port_cfg);
> -
> + ovs_assert(port != NULL);
> for (k = 0; k < port_cfg->n_vlan_bindings; k++) {
> struct vtep_ctl_lswitch *ls;
> char *vlan;
> @@ -1892,8 +1894,10 @@ del_mcast_entry(struct ctl_context *ctx,
> vteprec_mcast_macs_remote_delete(mcast_mac->remote_cfg);
> }
>
> - free(node->data);
> - shash_delete(mcast_shash, node);
> + if (node) {
> + free(node->data);
> + shash_delete(mcast_shash, node);
> + }
Instead, consider using an ovs_assert() where the code calls
shash_find(), which should make reading this a bit more pleasant.
> } else {
> if (local) {
> vteprec_mcast_macs_local_set_locator_set(mcast_mac->local_cfg,
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev