Patchwork [1/1] Fix "strcpy" calls

login
register
mail settings
Submitter Crístian Viana
Date May 30, 2012, 4:59 a.m.
Message ID <1338353975-28363-1-git-send-email-vianac@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/161846/
State New
Headers show

Comments

Crístian Viana - May 30, 2012, 4:59 a.m.
Replace some "strcpy" and "strncpy" calls by "pstrcpy" because the former ones
may cause buffer overflow and may also not write a null-terminating character at
the end of the resulting string

Signed-off-by: Crístian Viana <vianac@linux.vnet.ibm.com>
---
According to the file HACKING, the functions "strcpy" and "strncpy" should not be
used. I have searched for all the code and replaced most of those calls
by "pstrcpy". I will send other patches fixing the same thing with the functions
"strcat" -> "pstrcat" and "sprintf" -> "snprintf".
There are a few strcpy/strncpy calls that have been left out because I don't
know how to find the original string length in those cases. Here they are:

$ git grep -c '[^p]strcpy' | sort -n -r -t : -k 2
hw/nseries.c:28
i386-dis.c:25
cris-dis.c:7
linux-user/syscall.c:6
pc-bios/slof.bin:1
pc-bios/openbios-sparc64:1
pc-bios/openbios-sparc32:1
pc-bios/openbios-ppc:1
block/raw-posix.c:1

$ git grep -c '[^p]strncpy' | sort -n -r -t : -k 2
pc-bios/slof.bin:2
hw/acpi.c:1
HACKING:1

I also tried to comply with the script checkpatch.pl, so I made other changes
(not technically related to the patch) to the code to make sure the patch has no
errors or warnings, even when they leave that code inconsistent with the rest of
the file. If this is not desired, please let me know.

 block.c                        |    2 +-
 block/qcow2.c                  |    2 +-
 block/rbd.c                    |    2 +-
 block/sheepdog.c               |   22 +++++++++----------
 block/vmdk.c                   |    2 +-
 bsd-user/syscall.c             |    6 +++---
 cmd.c                          |   10 ++++-----
 fsdev/virtfs-proxy-helper.c    |    2 +-
 hw/9pfs/virtio-9p-posix-acl.c  |    4 ++--
 hw/9pfs/virtio-9p-proxy.c      |    4 ++--
 hw/9pfs/virtio-9p-synth.c      |    6 +++---
 hw/9pfs/virtio-9p-xattr-user.c |    2 +-
 hw/9pfs/virtio-9p-xattr.c      |    2 +-
 hw/bt-hci.c                    |    2 +-
 hw/ide/core.c                  |    9 +++++---
 hw/lm32_hwsetup.h              |    2 +-
 hw/r2d.c                       |    4 ++--
 hw/scsi-bus.c                  |    2 +-
 hw/spapr_vscsi.c               |    4 ++--
 hw/usb/host-linux.c            |    2 +-
 hw/virtio-blk.c                |    6 +++---
 hw/xen_backend.c               |    2 +-
 ia64-dis.c                     |   46 +++++++++++++++++++++++++++++-----------
 libcacard/vcard_emul_nss.c     |    2 +-
 libcacard/vscclient.c          |    2 +-
 linux-user/elfload.c           |    3 +--
 linux-user/syscall.c           |    2 +-
 microblaze-dis.c               |   28 ++++++++++++------------
 os-posix.c                     |    2 +-
 qga/commands-posix.c           |    2 +-
 slirp/ip_icmp.c                |    4 ++--
 slirp/misc.c                   |    2 +-
 target-i386/cpu.c              |    2 +-
 target-ppc/kvm.c               |    2 +-
 tests/tcg/cris/check_openpf1.c |    2 +-
 tests/tcg/cris/check_openpf5.c |    2 +-
 ui/vnc-auth-sasl.c             |    2 +-
 ui/vnc-tls.c                   |    2 +-
 38 files changed, 114 insertions(+), 90 deletions(-)
Peter Maydell - May 30, 2012, 5:41 a.m.
On 30 May 2012 05:59, Crístian Viana <vianac@linux.vnet.ibm.com> wrote:
> Replace some "strcpy" and "strncpy" calls by "pstrcpy" because the former ones
> may cause buffer overflow and may also not write a null-terminating character at
> the end of the resulting string
>
> Signed-off-by: Crístian Viana <vianac@linux.vnet.ibm.com>

Nak. This is duplicating a much better patchset from Jim Meyering:
http://lists.gnu.org/archive/html/qemu-devel/2012-05/msg01151.html

-- PMM
Crístian Viana - May 30, 2012, 4:11 p.m.
On 30-05-2012 02:41, Peter Maydell wrote:
> Nak. This is duplicating a much better patchset from Jim Meyering: 
> http://lists.gnu.org/archive/html/qemu-devel/2012-05/msg01151.html -- PMM 

Sorry, I hadn't seen his patchset. Is it OK for me to proceed with a 
similar patch regarding the function "strcat"?

Patch

diff --git a/block.c b/block.c
index af2ab4f..22b48c0 100644
--- a/block.c
+++ b/block.c
@@ -1252,7 +1252,7 @@  int bdrv_commit(BlockDriverState *bs)
 
     backing_drv = bs->backing_hd->drv;
     ro = bs->backing_hd->read_only;
-    strncpy(filename, bs->backing_hd->filename, sizeof(filename));
+    pstrcpy(filename, sizeof(filename), bs->backing_hd->filename);
     open_flags =  bs->backing_hd->open_flags;
 
     if (ro) {
diff --git a/block/qcow2.c b/block/qcow2.c
index c2e49cd..06f263c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -994,7 +994,7 @@  int qcow2_update_header(BlockDriverState *bs)
             goto fail;
         }
 
-        strncpy(buf, bs->backing_file, buflen);
+        pstrcpy(buf, buflen, bs->backing_file);
 
         header->backing_file_offset = cpu_to_be64(buf - ((char*) header));
         header->backing_file_size   = cpu_to_be32(backing_file_len);
diff --git a/block/rbd.c b/block/rbd.c
index 1280d66..4029e02 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -221,7 +221,7 @@  static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
 
         if (strncmp(p, "id=", 3) == 0) {
             len -= 3;
-            strncpy(clientname, p + 3, len);
+            pstrcpy(clientname, len, p + 3);
             clientname[len] = '\0';
             return clientname;
         }
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 6d52277..5b7b463 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -857,14 +857,14 @@  static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
         s->port = 0;
     }
 
-    strncpy(vdi, p, SD_MAX_VDI_LEN);
+    pstrcpy(vdi, SD_MAX_VDI_LEN, p);
 
     p = strchr(vdi, ':');
     if (p) {
         *p++ = '\0';
         *snapid = strtoul(p, NULL, 10);
         if (*snapid == 0) {
-            strncpy(tag, p, SD_MAX_VDI_TAG_LEN);
+            pstrcpy(tag, SD_MAX_VDI_TAG_LEN, p);
         }
     } else {
         *snapid = CURRENT_VDI_ID; /* search current vdi */
@@ -892,8 +892,8 @@  static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
     }
 
     memset(buf, 0, sizeof(buf));
-    strncpy(buf, filename, SD_MAX_VDI_LEN);
-    strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN);
+    pstrcpy(buf, SD_MAX_VDI_LEN, filename);
+    pstrcpy(buf + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, tag);
 
     memset(&hdr, 0, sizeof(hdr));
     if (for_snapshot) {
@@ -1141,7 +1141,7 @@  static int sd_open(BlockDriverState *bs, const char *filename, int flags)
     s->max_dirty_data_idx = 0;
 
     bs->total_sectors = s->inode.vdi_size / SECTOR_SIZE;
-    strncpy(s->name, vdi, sizeof(s->name));
+    pstrcpy(s->name, sizeof(s->name), vdi);
     qemu_co_mutex_init(&s->lock);
     g_free(buf);
     return 0;
@@ -1170,7 +1170,7 @@  static int do_sd_create(char *filename, int64_t vdi_size,
     }
 
     memset(buf, 0, sizeof(buf));
-    strncpy(buf, filename, SD_MAX_VDI_LEN);
+    pstrcpy(buf, SD_MAX_VDI_LEN, filename);
 
     memset(&hdr, 0, sizeof(hdr));
     hdr.opcode = SD_OP_NEW_VDI;
@@ -1740,7 +1740,7 @@  static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 
     s->inode.vm_state_size = sn_info->vm_state_size;
     s->inode.vm_clock_nsec = sn_info->vm_clock_nsec;
-    strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag));
+    pstrcpy(s->inode.tag, sizeof(s->inode.tag), sn_info->name);
     /* we don't need to update entire object */
     datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
 
@@ -1800,12 +1800,12 @@  static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     memcpy(old_s, s, sizeof(BDRVSheepdogState));
 
     memset(vdi, 0, sizeof(vdi));
-    strncpy(vdi, s->name, sizeof(vdi));
+    pstrcpy(vdi, sizeof(vdi), s->name);
 
     memset(tag, 0, sizeof(tag));
     snapid = strtoul(snapshot_id, NULL, 10);
     if (!snapid) {
-        strncpy(tag, s->name, sizeof(tag));
+        pstrcpy(tag, sizeof(tag), s->name);
     }
 
     ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
@@ -1934,8 +1934,8 @@  static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 
             snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
                      inode.snap_id);
-            strncpy(sn_tab[found].name, inode.tag,
-                    MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)));
+            pstrcpy(sn_tab[found].name, MIN(sizeof(sn_tab[found].name),
+                    sizeof(inode.tag)), inode.tag);
             found++;
         }
     }
diff --git a/block/vmdk.c b/block/vmdk.c
index 18e9b4c..f25c947 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1320,7 +1320,7 @@  static int relative_path(char *dest, int dest_size,
     }
     if (path_is_absolute(target)) {
         dest[dest_size - 1] = '\0';
-        strncpy(dest, target, dest_size - 1);
+        pstrcpy(dest, dest_size - 1, target);
         return 0;
     }
     while (base[i] == target[i]) {
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 18b43f1..cac52c8 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -164,7 +164,7 @@  static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
  * (this is mostly copied from src/sbin/sysctl/sysctl.c)
  */
 static int
-oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
+oidfmt(int *oid, int len, char *fmt, int fmt_max_size, uint32_t *kind)
 {
     int qoid[CTL_MAXNAME+2];
     uint8_t buf[BUFSIZ];
@@ -184,7 +184,7 @@  oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
         *kind = *(uint32_t *)buf;
 
     if (fmt)
-        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
+        pstrcpy(fmt, fmt_max_size, (char *)(buf + sizeof(uint32_t)));
     return (0);
 }
 
@@ -245,7 +245,7 @@  static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol
     holdlen = oldlen;
     for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
        *q++ = tswap32(*p);
-    oidfmt(snamep, namelen, NULL, &kind);
+    oidfmt(snamep, namelen, NULL, 0, &kind);
     /* XXX swap hnewp */
     ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
     if (!ret)
diff --git a/cmd.c b/cmd.c
index f40f09b..31d4a34 100644
--- a/cmd.c
+++ b/cmd.c
@@ -445,11 +445,11 @@  cvtstr(
 	}
 
 	trim = strstr(str, ".000");
-	if (trim) {
-		strcpy(trim, suffix);
-	} else {
-		strcat(str, suffix);
-	}
+    if (trim) {
+        pstrcpy(trim, strlen(trim) + 1, suffix);
+    } else {
+        strcat(str, suffix);
+    }
 }
 
 struct timeval
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index f9a8270..782c6ba 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -710,7 +710,7 @@  static int proxy_socket(const char *path, uid_t uid, gid_t gid)
     umask(7);
 
     proxy.sun_family = AF_UNIX;
-    strcpy(proxy.sun_path, path);
+    pstrcpy(proxy.sun_path, sizeof(proxy.sun_path), path);
     if (bind(sock, (struct sockaddr *)&proxy,
             sizeof(struct sockaddr_un)) < 0) {
         do_perror("bind");
diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c
index a1948e3..e35a901 100644
--- a/hw/9pfs/virtio-9p-posix-acl.c
+++ b/hw/9pfs/virtio-9p-posix-acl.c
@@ -44,7 +44,7 @@  static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
         return -1;
     }
 
-    strncpy(value, ACL_ACCESS, len);
+    pstrcpy(value, len, ACL_ACCESS);
     return 0;
 }
 
@@ -95,7 +95,7 @@  static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
         return -1;
     }
 
-    strncpy(value, ACL_DEFAULT, len);
+    pstrcpy(value, len, ACL_DEFAULT);
     return 0;
 }
 
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index d5ad208..89c91f5 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -230,7 +230,7 @@  static int v9fs_receive_response(V9fsProxy *proxy, int type,
         V9fsString target;
         v9fs_string_init(&target);
         retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
-        strcpy(response, target.data);
+        pstrcpy(response, header.size, target.data);
         v9fs_string_free(&target);
         break;
     }
@@ -1105,7 +1105,7 @@  static int connect_namedsocket(const char *path)
         fprintf(stderr, "socket %s\n", strerror(errno));
         return -1;
     }
-    strcpy(helper.sun_path, path);
+    pstrcpy(helper.sun_path, sizeof(helper.sun_path), path);
     helper.sun_family = AF_UNIX;
     size = strlen(helper.sun_path) + sizeof(helper.sun_family);
     if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) {
diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c
index 92e0b09..988f615 100644
--- a/hw/9pfs/virtio-9p-synth.c
+++ b/hw/9pfs/virtio-9p-synth.c
@@ -58,7 +58,7 @@  static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
         node->attr->read  = NULL;
     }
     node->private = node;
-    strncpy(node->name, name, sizeof(node->name));
+    pstrcpy(node->name, sizeof(node->name), name);
     QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
     return node;
 }
@@ -132,7 +132,7 @@  int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
     node->attr->write  = write;
     node->attr->mode   = mode;
     node->private      = arg;
-    strncpy(node->name, name, sizeof(node->name));
+    pstrcpy(node->name, sizeof(node->name), name);
     QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
     ret = 0;
 err_out:
@@ -218,7 +218,7 @@  static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
 static void v9fs_synth_direntry(V9fsSynthNode *node,
                                 struct dirent *entry, off_t off)
 {
-    strcpy(entry->d_name, node->name);
+    pstrcpy(entry->d_name, NAME_MAX, node->name);
     entry->d_ino = node->attr->inode;
     entry->d_off = off + 1;
 }
diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c
index 5044a3e..10373d4 100644
--- a/hw/9pfs/virtio-9p-xattr-user.c
+++ b/hw/9pfs/virtio-9p-xattr-user.c
@@ -61,7 +61,7 @@  static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
         return -1;
     }
 
-    strncpy(value, name, name_size);
+    pstrcpy(value, name_size, name);
     return name_size;
 }
 
diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c
index 7f08f6e..2d898fa 100644
--- a/hw/9pfs/virtio-9p-xattr.c
+++ b/hw/9pfs/virtio-9p-xattr.c
@@ -53,7 +53,7 @@  ssize_t pt_listxattr(FsContext *ctx, const char *path,
         return -1;
     }
 
-    strncpy(value, name, name_size);
+    pstrcpy(value, name_size, name);
     return name_size;
 }
 
diff --git a/hw/bt-hci.c b/hw/bt-hci.c
index a3a7fb4..92a5cc3 100644
--- a/hw/bt-hci.c
+++ b/hw/bt-hci.c
@@ -1388,7 +1388,7 @@  static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci)
     params.status = HCI_SUCCESS;
     memset(params.name, 0, sizeof(params.name));
     if (hci->device.lmp_name)
-        strncpy(params.name, hci->device.lmp_name, sizeof(params.name));
+        pstrcpy(params.name, sizeof(params.name), hci->device.lmp_name);
 
     bt_hci_event_complete(hci, &params, READ_LOCAL_NAME_RP_SIZE);
 }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9785d5f..3991437 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1969,13 +1969,16 @@  int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
     } else {
         switch (kind) {
         case IDE_CD:
-            strcpy(s->drive_model_str, "QEMU DVD-ROM");
+            pstrcpy(s->drive_model_str, sizeof(s->drive_model_str),
+                    "QEMU DVD-ROM");
             break;
         case IDE_CFATA:
-            strcpy(s->drive_model_str, "QEMU MICRODRIVE");
+            pstrcpy(s->drive_model_str, sizeof(s->drive_model_str),
+                    "QEMU MICRODRIVE");
             break;
         default:
-            strcpy(s->drive_model_str, "QEMU HARDDISK");
+            pstrcpy(s->drive_model_str, sizeof(s->drive_model_str),
+                    "QEMU HARDDISK");
             break;
         }
     }
diff --git a/hw/lm32_hwsetup.h b/hw/lm32_hwsetup.h
index 8fc285e..f9d2eef 100644
--- a/hw/lm32_hwsetup.h
+++ b/hw/lm32_hwsetup.h
@@ -96,7 +96,7 @@  static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
 
 static inline void hwsetup_add_str(HWSetup *hw, const char *str)
 {
-    strncpy(hw->ptr, str, 31); /* make sure last byte is zero */
+    pstrcpy(hw->ptr, 31, str); /* make sure last byte is zero */
     hw->ptr += 32;
 }
 
diff --git a/hw/r2d.c b/hw/r2d.c
index c55de01..84193a9 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -328,8 +328,8 @@  static void r2d_init(ram_addr_t ram_size,
     }
 
     if (kernel_cmdline) {
-        strncpy(boot_params.kernel_cmdline, kernel_cmdline,
-                sizeof(boot_params.kernel_cmdline));
+        pstrcpy(boot_params.kernel_cmdline, sizeof(boot_params.kernel_cmdline),
+                kernel_cmdline);
     }
 
     rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params),
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index f10f3ec..0750fe1 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -406,7 +406,7 @@  static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
         r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ.  */
         memcpy(&r->buf[8], "QEMU    ", 8);
         memcpy(&r->buf[16], "QEMU TARGET     ", 16);
-        strncpy((char *) &r->buf[32], QEMU_VERSION, 4);
+        pstrcpy((char *) &r->buf[32], 4, QEMU_VERSION);
     }
     return true;
 }
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 037867a..2fc6f05 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -735,8 +735,8 @@  static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
     }
 #endif
     memset(&info, 0, sizeof(info));
-    strcpy(info.srp_version, SRP_VERSION);
-    strncpy(info.partition_name, "qemu", sizeof("qemu"));
+    pstrcpy(info.srp_version, sizeof(info.srp_version), SRP_VERSION);
+    pstrcpy(info.partition_name, sizeof("qemu"), "qemu");
     info.partition_number = cpu_to_be32(0);
     info.mad_version = cpu_to_be32(1);
     info.os_type = cpu_to_be32(2);
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index a95b0ed..68ffc55 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1298,7 +1298,7 @@  static int usb_host_open(USBHostDevice *dev, int bus_num,
 
     dev->bus_num = bus_num;
     dev->addr = addr;
-    strcpy(dev->port, port);
+    pstrcpy(dev->port, sizeof(dev->port), port);
     dev->fd = fd;
 
     /* read the device description */
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index f9e1896..df082d0 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -388,9 +388,9 @@  static void virtio_blk_handle_request(VirtIOBlockReq *req,
          * NB: per existing s/n string convention the string is
          * terminated by '\0' only when shorter than buffer.
          */
-        strncpy(req->elem.in_sg[0].iov_base,
-                s->blk->serial ? s->blk->serial : "",
-                MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
+        pstrcpy(req->elem.in_sg[0].iov_base,
+                MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES),
+                s->blk->serial ? s->blk->serial : "");
         virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
         g_free(req);
     } else if (type & VIRTIO_BLK_T_OUT) {
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index 66cb144..7512306 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -602,7 +602,7 @@  static void xenstore_update_be(char *watch, char *type, int dom,
         return;
     }
     if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
-        strcpy(path, "");
+        pstrcpy(path, sizeof(path), "");
         if (sscanf(watch+len, "/%u", &dev) != 1) {
             dev = -1;
         }
diff --git a/ia64-dis.c b/ia64-dis.c
index 2a103e6..85d302f 100644
--- a/ia64-dis.c
+++ b/ia64-dis.c
@@ -10306,7 +10306,7 @@  ia64_dis_opcode (ia64_insn insn, enum ia64_insn_type type)
       int ci = main_table[place].completers;
       ia64_insn tinsn = main_table[place].opcode;
 
-      strcpy (name, ia64_strings [main_table[place].name_index]);
+      pstrcpy(name, sizeof(name), ia64_strings[main_table[place].name_index]);
 
       while (cb)
 	{
@@ -10523,17 +10523,39 @@  print_insn_ia64 (bfd_vma memaddr, struct disassemble_info *info)
 		  case 4: case 5: case 6: case 7:
 		    sprintf (regname, "ar.k%u", (unsigned int) value);
 		    break;
-		  case 16:	strcpy (regname, "ar.rsc"); break;
-		  case 17:	strcpy (regname, "ar.bsp"); break;
-		  case 18:	strcpy (regname, "ar.bspstore"); break;
-		  case 19:	strcpy (regname, "ar.rnat"); break;
-		  case 32:	strcpy (regname, "ar.ccv"); break;
-		  case 36:	strcpy (regname, "ar.unat"); break;
-		  case 40:	strcpy (regname, "ar.fpsr"); break;
-		  case 44:	strcpy (regname, "ar.itc"); break;
-		  case 64:	strcpy (regname, "ar.pfs"); break;
-		  case 65:	strcpy (regname, "ar.lc"); break;
-		  case 66:	strcpy (regname, "ar.ec"); break;
+                    case 16:
+                        pstrcpy(regname, sizeof(regname), "ar.rsc");
+                        break;
+                    case 17:
+                        pstrcpy(regname, sizeof(regname), "ar.bsp");
+                        break;
+                    case 18:
+                        pstrcpy(regname, sizeof(regname), "ar.bspstore");
+                        break;
+                    case 19:
+                        pstrcpy(regname, sizeof(regname), "ar.rnat");
+                        break;
+                    case 32:
+                        pstrcpy(regname, sizeof(regname), "ar.ccv");
+                        break;
+                    case 36:
+                        pstrcpy(regname, sizeof(regname), "ar.unat");
+                        break;
+                    case 40:
+                        pstrcpy(regname, sizeof(regname), "ar.fpsr");
+                        break;
+                    case 44:
+                        pstrcpy(regname, sizeof(regname), "ar.itc");
+                        break;
+                    case 64:
+                        pstrcpy(regname, sizeof(regname), "ar.pfs");
+                        break;
+                    case 65:
+                        pstrcpy(regname, sizeof(regname), "ar.lc");
+                        break;
+                    case 66:
+                        pstrcpy(regname, sizeof(regname), "ar.ec");
+                        break;
 		  default:
 		    sprintf (regname, "ar%u", (unsigned int) value);
 		    break;
diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
index 802cae3..ed71e7e 100644
--- a/libcacard/vcard_emul_nss.c
+++ b/libcacard/vcard_emul_nss.c
@@ -1169,7 +1169,7 @@  vcard_emul_options(const char *args)
             NEXT_TOKEN(vname)
             NEXT_TOKEN(type_params)
             type_params_length = MIN(type_params_length, sizeof(type_str)-1);
-            strncpy(type_str, type_params, type_params_length);
+            pstrcpy(type_str, type_params_length, type_params);
             type_str[type_params_length] = 0;
             type = vcard_emul_type_from_string(type_str);
 
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
index b64c93d..4b47506 100644
--- a/libcacard/vscclient.c
+++ b/libcacard/vscclient.c
@@ -490,7 +490,7 @@  main(
             len += strlen(cert_names[i])+1; /* 1 == comma */
         }
         new_args = g_malloc(len);
-        strcpy(new_args, emul_args);
+        pstrcpy(new_args, len, emul_args);
         strcat(new_args, SOFT_STRING);
         for (i = 0; i < cert_count; i++) {
             strcat(new_args, cert_names[i]);
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f3b1552..63db579 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2340,8 +2340,7 @@  static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
 
     filename = strdup(ts->bprm->filename);
     base_filename = strdup(basename(filename));
-    (void) strncpy(psinfo->pr_fname, base_filename,
-                   sizeof(psinfo->pr_fname));
+    (void) pstrcpy(psinfo->pr_fname, sizeof(psinfo->pr_fname), base_filename);
     free(base_filename);
     free(filename);
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 20d2a74..19ae280 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -275,7 +275,7 @@  static bitmask_transtbl fcntl_flags_tbl[] = {
 #define COPY_UTSNAME_FIELD(dest, src) \
   do { \
       /* __NEW_UTS_LEN doesn't include terminating null */ \
-      (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+      (void) pstrcpy((dest), __NEW_UTS_LEN, (src)); \
       (dest)[__NEW_UTS_LEN] = '\0'; \
   } while (0)
 
diff --git a/microblaze-dis.c b/microblaze-dis.c
index 16c312f..369f256 100644
--- a/microblaze-dis.c
+++ b/microblaze-dis.c
@@ -697,43 +697,43 @@  get_field_special (long instr, struct op_code_struct * op)
    switch ( (((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ) {
 
    case REG_MSR_MASK :
-      strcpy(spr, "msr");
+      pstrcpy(spr, sizeof(spr), "msr");
       break;
    case REG_PC_MASK :
-      strcpy(spr, "pc");
+      pstrcpy(spr, sizeof(spr), "pc");
       break;
    case REG_EAR_MASK :
-      strcpy(spr, "ear");
+      pstrcpy(spr, sizeof(spr), "ear");
       break;
    case REG_ESR_MASK :
-      strcpy(spr, "esr");
+      pstrcpy(spr, sizeof(spr), "esr");
       break;
    case REG_FSR_MASK :
-      strcpy(spr, "fsr");
+      pstrcpy(spr, sizeof(spr), "fsr");
       break;
    case REG_BTR_MASK :
-      strcpy(spr, "btr");
+      pstrcpy(spr, sizeof(spr), "btr");
       break;      
    case REG_EDR_MASK :
-      strcpy(spr, "edr");
+      pstrcpy(spr, sizeof(spr), "edr");
       break;
    case REG_PID_MASK :
-      strcpy(spr, "pid");
+      pstrcpy(spr, sizeof(spr), "pid");
       break;
    case REG_ZPR_MASK :
-      strcpy(spr, "zpr");
+      pstrcpy(spr, sizeof(spr), "zpr");
       break;
    case REG_TLBX_MASK :
-      strcpy(spr, "tlbx");
+      pstrcpy(spr, sizeof(spr), "tlbx");
       break;
    case REG_TLBLO_MASK :
-      strcpy(spr, "tlblo");
+      pstrcpy(spr, sizeof(spr), "tlblo");
       break;
    case REG_TLBHI_MASK :
-      strcpy(spr, "tlbhi");
+      pstrcpy(spr, sizeof(spr), "tlbhi");
       break;
    case REG_TLBSX_MASK :
-      strcpy(spr, "tlbsx");
+      pstrcpy(spr, sizeof(spr), "tlbsx");
       break;
    default :
      {
@@ -741,7 +741,7 @@  get_field_special (long instr, struct op_code_struct * op)
 	 sprintf(tmpstr, "%spvr%d", register_prefix, (unsigned short)(((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ^ REG_PVR_MASK);
 	 return(strdup(tmpstr));
        } else {
-	 strcpy(spr, "pc");
+                pstrcpy(spr, sizeof(spr), "pc");
        }
      }
      break;
diff --git a/os-posix.c b/os-posix.c
index daf3d6f..02a9076 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -149,7 +149,7 @@  void os_set_proc_name(const char *s)
     if (!s)
         return;
     name[sizeof(name) - 1] = 0;
-    strncpy(name, s, sizeof(name));
+    pstrcpy(name, sizeof(name), s);
     /* Could rewrite argv[0] too, but that's a bit more complicated.
        This simple way is enough for `top'. */
     if (prctl(PR_SET_NAME, name)) {
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index dab3bf9..607aad7 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -759,7 +759,7 @@  GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
             }
 
             memset(&ifr, 0, sizeof(ifr));
-            strncpy(ifr.ifr_name,  info->value->name, IF_NAMESIZE);
+            pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
             if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
                 snprintf(err_msg, sizeof(err_msg),
                          "failed to get MAC address of %s: %s",
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index d571fd0..19a4463 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -262,8 +262,8 @@  icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
   ip = mtod(msrc, struct ip *);
 #ifdef DEBUG
   { char bufa[20], bufb[20];
-    strcpy(bufa, inet_ntoa(ip->ip_src));
-    strcpy(bufb, inet_ntoa(ip->ip_dst));
+    pstrcpy(bufa, sizeof(bufa), inet_ntoa(ip->ip_src));
+    pstrcpy(bufb, sizeof(bufb), inet_ntoa(ip->ip_dst));
     DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
   }
 #endif
diff --git a/slirp/misc.c b/slirp/misc.c
index 0bee864..f61316e 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -236,7 +236,7 @@  strdup(str)
 	char *bptr;
 
 	bptr = (char *)malloc(strlen(str)+1);
-	strcpy(bptr, str);
+    pstrcpy(bptr, strlen(str) + 1, str);
 
 	return bptr;
 }
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 89b4ac7..49595e9 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1266,7 +1266,7 @@  static int cpudef_setfield(const char *name, const char *str, void *opaque)
         g_free((void *)def->name);
         def->name = g_strdup(str);
     } else if (!strcmp(name, "model_id")) {
-        strncpy(def->model_id, str, sizeof (def->model_id));
+        pstrcpy(def->model_id, sizeof(def->model_id), str);
     } else if (!strcmp(name, "level")) {
         setscalar(&def->level, str, &err)
     } else if (!strcmp(name, "vendor")) {
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index c09cc39..fb79e9f 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -587,7 +587,7 @@  static int read_cpuinfo(const char *field, char *value, int len)
             break;
         }
         if (!strncmp(line, field, field_len)) {
-            strncpy(value, line, len);
+            pstrcpy(value, len, line);
             ret = 0;
             break;
         }
diff --git a/tests/tcg/cris/check_openpf1.c b/tests/tcg/cris/check_openpf1.c
index fdcf4c5..f80ca91 100644
--- a/tests/tcg/cris/check_openpf1.c
+++ b/tests/tcg/cris/check_openpf1.c
@@ -20,7 +20,7 @@  int main (int argc, char *argv[])
       fnam = malloc (strlen (argv[0]) + 2);
       if (fnam == NULL)
 	abort ();
-      strcpy (fnam, "/");
+      pstrcpy(fnam, strlen(argv[0]) + 2, "/");
       strcat (fnam, argv[0]);
     }
 
diff --git a/tests/tcg/cris/check_openpf5.c b/tests/tcg/cris/check_openpf5.c
index 1f86ea2..c157ad2 100644
--- a/tests/tcg/cris/check_openpf5.c
+++ b/tests/tcg/cris/check_openpf5.c
@@ -27,7 +27,7 @@  int main (int argc, char *argv[])
   char *fn = malloc (strlen (argv[0]) + 2);
   if (fn == NULL)
     abort ();
-  strcpy (fn, "/");
+  pstrcpy(fn, strlen(argv[0]) + 2, "/");
   strcat (fn, argv[0]);
 
   for (i = 0; i < filemax + 1; i++)
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 8fba770..4cd8a8d 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -433,7 +433,7 @@  static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size
 static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
 {
     char *mechname = g_malloc(len + 1);
-    strncpy(mechname, (char*)data, len);
+    pstrcpy(mechname, len, (char *) data);
     mechname[len] = '\0';
     VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
               mechname, vs->sasl.mechlist);
diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
index 3aaa939..2a00833 100644
--- a/ui/vnc-tls.c
+++ b/ui/vnc-tls.c
@@ -433,7 +433,7 @@  static int vnc_set_x509_credential(VncDisplay *vd,
 
     *cred = g_malloc(strlen(certdir) + strlen(filename) + 2);
 
-    strcpy(*cred, certdir);
+    pstrcpy(*cred, strlen(certdir) + strlen(filename) + 2, certdir);
     strcat(*cred, "/");
     strcat(*cred, filename);