diff mbox

[1/6] qemu-fd-exchange: provide common methods for exchange fd

Message ID 1389172376-30636-2-git-send-email-lilei@linux.vnet.ibm.com
State New
Headers show

Commit Message

Lei Li Jan. 8, 2014, 9:12 a.m. UTC
Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
---
 include/qemu/fd-exchange.h |   25 +++++++++++
 util/Makefile.objs         |    1 +
 util/qemu-fd-exchange.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+), 0 deletions(-)
 create mode 100644 include/qemu/fd-exchange.h
 create mode 100644 util/qemu-fd-exchange.c

Comments

Eric Blake Jan. 16, 2014, 3:16 p.m. UTC | #1
On 01/08/2014 02:12 AM, Lei Li wrote:
> Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
> ---
>  include/qemu/fd-exchange.h |   25 +++++++++++
>  util/Makefile.objs         |    1 +
>  util/qemu-fd-exchange.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 123 insertions(+), 0 deletions(-)
>  create mode 100644 include/qemu/fd-exchange.h
>  create mode 100644 util/qemu-fd-exchange.c
> 
> diff --git a/include/qemu/fd-exchange.h b/include/qemu/fd-exchange.h
> new file mode 100644
> index 0000000..6929026
> --- /dev/null
> +++ b/include/qemu/fd-exchange.h
> @@ -0,0 +1,25 @@
> +/*
> + * Internel common methods for exchange of FD
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.

Any reason you can't use GPLv2+?  Limiting to exactly version 2 means
your file cannot be copied into programs that want a wider array of
licensing optoins.
Eric Blake Jan. 16, 2014, 3:26 p.m. UTC | #2
On 01/08/2014 02:12 AM, Lei Li wrote:
> Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
> ---
>  include/qemu/fd-exchange.h |   25 +++++++++++
>  util/Makefile.objs         |    1 +
>  util/qemu-fd-exchange.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 123 insertions(+), 0 deletions(-)
>  create mode 100644 include/qemu/fd-exchange.h
>  create mode 100644 util/qemu-fd-exchange.c
> 
> diff --git a/include/qemu/fd-exchange.h b/include/qemu/fd-exchange.h
> new file mode 100644
> index 0000000..6929026
> --- /dev/null
> +++ b/include/qemu/fd-exchange.h
> @@ -0,0 +1,25 @@
> +/*
> + * Internel common methods for exchange of FD

s/Internel/Internal/


> +++ b/util/qemu-fd-exchange.c
> @@ -0,0 +1,97 @@
> +/*
> + * Internel common methods for exchange of FD

and again.


> +ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
> +                          const void *buf, size_t len)
> +{
> +    struct msghdr msg;
> +    struct iovec iov;
> +    struct cmsghdr *cmsg;
> +    union MsgControl msg_control;
> +    int retval;
> +
> +    iov.iov_base = (int *)buf;
> +    iov.iov_len = len;
> +
> +    memset(&msg, 0, sizeof(msg));
> +    msg.msg_iov = &iov;
> +    msg.msg_iovlen = len;
> +    msg.msg_control = &msg_control;
> +    msg.msg_controllen = sizeof(msg_control);
> +
> +    if (passed_fd < 0) {
> +        *(int *)buf = passed_fd;

Is it safe to assume that buf is aligned well enough to be casting it to
int* then dereferencing it?  Why not just type the parameter correctly
to begin with?  And why are you even writing into the caller's buffer
when they pass a negative fd, but leaving it alone when they pass a
non-negative fd?

> +ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
> +                          void *buf, size_t len)
> +{
> +    struct iovec iov;
> +    struct msghdr msg;
> +    struct cmsghdr *cmsg;
> +    union MsgControl msg_control;
> +    int retval;
> +    int data = *(int *)buf;

Again, why not type buf correctly, since otherwise you risk a user
passing in a buffer that is unsuitably aligned for dereferencing as an
int pointer.

> +
> +    iov.iov_base = buf;
> +    iov.iov_len = len;
> +
> +    memset(&msg, 0, sizeof(msg));
> +    msg.msg_iov = &iov;
> +    msg.msg_iovlen = 1;
> +    msg.msg_control = &msg_control;
> +    msg.msg_controllen = sizeof(msg_control);
> +

Should you take advantage of Linux' ability to use MSG_CMSG_CLOEXEC to
guarantee the received fd is atomically marked cloexec when possible?

> +    do {
> +        retval = recvmsg(sockfd, &msg, 0);
> +    } while (retval < 0 && errno == EINTR);
> +
> +    if (retval <= 0) {
> +        return retval;
> +    }
> +
> +    if (data != *(int *)buf) {
> +        *passed_fd = data;
> +        return 0;
> +    }
> +
> +    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
> +        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
> +            cmsg->cmsg_level != SOL_SOCKET ||
> +            cmsg->cmsg_type != SCM_RIGHTS) {
> +            continue;
> +        }
> +
> +        memcpy(passed_fd, CMSG_DATA(cmsg), sizeof(*passed_fd));
> +        return 0;
> +    }

And even when MSG_CMSG_CLOEXEC is not available, shouldn't you ensure
that cloexec is set after the fact?
Lei Li Jan. 17, 2014, 3:40 a.m. UTC | #3
On 01/16/2014 11:16 PM, Eric Blake wrote:
> On 01/08/2014 02:12 AM, Lei Li wrote:
>> Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
>> ---
>>   include/qemu/fd-exchange.h |   25 +++++++++++
>>   util/Makefile.objs         |    1 +
>>   util/qemu-fd-exchange.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 123 insertions(+), 0 deletions(-)
>>   create mode 100644 include/qemu/fd-exchange.h
>>   create mode 100644 util/qemu-fd-exchange.c
>>
>> diff --git a/include/qemu/fd-exchange.h b/include/qemu/fd-exchange.h
>> new file mode 100644
>> index 0000000..6929026
>> --- /dev/null
>> +++ b/include/qemu/fd-exchange.h
>> @@ -0,0 +1,25 @@
>> +/*
>> + * Internel common methods for exchange of FD
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2.  See
>> + * the COPYING file in the top-level directory.
> Any reason you can't use GPLv2+?  Limiting to exactly version 2 means
> your file cannot be copied into programs that want a wider array of
> licensing optoins.

Er... it's my miss copy, apologize to this. :(

>
Lei Li Jan. 17, 2014, 3:41 a.m. UTC | #4
On 01/16/2014 11:26 PM, Eric Blake wrote:
> On 01/08/2014 02:12 AM, Lei Li wrote:
>> Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
>> ---
>>   include/qemu/fd-exchange.h |   25 +++++++++++
>>   util/Makefile.objs         |    1 +
>>   util/qemu-fd-exchange.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 123 insertions(+), 0 deletions(-)
>>   create mode 100644 include/qemu/fd-exchange.h
>>   create mode 100644 util/qemu-fd-exchange.c
>>
>> diff --git a/include/qemu/fd-exchange.h b/include/qemu/fd-exchange.h
>> new file mode 100644
>> index 0000000..6929026
>> --- /dev/null
>> +++ b/include/qemu/fd-exchange.h
>> @@ -0,0 +1,25 @@
>> +/*
>> + * Internel common methods for exchange of FD
> s/Internel/Internal/
>
>
>> +++ b/util/qemu-fd-exchange.c
>> @@ -0,0 +1,97 @@
>> +/*
>> + * Internel common methods for exchange of FD
> and again.

Good catch! Thanks.

>
>> +ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
>> +                          const void *buf, size_t len)
>> +{
>> +    struct msghdr msg;
>> +    struct iovec iov;
>> +    struct cmsghdr *cmsg;
>> +    union MsgControl msg_control;
>> +    int retval;
>> +
>> +    iov.iov_base = (int *)buf;
>> +    iov.iov_len = len;
>> +
>> +    memset(&msg, 0, sizeof(msg));
>> +    msg.msg_iov = &iov;
>> +    msg.msg_iovlen = len;
>> +    msg.msg_control = &msg_control;
>> +    msg.msg_controllen = sizeof(msg_control);
>> +
>> +    if (passed_fd < 0) {
>> +        *(int *)buf = passed_fd;
> Is it safe to assume that buf is aligned well enough to be casting it to
> int* then dereferencing it?  Why not just type the parameter correctly

That's because there would be different type for this parameter.

> to begin with?  And why are you even writing into the caller's buffer
> when they pass a negative fd, but leaving it alone when they pass a
> non-negative fd?

That's just the original logical of exchange fd for proxy fs driver,

     if (fd < 0) {
         data = fd;
     } else {
         data = V9FS_FD_VALID;
         ....
     }

This common method don't leave it alone when a non-negative fd passed,
it'll be the same as the check value passed from the caller.

>> +ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
>> +                          void *buf, size_t len)
>> +{
>> +    struct iovec iov;
>> +    struct msghdr msg;
>> +    struct cmsghdr *cmsg;
>> +    union MsgControl msg_control;
>> +    int retval;
>> +    int data = *(int *)buf;
> Again, why not type buf correctly, since otherwise you risk a user
> passing in a buffer that is unsuitably aligned for dereferencing as an
> int pointer.
>
>> +
>> +    iov.iov_base = buf;
>> +    iov.iov_len = len;
>> +
>> +    memset(&msg, 0, sizeof(msg));
>> +    msg.msg_iov = &iov;
>> +    msg.msg_iovlen = 1;
>> +    msg.msg_control = &msg_control;
>> +    msg.msg_controllen = sizeof(msg_control);
>> +
> Should you take advantage of Linux' ability to use MSG_CMSG_CLOEXEC to
> guarantee the received fd is atomically marked cloexec when possible?

Whether close the fd in the common method depends on the process
of these current users (they are not the same). It'd be better to
let the users handling the close of fd to fit it.



>
>> +    do {
>> +        retval = recvmsg(sockfd, &msg, 0);
>> +    } while (retval < 0 && errno == EINTR);
>> +
>> +    if (retval <= 0) {
>> +        return retval;
>> +    }
>> +
>> +    if (data != *(int *)buf) {
>> +        *passed_fd = data;
>> +        return 0;
>> +    }
>> +
>> +    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
>> +        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
>> +            cmsg->cmsg_level != SOL_SOCKET ||
>> +            cmsg->cmsg_type != SCM_RIGHTS) {
>> +            continue;
>> +        }
>> +
>> +        memcpy(passed_fd, CMSG_DATA(cmsg), sizeof(*passed_fd));
>> +        return 0;
>> +    }
> And even when MSG_CMSG_CLOEXEC is not available, shouldn't you ensure
> that cloexec is set after the fact?

That's a good suggestion, thanks.
Daniel P. Berrangé Jan. 17, 2014, 10:02 a.m. UTC | #5
On Wed, Jan 08, 2014 at 05:12:51PM +0800, Lei Li wrote:
> Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
> ---
>  include/qemu/fd-exchange.h |   25 +++++++++++
>  util/Makefile.objs         |    1 +
>  util/qemu-fd-exchange.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 123 insertions(+), 0 deletions(-)
>  create mode 100644 include/qemu/fd-exchange.h
>  create mode 100644 util/qemu-fd-exchange.c
> 
> diff --git a/include/qemu/fd-exchange.h b/include/qemu/fd-exchange.h
> new file mode 100644
> index 0000000..6929026
> --- /dev/null
> +++ b/include/qemu/fd-exchange.h
> @@ -0,0 +1,25 @@
> +/*
> + * Internel common methods for exchange of FD
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#ifndef FD_EXCHANGE_H
> +#define FD_EXCHANGE_H
> +
> +#include <sys/socket.h>
> +
> +union MsgControl {
> +    struct cmsghdr cmsg;
> +    char control[CMSG_SPACE(sizeof(int))];
> +};
> +
> +ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
> +                          const void *buf, size_t len);
> +
> +ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
> +                          void *buf, size_t len);
> +
> +#endif
> diff --git a/util/Makefile.objs b/util/Makefile.objs
> index af3e5cb..2fb42bf 100644
> --- a/util/Makefile.objs
> +++ b/util/Makefile.objs
> @@ -13,3 +13,4 @@ util-obj-y += hexdump.o
>  util-obj-y += crc32c.o
>  util-obj-y += throttle.o
>  util-obj-y += getauxval.o
> +util-obj-y += qemu-fd-exchange.o
> diff --git a/util/qemu-fd-exchange.c b/util/qemu-fd-exchange.c
> new file mode 100644
> index 0000000..70a3206
> --- /dev/null
> +++ b/util/qemu-fd-exchange.c
> @@ -0,0 +1,97 @@
> +/*
> + * Internel common methods for exchange of FD
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/fd-exchange.h"
> +#include "qemu-common.h"
> +
> +
> +ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
> +                          const void *buf, size_t len)
> +{
> +    struct msghdr msg;
> +    struct iovec iov;
> +    struct cmsghdr *cmsg;
> +    union MsgControl msg_control;
> +    int retval;
> +
> +    iov.iov_base = (int *)buf;
> +    iov.iov_len = len;
> +
> +    memset(&msg, 0, sizeof(msg));
> +    msg.msg_iov = &iov;
> +    msg.msg_iovlen = len;
> +    msg.msg_control = &msg_control;
> +    msg.msg_controllen = sizeof(msg_control);
> +
> +    if (passed_fd < 0) {
> +        *(int *)buf = passed_fd;

You are casting 'char *buf' to an 'int *' but many of the
callers only pass in a pointer to a 'char buf[1]'. So you
are overflowing the array and also likely causing alignment
violations on ARM platforms.

> +    } else {
> +        msg.msg_control = &msg_control;
> +        msg.msg_controllen = sizeof(msg_control);
> +
> +        cmsg = &msg_control.cmsg;
> +        cmsg->cmsg_len = CMSG_LEN(sizeof(passed_fd));
> +        cmsg->cmsg_level = SOL_SOCKET;
> +        cmsg->cmsg_type = SCM_RIGHTS;
> +        memcpy(CMSG_DATA(cmsg), &passed_fd, sizeof(passed_fd));
> +
> +    }
> +
> +    do {
> +        retval = sendmsg(sockfd, &msg, 0);
> +    } while (retval < 0 && errno == EINTR);
> +
> +    return retval;
> +}
> +
> +ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
> +                          void *buf, size_t len)
> +{
> +    struct iovec iov;
> +    struct msghdr msg;
> +    struct cmsghdr *cmsg;
> +    union MsgControl msg_control;
> +    int retval;
> +    int data = *(int *)buf;
> +
> +    iov.iov_base = buf;
> +    iov.iov_len = len;
> +
> +    memset(&msg, 0, sizeof(msg));
> +    msg.msg_iov = &iov;
> +    msg.msg_iovlen = 1;
> +    msg.msg_control = &msg_control;
> +    msg.msg_controllen = sizeof(msg_control);
> +
> +    do {
> +        retval = recvmsg(sockfd, &msg, 0);
> +    } while (retval < 0 && errno == EINTR);
> +
> +    if (retval <= 0) {
> +        return retval;
> +    }
> +
> +    if (data != *(int *)buf) {
> +        *passed_fd = data;
> +        return 0;
> +    }

Again cast issues

> +
> +    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
> +        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
> +            cmsg->cmsg_level != SOL_SOCKET ||
> +            cmsg->cmsg_type != SCM_RIGHTS) {
> +            continue;
> +        }
> +
> +        memcpy(passed_fd, CMSG_DATA(cmsg), sizeof(*passed_fd));
> +        return 0;
> +    }
> +
> +    *passed_fd = -ENFILE;
> +    return retval;
> +}
> -- 

Regards,
Daniel
Lei Li Jan. 20, 2014, 1:50 a.m. UTC | #6
On 01/17/2014 06:02 PM, Daniel P. Berrange wrote:
> On Wed, Jan 08, 2014 at 05:12:51PM +0800, Lei Li wrote:
>> Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
>> ---
>>   include/qemu/fd-exchange.h |   25 +++++++++++
>>   util/Makefile.objs         |    1 +
>>   util/qemu-fd-exchange.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 123 insertions(+), 0 deletions(-)
>>   create mode 100644 include/qemu/fd-exchange.h
>>   create mode 100644 util/qemu-fd-exchange.c
>>
>> diff --git a/include/qemu/fd-exchange.h b/include/qemu/fd-exchange.h
>> new file mode 100644
>> index 0000000..6929026
>> --- /dev/null
>> +++ b/include/qemu/fd-exchange.h
>> @@ -0,0 +1,25 @@
>> +/*
>> + * Internel common methods for exchange of FD
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2.  See
>> + * the COPYING file in the top-level directory.
>> + *
>> + */
>> +
>> +#ifndef FD_EXCHANGE_H
>> +#define FD_EXCHANGE_H
>> +
>> +#include <sys/socket.h>
>> +
>> +union MsgControl {
>> +    struct cmsghdr cmsg;
>> +    char control[CMSG_SPACE(sizeof(int))];
>> +};
>> +
>> +ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
>> +                          const void *buf, size_t len);
>> +
>> +ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
>> +                          void *buf, size_t len);
>> +
>> +#endif
>> diff --git a/util/Makefile.objs b/util/Makefile.objs
>> index af3e5cb..2fb42bf 100644
>> --- a/util/Makefile.objs
>> +++ b/util/Makefile.objs
>> @@ -13,3 +13,4 @@ util-obj-y += hexdump.o
>>   util-obj-y += crc32c.o
>>   util-obj-y += throttle.o
>>   util-obj-y += getauxval.o
>> +util-obj-y += qemu-fd-exchange.o
>> diff --git a/util/qemu-fd-exchange.c b/util/qemu-fd-exchange.c
>> new file mode 100644
>> index 0000000..70a3206
>> --- /dev/null
>> +++ b/util/qemu-fd-exchange.c
>> @@ -0,0 +1,97 @@
>> +/*
>> + * Internel common methods for exchange of FD
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2.  See
>> + * the COPYING file in the top-level directory.
>> + *
>> + */
>> +
>> +#include "qemu/fd-exchange.h"
>> +#include "qemu-common.h"
>> +
>> +
>> +ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
>> +                          const void *buf, size_t len)
>> +{
>> +    struct msghdr msg;
>> +    struct iovec iov;
>> +    struct cmsghdr *cmsg;
>> +    union MsgControl msg_control;
>> +    int retval;
>> +
>> +    iov.iov_base = (int *)buf;
>> +    iov.iov_len = len;
>> +
>> +    memset(&msg, 0, sizeof(msg));
>> +    msg.msg_iov = &iov;
>> +    msg.msg_iovlen = len;
>> +    msg.msg_control = &msg_control;
>> +    msg.msg_controllen = sizeof(msg_control);
>> +
>> +    if (passed_fd < 0) {
>> +        *(int *)buf = passed_fd;
> You are casting 'char *buf' to an 'int *' but many of the
> callers only pass in a pointer to a 'char buf[1]'. So you
> are overflowing the array and also likely causing alignment
> violations on ARM platforms.

You are right, will fix it.

Thanks.

>
>> +    } else {
>> +        msg.msg_control = &msg_control;
>> +        msg.msg_controllen = sizeof(msg_control);
>> +
>> +        cmsg = &msg_control.cmsg;
>> +        cmsg->cmsg_len = CMSG_LEN(sizeof(passed_fd));
>> +        cmsg->cmsg_level = SOL_SOCKET;
>> +        cmsg->cmsg_type = SCM_RIGHTS;
>> +        memcpy(CMSG_DATA(cmsg), &passed_fd, sizeof(passed_fd));
>> +
>> +    }
>> +
>> +    do {
>> +        retval = sendmsg(sockfd, &msg, 0);
>> +    } while (retval < 0 && errno == EINTR);
>> +
>> +    return retval;
>> +}
>> +
>> +ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
>> +                          void *buf, size_t len)
>> +{
>> +    struct iovec iov;
>> +    struct msghdr msg;
>> +    struct cmsghdr *cmsg;
>> +    union MsgControl msg_control;
>> +    int retval;
>> +    int data = *(int *)buf;
>> +
>> +    iov.iov_base = buf;
>> +    iov.iov_len = len;
>> +
>> +    memset(&msg, 0, sizeof(msg));
>> +    msg.msg_iov = &iov;
>> +    msg.msg_iovlen = 1;
>> +    msg.msg_control = &msg_control;
>> +    msg.msg_controllen = sizeof(msg_control);
>> +
>> +    do {
>> +        retval = recvmsg(sockfd, &msg, 0);
>> +    } while (retval < 0 && errno == EINTR);
>> +
>> +    if (retval <= 0) {
>> +        return retval;
>> +    }
>> +
>> +    if (data != *(int *)buf) {
>> +        *passed_fd = data;
>> +        return 0;
>> +    }
> Again cast issues
>
>> +
>> +    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
>> +        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
>> +            cmsg->cmsg_level != SOL_SOCKET ||
>> +            cmsg->cmsg_type != SCM_RIGHTS) {
>> +            continue;
>> +        }
>> +
>> +        memcpy(passed_fd, CMSG_DATA(cmsg), sizeof(*passed_fd));
>> +        return 0;
>> +    }
>> +
>> +    *passed_fd = -ENFILE;
>> +    return retval;
>> +}
>> -- 
> Regards,
> Daniel
diff mbox

Patch

diff --git a/include/qemu/fd-exchange.h b/include/qemu/fd-exchange.h
new file mode 100644
index 0000000..6929026
--- /dev/null
+++ b/include/qemu/fd-exchange.h
@@ -0,0 +1,25 @@ 
+/*
+ * Internel common methods for exchange of FD
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef FD_EXCHANGE_H
+#define FD_EXCHANGE_H
+
+#include <sys/socket.h>
+
+union MsgControl {
+    struct cmsghdr cmsg;
+    char control[CMSG_SPACE(sizeof(int))];
+};
+
+ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
+                          const void *buf, size_t len);
+
+ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
+                          void *buf, size_t len);
+
+#endif
diff --git a/util/Makefile.objs b/util/Makefile.objs
index af3e5cb..2fb42bf 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -13,3 +13,4 @@  util-obj-y += hexdump.o
 util-obj-y += crc32c.o
 util-obj-y += throttle.o
 util-obj-y += getauxval.o
+util-obj-y += qemu-fd-exchange.o
diff --git a/util/qemu-fd-exchange.c b/util/qemu-fd-exchange.c
new file mode 100644
index 0000000..70a3206
--- /dev/null
+++ b/util/qemu-fd-exchange.c
@@ -0,0 +1,97 @@ 
+/*
+ * Internel common methods for exchange of FD
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/fd-exchange.h"
+#include "qemu-common.h"
+
+
+ssize_t qemu_send_with_fd(int sockfd, int passed_fd,
+                          const void *buf, size_t len)
+{
+    struct msghdr msg;
+    struct iovec iov;
+    struct cmsghdr *cmsg;
+    union MsgControl msg_control;
+    int retval;
+
+    iov.iov_base = (int *)buf;
+    iov.iov_len = len;
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = len;
+    msg.msg_control = &msg_control;
+    msg.msg_controllen = sizeof(msg_control);
+
+    if (passed_fd < 0) {
+        *(int *)buf = passed_fd;
+    } else {
+        msg.msg_control = &msg_control;
+        msg.msg_controllen = sizeof(msg_control);
+
+        cmsg = &msg_control.cmsg;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(passed_fd));
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        memcpy(CMSG_DATA(cmsg), &passed_fd, sizeof(passed_fd));
+
+    }
+
+    do {
+        retval = sendmsg(sockfd, &msg, 0);
+    } while (retval < 0 && errno == EINTR);
+
+    return retval;
+}
+
+ssize_t qemu_recv_with_fd(int sockfd, int *passed_fd,
+                          void *buf, size_t len)
+{
+    struct iovec iov;
+    struct msghdr msg;
+    struct cmsghdr *cmsg;
+    union MsgControl msg_control;
+    int retval;
+    int data = *(int *)buf;
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &msg_control;
+    msg.msg_controllen = sizeof(msg_control);
+
+    do {
+        retval = recvmsg(sockfd, &msg, 0);
+    } while (retval < 0 && errno == EINTR);
+
+    if (retval <= 0) {
+        return retval;
+    }
+
+    if (data != *(int *)buf) {
+        *passed_fd = data;
+        return 0;
+    }
+
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+            cmsg->cmsg_level != SOL_SOCKET ||
+            cmsg->cmsg_type != SCM_RIGHTS) {
+            continue;
+        }
+
+        memcpy(passed_fd, CMSG_DATA(cmsg), sizeof(*passed_fd));
+        return 0;
+    }
+
+    *passed_fd = -ENFILE;
+    return retval;
+}