From 75f32f047cc380bdb648faf3ee277f7dc3cdd007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 1 Feb 2016 21:57:41 -0500 Subject: [PATCH] Add memcpy_safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISO/IEC 9899:1999 ยง7.21.1/2 says: Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4. In base64_append_width memcpy was called as memcpy(x, NULL, 0). GCC 4.9 started making use of this and assumes This worked fine under -O0, but does something strange under -O3. This patch fixes a bug in base64_append_width(), fixes a possible bug in journal_file_append_entry_internal(), and makes use of the new function to simplify the code in other places. --- src/basic/hexdecoct.c | 3 ++- src/basic/util.h | 10 ++++++++++ src/journal/journal-file.c | 6 +++--- src/libsystemd-network/dhcp-option.c | 7 +------ src/libsystemd-network/dhcp6-option.c | 3 +-- src/libsystemd-network/test-dhcp-option.c | 11 +++-------- src/libsystemd/sd-bus/bus-control.c | 3 +-- src/libsystemd/sd-bus/bus-message.c | 3 +-- src/libsystemd/sd-bus/bus-socket.c | 6 +++--- src/libsystemd/sd-resolve/sd-resolve.c | 5 ++--- src/nspawn/nspawn.c | 10 ++++------ src/resolve/resolved-dns-packet.c | 3 +-- 12 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index f30e028f45..cbd97a1b69 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -27,6 +27,7 @@ #include "alloc-util.h" #include "hexdecoct.h" #include "macro.h" +#include "util.h" char octchar(int x) { return '0' + (x & 7); @@ -574,7 +575,7 @@ static int base64_append_width(char **prefix, int plen, if (!t) return -ENOMEM; - memcpy(t + plen, sep, slen); + memcpy_safe(t + plen, sep, slen); for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) { int act = MIN(width, avail); diff --git a/src/basic/util.h b/src/basic/util.h index 76a06822b7..b7bad76212 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -104,6 +104,16 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_ qsort(base, nmemb, size, compar); } +/** + * Normal memcpy requires src to be nonnull. We do nothing if n is 0. + */ +static inline void memcpy_safe(void *dst, const void *src, size_t n) { + if (n == 0) + return; + assert(src); + memcpy(dst, src, n); +} + int on_ac_power(void); #define memzero(x,l) (memset((x), 0, (l))) diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 2973176c8d..da8039712f 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -1110,8 +1110,8 @@ static int journal_file_append_data( } #endif - if (compression == 0 && size > 0) - memcpy(o->data.payload, data, size); + if (compression == 0) + memcpy_safe(o->data.payload, data, size); r = journal_file_link_data(f, o, p, hash); if (r < 0) @@ -1373,7 +1373,7 @@ static int journal_file_append_entry_internal( return r; o->entry.seqnum = htole64(journal_file_entry_seqnum(f, seqnum)); - memcpy(o->entry.items, items, n_items * sizeof(EntryItem)); + memcpy_safe(o->entry.items, items, n_items * sizeof(EntryItem)); o->entry.realtime = htole64(ts->realtime); o->entry.monotonic = htole64(ts->monotonic); o->entry.xor_hash = htole64(xor_hash); diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 9f0d96e57d..3ceb70f07e 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -56,12 +56,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, options[*offset] = code; options[*offset + 1] = optlen; - if (optlen) { - assert(optval); - - memcpy(&options[*offset + 2], optval, optlen); - } - + memcpy_safe(&options[*offset + 2], optval, optlen); *offset += optlen + 2; break; diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 6050851858..e858e14d97 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -73,8 +73,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, if (r < 0) return r; - if (optval) - memcpy(*buf, optval, optlen); + memcpy_safe(*buf, optval, optlen); *buf += optlen; *buflen -= optlen; diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index 7b80a5bd90..45f4e0b5f5 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -112,14 +112,9 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen, message = malloc0(len); assert_se(message); - if (options && optlen) - memcpy(&message->options, options, optlen); - - if (file && filelen <= 128) - memcpy(&message->file, file, filelen); - - if (sname && snamelen <= 64) - memcpy(&message->sname, sname, snamelen); + memcpy_safe(&message->options, options, optlen); + memcpy_safe(&message->file, file, filelen); + memcpy_safe(&message->sname, sname, snamelen); return message; } diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index ff628cfe72..00de2a95da 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1133,8 +1133,7 @@ static int add_name_change_match(sd_bus *bus, item->name_change.old_id.id = old_owner_id; item->name_change.new_id.id = new_owner_id; - if (name) - memcpy(item->name_change.name, name, l); + memcpy_safe(item->name_change.name, name, l); /* If the old name is unset or empty, then * this can match against added names */ diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index e939359338..6fd0001359 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -2633,8 +2633,7 @@ _public_ int sd_bus_message_append_array( if (r < 0) return r; - if (size > 0) - memcpy(p, ptr, size); + memcpy_safe(p, ptr, size); return 0; } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 1df571ac92..4f99719231 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -352,7 +352,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) { if (!p) return -ENOMEM; - memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); + memcpy_safe(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); memcpy(p + b->auth_iovec[0].iov_len, t, l); b->auth_iovec[0].iov_base = p; @@ -789,7 +789,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { n = m->n_iovec * sizeof(struct iovec); iov = alloca(n); - memcpy(iov, m->iovec, n); + memcpy_safe(iov, m->iovec, n); j = 0; iovec_advance(iov, &j, *idx); @@ -1000,7 +1000,7 @@ int bus_socket_read_message(sd_bus *bus) { return -ENOMEM; } - memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); bus->fds = f; bus->n_fds += n; } else diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index d6e6f396d4..c3489cb02f 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -219,9 +219,8 @@ static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *leng memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization)); memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen); - - if (ai->ai_canonname) - memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl); + memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, + ai->ai_canonname, cnl); *length += l; return (uint8_t*) p + l; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9dd4c051b2..1c010b3b84 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2580,12 +2580,10 @@ static int inner_child( /* Automatically search for the init system */ - m = 1 + strv_length(arg_parameters); - a = newa(char*, m + 1); - if (strv_isempty(arg_parameters)) - a[1] = NULL; - else - memcpy(a + 1, arg_parameters, m * sizeof(char*)); + m = strv_length(arg_parameters); + a = newa(char*, m + 2); + memcpy_safe(a + 1, arg_parameters, m * sizeof(char*)); + a[1 + m] = NULL; a[0] = (char*) "/usr/lib/systemd/systemd"; execve(a[0], a, env_use); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 5cbe20832f..abb9725b73 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -433,8 +433,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_ ((uint8_t*) d)[0] = (uint8_t) size; - if (size > 0) - memcpy(((uint8_t*) d) + 1, s, size); + memcpy_safe(((uint8_t*) d) + 1, s, size); return 0; }