summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-02-01 21:57:41 -0500
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-02-11 13:07:02 -0500
commit75f32f047cc380bdb648faf3ee277f7dc3cdd007 (patch)
tree62f5383768643896e2dfe2788c2bcd0933c19ab4
parent8cd095cc2724dac7523eda400522bbda41219d43 (diff)
Add memcpy_safe
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.
-rw-r--r--src/basic/hexdecoct.c3
-rw-r--r--src/basic/util.h10
-rw-r--r--src/journal/journal-file.c6
-rw-r--r--src/libsystemd-network/dhcp-option.c7
-rw-r--r--src/libsystemd-network/dhcp6-option.c3
-rw-r--r--src/libsystemd-network/test-dhcp-option.c11
-rw-r--r--src/libsystemd/sd-bus/bus-control.c3
-rw-r--r--src/libsystemd/sd-bus/bus-message.c3
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c6
-rw-r--r--src/libsystemd/sd-resolve/sd-resolve.c5
-rw-r--r--src/nspawn/nspawn.c10
-rw-r--r--src/resolve/resolved-dns-packet.c3
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;
}