[libvirt] [PATCH] Introduce virStrcpy.

Chris Lalancette clalance at redhat.com
Fri Aug 7 09:06:29 UTC 2009


Add the virStrcpy function, which takes a dst string, source string, and
number of bytes available in the dest string.  If the source string is
too large to fit into the destination string, including the \0 byte, then
no data is copied and the function returns NULL.  Otherwise, this
function copies source into dst, including the \0, and returns a pointer
to the dst string.  This function is intended to replace all unsafe
uses of strncpy in the code base, since strncpy does *not* guarantee that
the buffer terminates with a \0.

Signed-off-by: Chris Lalancette <clalance at redhat.com>
---
 cfg.mk                      |    5 ++
 proxy/libvirt_proxy.c       |    7 ++-
 qemud/Makefile.am           |    3 +-
 qemud/qemud.c               |    7 +-
 qemud/remote.c              |    9 ++-
 src/bridge.c                |   89 ++++++++--------------------
 src/datatypes.c             |    8 ++-
 src/esx/esx_driver.c        |   10 ++-
 src/esx/esx_vmx.c           |    7 ++-
 src/lxc_controller.c        |    7 ++-
 src/lxc_driver.c            |   13 ++++-
 src/nodeinfo.c              |    5 +-
 src/opennebula/one_client.c |    5 +-
 src/openvz_conf.c           |   33 +++++++---
 src/phyp/phyp_driver.c      |    2 +-
 src/proxy_internal.c        |    5 +-
 src/qemu_conf.c             |   16 +++---
 src/qemu_driver.c           |   13 +++-
 src/remote_internal.c       |   20 +++++--
 src/test.c                  |   15 ++++-
 src/uml_driver.c            |   17 ++++--
 src/util.c                  |   31 ++++++++--
 src/util.h                  |    1 +
 src/xen_internal.c          |   22 +++++--
 src/xend_internal.c         |   62 ++++++++++++++------
 src/xm_internal.c           |  134 +++++++++++++++++++++++++++---------------
 26 files changed, 343 insertions(+), 203 deletions(-)

diff --git a/cfg.mk b/cfg.mk
index 64bd26e..ad96bc6 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -91,6 +91,11 @@ sc_prohibit_asprintf:
 	msg='use virAsprintf, not a'sprintf				\
 	  $(_prohibit_regexp)
 
+sc_prohibit_strncpy:
+	@re='strncpy *\('                                               \
+	msg='use virStrcpy, not strncpy'                                \
+	  $(_prohibit_regexp)
+
 sc_prohibit_VIR_ERR_NO_MEMORY:
 	@re='\<V''IR_ERR_NO_MEMORY\>'					\
 	msg='use virReportOOMError, not V'IR_ERR_NO_MEMORY		\
diff --git a/proxy/libvirt_proxy.c b/proxy/libvirt_proxy.c
index e008a7f..42084c7 100644
--- a/proxy/libvirt_proxy.c
+++ b/proxy/libvirt_proxy.c
@@ -167,10 +167,13 @@ proxyListenUnixSocket(const char *path) {
      * Abstract socket do not hit the filesystem, way more secure and
      * guaranteed to be atomic
      */
-    memset(&addr, 0, sizeof(addr));
     addr.sun_family = AF_UNIX;
     addr.sun_path[0] = '\0';
-    strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2);
+    if (virStrcpy(&addr.sun_path[1], path, sizeof(addr.sun_path) - 1) == NULL) {
+        fprintf(stderr, "Path %s too long to fit into destination\n", path);
+        close(fd);
+        return -1;
+    }
 
     /*
      * now bind the socket to that address and listen on it
diff --git a/qemud/Makefile.am b/qemud/Makefile.am
index 5f1376e..3220ded 100644
--- a/qemud/Makefile.am
+++ b/qemud/Makefile.am
@@ -108,9 +108,10 @@ libvirtd_LDADD =					\
 	$(SASL_LIBS)					\
 	$(POLKIT_LIBS)
 
+libvirtd_LDADD += ../src/libvirt_util.la
+
 if WITH_DRIVER_MODULES
   libvirtd_LDADD += ../src/libvirt_driver.la
-  libvirtd_LDADD += ../src/libvirt_util.la
 else
 if WITH_QEMU
     libvirtd_LDADD += ../src/libvirt_driver_qemu.la
diff --git a/qemud/qemud.c b/qemud/qemud.c
index b2bd59d..17fc172 100644
--- a/qemud/qemud.c
+++ b/qemud/qemud.c
@@ -509,13 +509,14 @@ static int qemudListenUnix(struct qemud_server *server,
         virSetNonBlock(sock->fd) < 0)
         goto cleanup;
 
-    memset(&addr, 0, sizeof(addr));
     addr.sun_family = AF_UNIX;
-    strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+    if (virStrcpy(addr.sun_path, path, sizeof(addr.sun_path)) == NULL) {
+        VIR_ERROR(_("Path %s too long for unix socket"), path);
+        goto cleanup;
+    }
     if (addr.sun_path[0] == '@')
         addr.sun_path[0] = '\0';
 
-
     oldgrp = getgid();
     oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask);
     if (server->privileged)
diff --git a/qemud/remote.c b/qemud/remote.c
index 2225d06..92cc925 100644
--- a/qemud/remote.c
+++ b/qemud/remote.c
@@ -570,9 +570,12 @@ remoteDispatchDomainSetSchedulerParameters (struct qemud_server *server ATTRIBUT
 
     /* Deserialise parameters. */
     for (i = 0; i < nparams; ++i) {
-        strncpy (params[i].field, args->params.params_val[i].field,
-                 VIR_DOMAIN_SCHED_FIELD_LENGTH);
-        params[i].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+        if (virStrcpy(params[i].field, args->params.params_val[i].field,
+                      sizeof(params[i].field)) == NULL) {
+            remoteDispatchFormatError(rerr, _("Field %s too big for destination"),
+                                      args->params.params_val[i].field);
+            return -1;
+        }
         params[i].type = args->params.params_val[i].value.type;
         switch (params[i].type) {
         case VIR_DOMAIN_SCHED_FIELD_INT:
diff --git a/src/bridge.c b/src/bridge.c
index 414d87b..378c055 100644
--- a/src/bridge.c
+++ b/src/bridge.c
@@ -149,23 +149,19 @@ brHasBridge(brControl *ctl,
             const char *name)
 {
     struct ifreq ifr;
-    int len;
 
     if (!ctl || !name) {
         errno = EINVAL;
         return -1;
     }
 
-    if ((len = strlen(name)) >= BR_IFNAME_MAXLEN) {
+    memset(&ifr, 0, sizeof(struct ifreq));
+
+    if (virStrcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)) == NULL) {
         errno = EINVAL;
         return -1;
     }
 
-    memset(&ifr, 0, sizeof(struct ifreq));
-
-    strncpy(ifr.ifr_name, name, len);
-    ifr.ifr_name[len] = '\0';
-
     if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr))
         return -1;
 
@@ -216,18 +212,14 @@ brAddDelInterface(brControl *ctl,
                   const char *iface)
 {
     struct ifreq ifr;
-    int len;
 
     if (!ctl || !ctl->fd || !bridge || !iface)
         return EINVAL;
 
-    if ((len = strlen(bridge)) >= BR_IFNAME_MAXLEN)
-        return EINVAL;
-
     memset(&ifr, 0, sizeof(struct ifreq));
 
-    strncpy(ifr.ifr_name, bridge, len);
-    ifr.ifr_name[len] = '\0';
+    if (virStrcpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name)) == NULL)
+        return EINVAL;
 
     if (!(ifr.ifr_ifindex = if_nametoindex(iface)))
         return ENODEV;
@@ -305,23 +297,19 @@ brDeleteInterface(brControl *ctl ATTRIBUTE_UNUSED,
 static int ifGetMtu(brControl *ctl, const char *ifname)
 {
     struct ifreq ifr;
-    int len;
 
     if (!ctl || !ifname) {
         errno = EINVAL;
         return -1;
     }
 
-    if ((len = strlen(ifname)) >=  BR_IFNAME_MAXLEN) {
+    memset(&ifr, 0, sizeof(struct ifreq));
+
+    if (virStrcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) == NULL) {
         errno = EINVAL;
         return -1;
     }
 
-    memset(&ifr, 0, sizeof(struct ifreq));
-
-    strncpy(ifr.ifr_name, ifname, len);
-    ifr.ifr_name[len] = '\0';
-
     if (ioctl(ctl->fd, SIOCGIFMTU, &ifr))
         return -1;
 
@@ -343,18 +331,14 @@ static int ifGetMtu(brControl *ctl, const char *ifname)
 static int ifSetMtu(brControl *ctl, const char *ifname, int mtu)
 {
     struct ifreq ifr;
-    int len;
 
     if (!ctl || !ifname)
         return EINVAL;
 
-    if ((len = strlen(ifname)) >=  BR_IFNAME_MAXLEN)
-        return EINVAL;
-
     memset(&ifr, 0, sizeof(struct ifreq));
 
-    strncpy(ifr.ifr_name, ifname, len);
-    ifr.ifr_name[len] = '\0';
+    if (virStrcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) == NULL)
+        return EINVAL;
     ifr.ifr_mtu = mtu;
 
     return ioctl(ctl->fd, SIOCSIFMTU, &ifr) == 0 ? 0 : errno;
@@ -466,7 +450,7 @@ brAddTap(brControl *ctl,
          int vnet_hdr,
          int *tapfd)
 {
-    int fd, len;
+    int fd;
     struct ifreq ifr;
 
     if (!ctl || !ctl->fd || !bridge || !ifname)
@@ -486,17 +470,14 @@ brAddTap(brControl *ctl,
     (void) vnet_hdr;
 #endif
 
-    strncpy(ifr.ifr_name, *ifname, IFNAMSIZ-1);
-
-    if (ioctl(fd, TUNSETIFF, &ifr) < 0)
-        goto error;
-
-    len = strlen(ifr.ifr_name);
-    if (len >= BR_IFNAME_MAXLEN - 1) {
+    if (virStrcpy(ifr.ifr_name, *ifname, sizeof(ifr.ifr_name)) == NULL) {
         errno = EINVAL;
         goto error;
     }
 
+    if (ioctl(fd, TUNSETIFF, &ifr) < 0)
+        goto error;
+
     /* We need to set the interface MTU before adding it
      * to the bridge, because the bridge will have its
      * MTU adjusted automatically when we add the new interface.
@@ -527,7 +508,6 @@ int brDeleteTap(brControl *ctl,
                 const char *ifname)
 {
     struct ifreq try;
-    int len;
     int fd;
 
     if (!ctl || !ctl->fd || !ifname)
@@ -539,15 +519,11 @@ int brDeleteTap(brControl *ctl,
     memset(&try, 0, sizeof(struct ifreq));
     try.ifr_flags = IFF_TAP|IFF_NO_PI;
 
-    len = strlen(ifname);
-    if (len >= BR_IFNAME_MAXLEN - 1) {
+    if (virStrcpy(try.ifr_name, ifname, sizeof(try.ifr_name)) == NULL) {
         errno = EINVAL;
         goto error;
     }
 
-    strncpy(try.ifr_name, ifname, len);
-    try.ifr_name[len] = '\0';
-
     if (ioctl(fd, TUNSETIFF, &try) == 0) {
         if ((errno = ioctl(fd, TUNSETPERSIST, 0)))
             goto error;
@@ -576,19 +552,15 @@ brSetInterfaceUp(brControl *ctl,
                  int up)
 {
     struct ifreq ifr;
-    int len;
     int flags;
 
     if (!ctl || !ifname)
         return EINVAL;
 
-    if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
-        return EINVAL;
-
     memset(&ifr, 0, sizeof(struct ifreq));
 
-    strncpy(ifr.ifr_name, ifname, len);
-    ifr.ifr_name[len] = '\0';
+    if (virStrcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) == NULL)
+        return EINVAL;
 
     if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
         return errno;
@@ -621,18 +593,14 @@ brGetInterfaceUp(brControl *ctl,
                  int *up)
 {
     struct ifreq ifr;
-    int len;
 
     if (!ctl || !ifname || !up)
         return EINVAL;
 
-    if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
-        return EINVAL;
-
     memset(&ifr, 0, sizeof(struct ifreq));
 
-    strncpy(ifr.ifr_name, ifname, len);
-    ifr.ifr_name[len] = '\0';
+    if (virStrcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) == NULL)
+        return EINVAL;
 
     if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
         return errno;
@@ -654,18 +622,15 @@ brSetInetAddr(brControl *ctl,
     } s;
     struct ifreq ifr;
     struct in_addr inaddr;
-    int len, ret;
+    int ret;
 
     if (!ctl || !ctl->fd || !ifname || !addr)
         return EINVAL;
 
-    if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
-        return EINVAL;
-
     memset(&ifr, 0, sizeof(struct ifreq));
 
-    strncpy(ifr.ifr_name, ifname, len);
-    ifr.ifr_name[len] = '\0';
+    if (virStrcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) == NULL)
+        return EINVAL;
 
     if ((ret = inet_pton(AF_INET, addr, &inaddr)) < 0)
         return errno;
@@ -692,18 +657,14 @@ brGetInetAddr(brControl *ctl,
 {
     struct ifreq ifr;
     struct in_addr *inaddr;
-    int len;
 
     if (!ctl || !ctl->fd || !ifname || !addr)
         return EINVAL;
 
-    if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
-        return EINVAL;
-
     memset(&ifr, 0, sizeof(struct ifreq));
 
-    strncpy(ifr.ifr_name, ifname, len);
-    ifr.ifr_name[len] = '\0';
+    if (virStrcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) == NULL)
+        return EINVAL;
 
     if (ioctl(ctl->fd, cmd, &ifr) < 0)
         return errno;
diff --git a/src/datatypes.c b/src/datatypes.c
index ac61682..b10452e 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -25,6 +25,7 @@
 #include "virterror_internal.h"
 #include "logging.h"
 #include "memory.h"
+#include "util.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 
@@ -876,8 +877,11 @@ virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const c
             virReportOOMError(conn);
             goto error;
         }
-        strncpy(ret->key, key, sizeof(ret->key)-1);
-        ret->key[sizeof(ret->key)-1] = '\0';
+        if (virStrcpy(ret->key, key, sizeof(ret->key)) == NULL) {
+            virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("Volume key %s too large for destination"), key);
+            goto error;
+        }
         ret->magic = VIR_STORAGE_VOL_MAGIC;
         ret->conn = conn;
 
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index dba6305..c5dbda2 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -696,9 +696,13 @@ esxNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
                 ++ptr;
             }
 
-            strncpy (nodeinfo->model, dynamicProperty->val->string,
-                     sizeof (nodeinfo->model) - 1);
-            nodeinfo->model[sizeof (nodeinfo->model) - 1] = '\0';
+            if (virStrcpy(nodeinfo->model, dynamicProperty->val->string,
+                          sizeof(nodeinfo->model)) == NULL) {
+                ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                          "Model %s too long for destination",
+                          dynamicProperty->val->string);
+                goto failure;
+            }
         } else {
             VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
         }
diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c
index 91a86e2..b138d13 100644
--- a/src/esx/esx_vmx.c
+++ b/src/esx/esx_vmx.c
@@ -885,8 +885,11 @@ esxVMX_IndexToDiskName(virConnectPtr conn, int idx, const char *prefix)
         return NULL;
     }
 
-    strncpy(buffer, prefix, sizeof (buffer) - 1);
-    buffer[sizeof (buffer) - 1] = '\0';
+    if (virStrcpy(buffer, prefix, sizeof(buffer)) == NULL) {
+        ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                  "Prefix %s too big for destination", prefix);
+        return NULL;
+    }
 
     if (idx < 26) {
         buffer[length] = 'a' + idx;
diff --git a/src/lxc_controller.c b/src/lxc_controller.c
index 8d11238..6bc9976 100644
--- a/src/lxc_controller.c
+++ b/src/lxc_controller.c
@@ -176,9 +176,12 @@ static int lxcMonitorServer(const char *sockpath)
     }
 
     unlink(sockpath);
-    memset(&addr, 0, sizeof(addr));
     addr.sun_family = AF_UNIX;
-    strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+    if (virStrcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)) == NULL) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("Socket path %s too long for destination"), sockpath);
+        goto error;
+    }
 
     if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         virReportSystemError(NULL, errno,
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
index c6cf935..b42f77f 100644
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -719,7 +719,11 @@ static int lxcMonitorClient(virConnectPtr conn,
 
     memset(&addr, 0, sizeof(addr));
     addr.sun_family = AF_UNIX;
-    strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+    if (virStrcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)) == NULL) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("Socket path %s too big for destination"), sockpath);
+        goto error;
+    }
 
     if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         virReportSystemError(conn, errno, "%s",
@@ -1737,7 +1741,12 @@ static int lxcGetSchedulerParameters(virDomainPtr domain,
     if (virCgroupGetCpuShares(group, &val) != 0)
         goto cleanup;
     params[0].value.ul = val;
-    strncpy(params[0].field, "cpu_shares", sizeof(params[0].field));
+    if (virStrcpy(params[0].field, "cpu_shares",
+                  sizeof(params[0].field)) == NULL) {
+        lxcError(NULL, domain, VIR_ERR_INTERNAL_ERROR,
+                 "%s", _("Field cpu_shares too big for destination"));
+        goto cleanup;
+    }
     params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
 
     ret = 0;
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 0a211a7..b620ced 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -141,8 +141,9 @@ int nodeGetInfo(virConnectPtr conn,
 
     uname(&info);
 
-    strncpy(nodeinfo->model, info.machine, sizeof(nodeinfo->model)-1);
-    nodeinfo->model[sizeof(nodeinfo->model)-1] = '\0';
+    if (virStrcpy(nodeinfo->model, info.machine,
+                  sizeof(nodeinfo->model)) == NULL)
+        return -1;
 
 #else /* !HAVE_UNAME */
 
diff --git a/src/opennebula/one_client.c b/src/opennebula/one_client.c
index 21f303a..9d3a5c6 100644
--- a/src/opennebula/one_client.c
+++ b/src/opennebula/one_client.c
@@ -24,6 +24,8 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include "one_client.h"
+#include "datatypes.h"
+#include "util.h"
 
 oneClient one_client;
 
@@ -186,8 +188,7 @@ int c_oneVmInfo(int vmid, char* ret_info,int length)
 
     if( return_code )
     {
-        strncpy(ret_info, return_string, length-1);
-        ret_info[length-1] = '\0';
+        virStrcpy(ret_info, return_string, length);
 
         retval = 0;
     }
diff --git a/src/openvz_conf.c b/src/openvz_conf.c
index a172fe3..27f0264 100644
--- a/src/openvz_conf.c
+++ b/src/openvz_conf.c
@@ -261,8 +261,11 @@ openvzReadNetworkConf(virConnectPtr conn,
                     if (VIR_ALLOC_N(net->ifname, len+1) < 0)
                         goto no_memory;
 
-                    strncpy(net->ifname, p, len);
-                    net->ifname[len] = '\0';
+                    if (virStrcpy(net->ifname, p, len+1) == NULL) {
+                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                                    _("Network ifname %s too long for destination"), p);
+                        goto error;
+                    }
                 } else if (STRPREFIX(p, "bridge=")) {
                     p += 7;
                     len = next - p;
@@ -275,8 +278,11 @@ openvzReadNetworkConf(virConnectPtr conn,
                     if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
                         goto no_memory;
 
-                    strncpy(net->data.bridge.brname, p, len);
-                    net->data.bridge.brname[len] = '\0';
+                    if (virStrcpy(net->data.bridge.brname, p, len+1) == NULL) {
+                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                                    _("Bridge name %s too long for destination"), p);
+                        goto error;
+                    }
                 } else if (STRPREFIX(p, "mac=")) {
                     p += 4;
                     len = next - p;
@@ -285,8 +291,11 @@ openvzReadNetworkConf(virConnectPtr conn,
                               "%s", _("Wrong length MAC address"));
                         goto error;
                     }
-                    strncpy(cpy_temp, p, len);
-                    cpy_temp[len] = '\0';
+                    if (virStrcpy(cpy_temp, p, sizeof(cpy_temp)) == NULL) {
+                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                                    _("MAC address %s too long for destination"), p);
+                        goto error;
+                    }
                     if (virParseMacAddr(cpy_temp, net->mac) < 0) {
                         openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                               "%s", _("Wrong MAC address"));
@@ -629,8 +638,10 @@ openvzReadConfigParam(const char * conf_file ,const char * param, char *value, i
             if (sf[0] == '=' && sf[1] != '\0' ) {
                 sf ++;
                 if ((token = strtok_r(sf,"\"\t\n", &saveptr)) != NULL) {
-                    strncpy(value, token, maxlen) ;
-                    value[maxlen-1] = '\0';
+                    if (virStrcpy(value, token, maxlen) == NULL) {
+                        ret = -1;
+                        break;
+                    }
                     found = 1;
                 }
             }
@@ -812,6 +823,7 @@ openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
     char uuidbuf[1024];
     char iden[1024];
     int fd, ret;
+    int retval = 0;
 
     if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
        return -1;
@@ -832,13 +844,14 @@ openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
 
         sscanf(line, "%s %s\n", iden, uuidbuf);
         if(STREQ(iden, "#UUID:")) {
-            strncpy(uuidstr, uuidbuf, len);
+            if (virStrcpy(uuidstr, uuidbuf, len) == NULL)
+                retval = -1;
             break;
         }
     }
     close(fd);
 
-    return 0;
+    return retval;
 }
 
 /* Do actual checking for UUID presence in conf file,
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index f457cf4..508767e 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -1369,7 +1369,7 @@ escape_specialcharacters(char *src, char *dst, size_t dstlen)
     }
     temp_buffer[j] = '\0';
 
-    if (strncpy(dst, temp_buffer, dstlen) == NULL)
+    if (virStrcpy(dst, temp_buffer, dstlen) == NULL)
         return -1;
 
     return 0;
diff --git a/src/proxy_internal.c b/src/proxy_internal.c
index 5b92ad8..8609201 100644
--- a/src/proxy_internal.c
+++ b/src/proxy_internal.c
@@ -197,7 +197,10 @@ retry:
     memset(&addr, 0, sizeof(addr));
     addr.sun_family = AF_UNIX;
     addr.sun_path[0] = '\0';
-    strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2);
+    if (virStrcpy(&addr.sun_path[1], path, sizeof(addr.sun_path) - 1) == NULL) {
+        close(fd);
+        return -1;
+    }
 
     /*
      * now bind the socket to that address and listen on it
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 6b0b404..4690c69 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -1282,18 +1282,18 @@ static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
 {
     switch (dev->type) {
     case VIR_DOMAIN_CHR_TYPE_NULL:
-        strncpy(buf, "null", buflen);
-        buf[buflen-1] = '\0';
+        if (virStrcpy(buf, "null", buflen) == NULL)
+            return -1;
         break;
 
     case VIR_DOMAIN_CHR_TYPE_VC:
-        strncpy(buf, "vc", buflen);
-        buf[buflen-1] = '\0';
+        if (virStrcpy(buf, "vc", buflen) == NULL)
+            return -1;
         break;
 
     case VIR_DOMAIN_CHR_TYPE_PTY:
-        strncpy(buf, "pty", buflen);
-        buf[buflen-1] = '\0';
+        if (virStrcpy(buf, "pty", buflen) == NULL)
+            return -1;
         break;
 
     case VIR_DOMAIN_CHR_TYPE_DEV:
@@ -1315,8 +1315,8 @@ static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
         break;
 
     case VIR_DOMAIN_CHR_TYPE_STDIO:
-        strncpy(buf, "stdio", buflen);
-        buf[buflen-1] = '\0';
+        if (virStrcpy(buf, "stdio", buflen) == NULL)
+            return -1;
         break;
 
     case VIR_DOMAIN_CHR_TYPE_UDP:
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index 37fdec2..bcacd41 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -909,7 +909,11 @@ qemudOpenMonitorUnix(virConnectPtr conn,
 
     memset(&addr, 0, sizeof(addr));
     addr.sun_family = AF_UNIX;
-    strncpy(addr.sun_path, monitor, sizeof(addr.sun_path));
+    if (virStrcpy(addr.sun_path, monitor, sizeof(addr.sun_path)) == NULL) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("Monitor path %s too big for destination"), monitor);
+        goto error;
+    }
 
     do {
         ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr));
@@ -5802,8 +5806,11 @@ static int qemuGetSchedulerParameters(virDomainPtr dom,
         goto cleanup;
     }
     params[0].value.ul = val;
-    strncpy(params[0].field, "cpu_shares", sizeof(params[0].field));
-    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
+    if (virStrcpy(params[0].field, "cpu_shares", sizeof(params[0].field)) == NULL) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "%s", _("Field cpu_shares too long for destination"));
+        goto cleanup;
+    }
 
     ret = 0;
 
diff --git a/src/remote_internal.c b/src/remote_internal.c
index ad0cbf0..bc69c70 100644
--- a/src/remote_internal.c
+++ b/src/remote_internal.c
@@ -670,7 +670,11 @@ doRemoteOpen (virConnectPtr conn,
 
         memset (&addr, 0, sizeof addr);
         addr.sun_family = AF_UNIX;
-        strncpy (addr.sun_path, sockname, UNIX_PATH_MAX (addr));
+        if (virStrcpy(addr.sun_path, sockname, sizeof(addr.sun_path)) == NULL) {
+            errorf(conn, VIR_ERR_INTERNAL_ERROR,
+                   _("Socket %s too big for destination"), sockname);
+            goto failed;
+        }
         if (addr.sun_path[0] == '@')
             addr.sun_path[0] = '\0';
 
@@ -1585,8 +1589,8 @@ remoteNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info)
               (xdrproc_t) xdr_remote_node_get_info_ret, (char *) &ret) == -1)
         goto done;
 
-    strncpy (info->model, ret.model, 32);
-    info->model[31] = '\0';
+    if (virStrcpy(info->model, ret.model, sizeof(info->model)) == NULL)
+        goto done;
     info->memory = ret.memory;
     info->cpus = ret.cpus;
     info->mhz = ret.mhz;
@@ -3017,9 +3021,13 @@ remoteDomainGetSchedulerParameters (virDomainPtr domain,
 
     /* Deserialise the result. */
     for (i = 0; i < *nparams; ++i) {
-        strncpy (params[i].field, ret.params.params_val[i].field,
-                 VIR_DOMAIN_SCHED_FIELD_LENGTH);
-        params[i].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+        if (virStrcpy(params[i].field, ret.params.params_val[i].field,
+                      sizeof(params[i].field)) == NULL) {
+            errorf(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                   _("Parameter %s too big for destination"),
+                   ret.params.params_val[i].field);
+            goto cleanup;
+        }
         params[i].type = ret.params.params_val[i].value.type;
         switch (params[i].type) {
         case VIR_DOMAIN_SCHED_FIELD_INT:
diff --git a/src/test.c b/src/test.c
index ab6cfdf..e265d38 100644
--- a/src/test.c
+++ b/src/test.c
@@ -570,8 +570,11 @@ static int testOpenFromFile(virConnectPtr conn,
 
     privconn->nextDomID = 1;
     privconn->numCells = 0;
-    strncpy(privconn->path, file, PATH_MAX-1);
-    privconn->path[PATH_MAX-1] = '\0';
+    if (virStrcpy(privconn->path, file, sizeof(privconn->path)) == NULL) {
+        testError(NULL, VIR_ERR_INTERNAL_ERROR,
+                  _("Path %s too big for destination"), file);
+        goto error;
+    }
     memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
 
     nodeInfo = &privconn->nodeInfo;
@@ -627,8 +630,12 @@ static int testOpenFromFile(virConnectPtr conn,
 
     str = virXPathString(conn, "string(/node/cpu/model[1])", ctxt);
     if (str != NULL) {
-        strncpy(nodeInfo->model, str, sizeof(nodeInfo->model)-1);
-        nodeInfo->model[sizeof(nodeInfo->model)-1] = '\0';
+        if (virStrcpy(nodeInfo->model, str, sizeof(nodeInfo->model)) == NULL) {
+            testError(NULL, VIR_ERR_INTERNAL_ERROR,
+                      _("Model %s too big for destination"), str);
+            VIR_FREE(str);
+            goto error;
+        }
         VIR_FREE(str);
     }
 
diff --git a/src/uml_driver.c b/src/uml_driver.c
index 53e7e10..815a4b3 100644
--- a/src/uml_driver.c
+++ b/src/uml_driver.c
@@ -562,6 +562,7 @@ static int umlMonitorAddress(virConnectPtr conn,
                              virDomainObjPtr vm,
                              struct sockaddr_un *addr) {
     char *sockname;
+    int retval = 0;
 
     if (virAsprintf(&sockname, "%s/%s/mconsole",
                     driver->monitorDir, vm->def->name) < 0) {
@@ -571,10 +572,13 @@ static int umlMonitorAddress(virConnectPtr conn,
 
     memset(addr, 0, sizeof *addr);
     addr->sun_family = AF_UNIX;
-    strncpy(addr->sun_path, sockname, sizeof(addr->sun_path)-1);
-    NUL_TERMINATE(addr->sun_path);
+    if (virStrcpy(addr->sun_path, sockname, sizeof(addr->sun_path)) == NULL) {
+        umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                       _("Unix path %s too long for destination"), sockname);
+        retval = -1;
+    }
     VIR_FREE(sockname);
-    return 0;
+    return retval;
 }
 
 static int umlOpenMonitor(virConnectPtr conn,
@@ -668,8 +672,11 @@ static int umlMonitorCommand(virConnectPtr conn,
                              cmd, req.length);
         return -1;
     }
-    strncpy(req.data, cmd, req.length);
-    req.data[req.length] = '\0';
+    if (virStrcpy(req.data, cmd, sizeof(req.data)) == NULL) {
+        umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                       _("Command %s too long for destination"), cmd);
+        return -1;
+    }
 
     if (sendto(vm->monitor, &req, sizeof req, 0,
                (struct sockaddr *)&addr, sizeof addr) != (sizeof req)) {
diff --git a/src/util.c b/src/util.c
index 0d4f3fa..0d252e6 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1121,9 +1121,8 @@ char *virFindFileInPath(const char *file)
     char fullpath[PATH_MAX];
 
     /* copy PATH env so we can tweak it */
-    strncpy(pathenv, getenv("PATH"), PATH_MAX);
-    pathenv[PATH_MAX - 1] = '\0';
-
+    if (virStrcpy(pathenv, getenv("PATH"), sizeof(pathenv)) == NULL)
+        return NULL;
 
     /* for each path segment, append the file to search for and test for
      * it. return it if found.
@@ -1155,8 +1154,8 @@ int virFileMakePath(const char *path)
     if (stat(path, &st) >= 0)
         return 0;
 
-    strncpy(parent, path, PATH_MAX);
-    parent[PATH_MAX - 1] = '\0';
+    if (virStrcpy(parent, path, sizeof(parent)) == NULL)
+        return EINVAL;
 
     if (!(p = strrchr(parent, '/')))
         return EINVAL;
@@ -1573,6 +1572,28 @@ virAsprintf(char **strp, const char *fmt, ...)
     return ret;
 }
 
+/**
+ * virStrcpy
+ *
+ * A safe version of strcpy.  The last parameter is the number of bytes
+ * available in the destination string, *not* the number of bytes you want
+ * to copy.  If the destination is not large enough to hold all of the
+ * src string, NULL is returned and no data is copied.  If the destination
+ * is large enough to hold all of the src, then the string is copied and
+ * a pointer to the destination string is returned.
+ */
+char *
+virStrcpy(char *dest, const char *src, size_t destbytes)
+{
+    int len;
+
+    len = strlen(src) + 1;
+    if (len > destbytes)
+        return NULL;
+
+    return memcpy(dest, src, len);
+}
+
 /* Compare two MAC addresses, ignoring differences in case,
  * as well as leading zeros.
  */
diff --git a/src/util.h b/src/util.h
index b3e628a..ffbf2b3 100644
--- a/src/util.h
+++ b/src/util.h
@@ -164,6 +164,7 @@ void virSkipSpaces(const char **str);
 int virParseNumber(const char **str);
 int virAsprintf(char **strp, const char *fmt, ...)
     ATTRIBUTE_FMT_PRINTF(2, 3);
+char *virStrcpy(char *dest, const char *src, size_t destbytes);
 
 #define VIR_MAC_BUFLEN 6
 #define VIR_MAC_PREFIX_BUFLEN 3
diff --git a/src/xen_internal.c b/src/xen_internal.c
index ae78f84..fcc4977 100644
--- a/src/xen_internal.c
+++ b/src/xen_internal.c
@@ -1208,13 +1208,21 @@ xenHypervisorGetSchedulerParameters(virDomainPtr domain,
                 if (ret < 0)
                     return(-1);
 
-                strncpy (params[0].field, str_weight, VIR_DOMAIN_SCHED_FIELD_LENGTH);
-                params[0].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+                if (virStrcpy(params[0].field, str_weight,
+                              sizeof(params[0].field)) == NULL) {
+                    virXenError (domain->conn, VIR_ERR_INTERNAL_ERROR,
+                                 "Weight %s too big for destination", str_weight);
+                    return -1;
+                }
                 params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
                 params[0].value.ui = op_dom.u.getschedinfo.u.credit.weight;
 
-                strncpy (params[1].field, str_cap, VIR_DOMAIN_SCHED_FIELD_LENGTH);
-                params[1].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+                if (virStrcpy(params[1].field, str_cap,
+                              sizeof(params[1].field)) == NULL) {
+                    virXenError (domain->conn, VIR_ERR_INTERNAL_ERROR,
+                                 "Cap %s too big for destination", str_cap);
+                    return -1;
+                }
                 params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
                 params[1].value.ui = op_dom.u.getschedinfo.u.credit.cap;
 
@@ -2431,9 +2439,9 @@ xenHypervisorMakeCapabilitiesInternal(virConnectPtr conn,
         while (fgets (line, sizeof line, cpuinfo)) {
             if (regexec (&flags_hvm_rec, line, sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
                 && subs[0].rm_so != -1) {
-                strncpy (hvm_type,
-                         &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1);
-                hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0';
+                if (virStrcpy(hvm_type, &line[subs[1].rm_so],
+                              sizeof(hvm_type)) == NULL)
+                    return NULL;
             } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0)
                 host_pae = 1;
         }
diff --git a/src/xend_internal.c b/src/xend_internal.c
index 7bcee7d..a7167ae 100644
--- a/src/xend_internal.c
+++ b/src/xend_internal.c
@@ -763,7 +763,8 @@ xenDaemonOpen_unix(virConnectPtr conn, const char *path)
     addr = (struct sockaddr_un *)&priv->addr;
     addr->sun_family = AF_UNIX;
     memset(addr->sun_path, 0, sizeof(addr->sun_path));
-    strncpy(addr->sun_path, path, sizeof(addr->sun_path));
+    if (virStrcpy(addr->sun_path, path, sizeof(addr->sun_path)) == NULL)
+        return -1;
 
     return (0);
 }
@@ -1442,8 +1443,11 @@ xenDaemonParseSxprChar(virConnectPtr conn,
         return NULL;
     }
 
-    strncpy(prefix, value, sizeof(prefix)-1);
-    NUL_TERMINATE(prefix);
+    if (virStrcpy(prefix, value, sizeof(prefix)) == NULL) {
+        virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                     _("Value %s too big for prefix"), value);
+        goto error;
+    }
 
     if (value[0] == '/') {
         def->type = VIR_DOMAIN_CHR_TYPE_DEV;
@@ -1647,8 +1651,12 @@ xenDaemonParseSxprDisks(virConnectPtr conn,
 
                 if (VIR_ALLOC_N(disk->driverName, (offset-src)+1) < 0)
                     goto no_memory;
-                strncpy(disk->driverName, src, (offset-src));
-                disk->driverName[offset-src] = '\0';
+                if (virStrcpy(disk->driverName, src, (offset-src)+1) == NULL) {
+                    virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 _("Driver name %s too big for destination"),
+                                 src);
+                    goto error;
+                }
 
                 src = offset + 1;
 
@@ -1662,8 +1670,12 @@ xenDaemonParseSxprDisks(virConnectPtr conn,
 
                     if (VIR_ALLOC_N(disk->driverType, (offset-src)+1)< 0)
                         goto no_memory;
-                    strncpy(disk->driverType, src, (offset-src));
-                    disk->driverType[offset-src] = '\0';
+                    if (virStrcpy(disk->driverType, src, (offset-src)+1) == NULL) {
+                        virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                                     _("Driver type %s too big for destination"),
+                                     src);
+                        goto error;
+                    }
 
                     src = offset + 1;
                     /* Its possible to use blktap driver for block devs
@@ -1896,8 +1908,12 @@ xenDaemonParseSxprSound(virConnectPtr conn,
                                  _("unexpected sound model %s"), offset);
                 goto error;
             }
-            strncpy(model, offset, len);
-            model[len] = '\0';
+            if (virStrcpy(model, offset, sizeof(model)) == NULL) {
+                virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 _("Sound model %s too big for destination"),
+                             offset);
+                goto error;
+            }
 
             if (VIR_ALLOC(sound) < 0)
                 goto no_memory;
@@ -4786,13 +4802,22 @@ xenDaemonGetSchedulerParameters(virDomainPtr domain,
                 goto error;
             }
 
-            strncpy (params[0].field, str_weight, VIR_DOMAIN_SCHED_FIELD_LENGTH);
-            params[0].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+            if (virStrcpy(params[0].field, str_weight,
+                          sizeof(params[0].field)) == NULL) {
+                virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                             _("Weight %s too big for destination"),
+                             str_weight);
+                goto error;
+            }
             params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
             params[0].value.ui = sexpr_int(root, "domain/cpu_weight");
 
-            strncpy (params[1].field, str_cap, VIR_DOMAIN_SCHED_FIELD_LENGTH);
-            params[1].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+            if (virStrcpy(params[1].field, str_cap,
+                          sizeof(params[1].field)) == NULL) {
+                virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                             _("Cap %s too big for destination"), str_cap);
+                goto error;
+            }
             params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
             params[1].value.ui = sexpr_int(root, "domain/cpu_cap");
             *nparams = XEN_SCHED_CRED_NPARAM;
@@ -5842,6 +5867,7 @@ virDomainXMLDevID(virDomainPtr domain,
 {
     xenUnifiedPrivatePtr priv = domain->conn->privateData;
     char *xref;
+    char *tmp;
 
     if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
         if (dev->data.disk->driverName &&
@@ -5859,9 +5885,10 @@ virDomainXMLDevID(virDomainPtr domain,
         if (xref == NULL)
             return -1;
 
-        strncpy(ref, xref, ref_len);
+        tmp = virStrcpy(ref, xref, ref_len);
         free(xref);
-        ref[ref_len - 1] = '\0';
+        if (tmp == NULL)
+            return -1;
     } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
         char mac[30];
         virDomainNetDefPtr def = dev->data.net;
@@ -5878,9 +5905,10 @@ virDomainXMLDevID(virDomainPtr domain,
         if (xref == NULL)
             return -1;
 
-        strncpy(ref, xref, ref_len);
+        tmp = virStrcpy(ref, xref, ref_len);
         free(xref);
-        ref[ref_len - 1] = '\0';
+        if (tmp == NULL)
+            return -1;
     } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
                dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
                dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
diff --git a/src/xm_internal.c b/src/xm_internal.c
index 71b852e..00d9e9a 100644
--- a/src/xm_internal.c
+++ b/src/xm_internal.c
@@ -872,8 +872,12 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
             } else {
                 if (VIR_ALLOC_N(disk->src, (offset - head) + 1) < 0)
                     goto no_memory;
-                strncpy(disk->src, head, (offset - head));
-                disk->src[(offset-head)] = '\0';
+                if (virStrcpy(disk->src, head, (offset - head) + 1) == NULL) {
+                    xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                               _("Source file %s too big for destination"),
+                               head);
+                    goto cleanup;
+                }
             }
             head = offset + 1;
 
@@ -886,8 +890,11 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
                 goto skipdisk;
             if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
                 goto no_memory;
-            strncpy(disk->dst, head, (offset - head));
-            disk->dst[(offset-head)] = '\0';
+            if (virStrcpy(disk->dst, head, (offset - head) + 1) == NULL) {
+                xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                           _("Dest file %s too big for destination"), head);
+                goto cleanup;
+            }
             head = offset + 1;
 
 
@@ -897,8 +904,13 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
                 if ((tmp = strchr(disk->src, ':')) != NULL) {
                     if (VIR_ALLOC_N(disk->driverName, (tmp - disk->src) + 1) < 0)
                         goto no_memory;
-                    strncpy(disk->driverName, disk->src, (tmp - disk->src));
-                    disk->driverName[tmp - disk->src] = '\0';
+                    if (virStrcpy(disk->driverName, disk->src,
+                                  (tmp - disk->src) + 1) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("Driver name %s too big for destination"),
+                                   disk->src);
+                        goto cleanup;
+                    }
 
                     /* Strip the prefix we found off the source file name */
                     memmove(disk->src, disk->src+(tmp-disk->src)+1,
@@ -912,8 +924,13 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
                         goto skipdisk;
                     if (VIR_ALLOC_N(disk->driverType, (tmp - disk->src) + 1) < 0)
                         goto no_memory;
-                    strncpy(disk->driverType, disk->src, (tmp - disk->src));
-                    disk->driverType[tmp - disk->src] = '\0';
+                    if (virStrcpy(disk->driverType, disk->src,
+                                  (tmp - disk->src) + 1) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("Driver type %s too big for destination"),
+                                   disk->src);
+                        goto cleanup;
+                    }
 
                     /* Strip the prefix we found off the source file name */
                     memmove(disk->src, disk->src+(tmp-disk->src)+1,
@@ -1026,42 +1043,46 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
                 data++;
 
                 if (STRPREFIX(key, "mac=")) {
-                    int len = nextkey ? (nextkey - data) : 17;
-                    if (len > 17)
-                        len = 17;
-                    strncpy(mac, data, len);
-                    mac[len] = '\0';
+                    if (virStrcpy(mac, data, sizeof(mac)) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("MAC address %s too big for destination"),
+                                   data);
+                        goto cleanup;
+                    }
                 } else if (STRPREFIX(key, "bridge=")) {
-                    int len = nextkey ? (nextkey - data) : sizeof(bridge)-1;
+                    if (virStrcpy(bridge, data, sizeof(bridge)) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("Bridge %s too big for destination"),
+                                   data);
+                        goto cleanup;
+                    }
                     type = 1;
-                    if (len > (sizeof(bridge)-1))
-                        len = sizeof(bridge)-1;
-                    strncpy(bridge, data, len);
-                    bridge[len] = '\0';
                 } else if (STRPREFIX(key, "script=")) {
-                    int len = nextkey ? (nextkey - data) : PATH_MAX-1;
-                    if (len > (PATH_MAX-1))
-                        len = PATH_MAX-1;
-                    strncpy(script, data, len);
-                    script[len] = '\0';
+                    if (virStrcpy(script, data, sizeof(script)) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("Script %s too big for destination"),
+                                   data);
+                        goto cleanup;
+                    }
                 } else if (STRPREFIX(key, "model=")) {
-                    int len = nextkey ? (nextkey - data) : sizeof(model)-1;
-                    if (len > (sizeof(model)-1))
-                        len = sizeof(model)-1;
-                    strncpy(model, data, len);
-                    model[len] = '\0';
+                    if (virStrcpy(model, data, sizeof(model)) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("Model %s too big for destination"), data);
+                        goto cleanup;
+                    }
                 } else if (STRPREFIX(key, "vifname=")) {
-                    int len = nextkey ? (nextkey - data) : sizeof(vifname)-1;
-                    if (len > (sizeof(vifname)-1))
-                        len = sizeof(vifname)-1;
-                    strncpy(vifname, data, len);
-                    vifname[len] = '\0';
+                    if (virStrcpy(vifname, data, sizeof(vifname)) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("Vifname %s too big for destination"),
+                                   data);
+                        goto cleanup;
+                    }
                 } else if (STRPREFIX(key, "ip=")) {
-                    int len = nextkey ? (nextkey - data) : 15;
-                    if (len > 15)
-                        len = 15;
-                    strncpy(ip, data, len);
-                    ip[len] = '\0';
+                    if (virStrcpy(ip, data, sizeof(ip)) == NULL) {
+                        xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("IP %s too big for destination"), data);
+                        goto cleanup;
+                    }
                 }
 
                 while (nextkey && (nextkey[0] == ',' ||
@@ -1168,29 +1189,41 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
             if ((nextkey - key) > (sizeof(domain)-1))
                 goto skippci;
 
-            strncpy(domain, key, sizeof(domain));
-            domain[sizeof(domain)-1] = '\0';
+            if (virStrcpy(domain, key, sizeof(domain)) == NULL) {
+                xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                           _("Domain %s too big for destination"), key);
+                goto cleanup;
+            }
 
             key = nextkey + 1;
             if (!(nextkey = strchr(key, ':')))
                 goto skippci;
 
-            strncpy(bus, key, sizeof(bus));
-            bus[sizeof(bus)-1] = '\0';
+            if (virStrcpy(bus, key, sizeof(bus)) == NULL) {
+                xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                           _("Bus %s too big for destination"), key);
+                goto cleanup;
+            }
 
             key = nextkey + 1;
             if (!(nextkey = strchr(key, '.')))
                 goto skippci;
 
-            strncpy(slot, key, sizeof(slot));
-            slot[sizeof(slot)-1] = '\0';
+            if (virStrcpy(slot, key, sizeof(slot)) == NULL) {
+                xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                           _("Slot %s too big for destination"), key);
+                goto cleanup;
+            }
 
             key = nextkey + 1;
             if (strlen(key) != 1)
                 goto skippci;
 
-            strncpy(func, key, sizeof(func));
-            func[sizeof(func)-1] = '\0';
+            if (virStrcpy(func, key, sizeof(func)) == NULL) {
+                xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                           _("Function %s too big for destination"), key);
+                goto cleanup;
+            }
 
             if (virStrToLong_i(domain, NULL, 16, &domainID) < 0)
                 goto skippci;
@@ -1301,8 +1334,13 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
             list->list->str) {
             char vfb[MAX_VFB];
             char *key = vfb;
-            strncpy(vfb, list->list->str, MAX_VFB-1);
-            vfb[MAX_VFB-1] = '\0';
+
+            if (virStrcpy(vfb, list->list->str, sizeof(vfb)) == NULL) {
+                xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+                           _("VFB %s too big for destination"),
+                           list->list->str);
+                goto cleanup;
+            }
 
             if (VIR_ALLOC(graphics) < 0)
                 goto no_memory;
-- 
1.6.0.6




More information about the libvir-list mailing list