Commit 7d1740590b6550b2b8ab4901e4f0b704d9733383
Committed by
Anthony Liguori
1 parent
9977c894
Add SCM_RIGHTS support to unix socket character devices
If a file descriptor is passed via a message with SCM_RIGHTS ancillary data on a unix socket, store the file descriptor for use in the chr_read() handler. Close the file descriptor if it was not used. The qemu_chr_get_msgfd() API provides access to the passed descriptor. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing
2 changed files
with
56 additions
and
1 deletions
qemu-char.c
@@ -168,6 +168,11 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) | @@ -168,6 +168,11 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) | ||
168 | s->chr_read(s->handler_opaque, buf, len); | 168 | s->chr_read(s->handler_opaque, buf, len); |
169 | } | 169 | } |
170 | 170 | ||
171 | +int qemu_chr_get_msgfd(CharDriverState *s) | ||
172 | +{ | ||
173 | + return s->get_msgfd ? s->get_msgfd(s) : -1; | ||
174 | +} | ||
175 | + | ||
171 | void qemu_chr_accept_input(CharDriverState *s) | 176 | void qemu_chr_accept_input(CharDriverState *s) |
172 | { | 177 | { |
173 | if (s->chr_accept_input) | 178 | if (s->chr_accept_input) |
@@ -1832,6 +1837,7 @@ typedef struct { | @@ -1832,6 +1837,7 @@ typedef struct { | ||
1832 | int do_telnetopt; | 1837 | int do_telnetopt; |
1833 | int do_nodelay; | 1838 | int do_nodelay; |
1834 | int is_unix; | 1839 | int is_unix; |
1840 | + int msgfd; | ||
1835 | } TCPCharDriver; | 1841 | } TCPCharDriver; |
1836 | 1842 | ||
1837 | static void tcp_chr_accept(void *opaque); | 1843 | static void tcp_chr_accept(void *opaque); |
@@ -1907,20 +1913,61 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, | @@ -1907,20 +1913,61 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, | ||
1907 | *size = j; | 1913 | *size = j; |
1908 | } | 1914 | } |
1909 | 1915 | ||
1916 | +static int tcp_get_msgfd(CharDriverState *chr) | ||
1917 | +{ | ||
1918 | + TCPCharDriver *s = chr->opaque; | ||
1919 | + | ||
1920 | + return s->msgfd; | ||
1921 | +} | ||
1922 | + | ||
1910 | #ifndef WIN32 | 1923 | #ifndef WIN32 |
1924 | +static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg) | ||
1925 | +{ | ||
1926 | + TCPCharDriver *s = chr->opaque; | ||
1927 | + struct cmsghdr *cmsg; | ||
1928 | + | ||
1929 | + for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { | ||
1930 | + int fd; | ||
1931 | + | ||
1932 | + if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || | ||
1933 | + cmsg->cmsg_level != SOL_SOCKET || | ||
1934 | + cmsg->cmsg_type != SCM_RIGHTS) | ||
1935 | + continue; | ||
1936 | + | ||
1937 | + fd = *((int *)CMSG_DATA(cmsg)); | ||
1938 | + if (fd < 0) | ||
1939 | + continue; | ||
1940 | + | ||
1941 | + if (s->msgfd != -1) | ||
1942 | + close(s->msgfd); | ||
1943 | + s->msgfd = fd; | ||
1944 | + } | ||
1945 | +} | ||
1946 | + | ||
1911 | static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) | 1947 | static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) |
1912 | { | 1948 | { |
1913 | TCPCharDriver *s = chr->opaque; | 1949 | TCPCharDriver *s = chr->opaque; |
1914 | struct msghdr msg = { 0, }; | 1950 | struct msghdr msg = { 0, }; |
1915 | struct iovec iov[1]; | 1951 | struct iovec iov[1]; |
1952 | + union { | ||
1953 | + struct cmsghdr cmsg; | ||
1954 | + char control[CMSG_SPACE(sizeof(int))]; | ||
1955 | + } msg_control; | ||
1956 | + ssize_t ret; | ||
1916 | 1957 | ||
1917 | iov[0].iov_base = buf; | 1958 | iov[0].iov_base = buf; |
1918 | iov[0].iov_len = len; | 1959 | iov[0].iov_len = len; |
1919 | 1960 | ||
1920 | msg.msg_iov = iov; | 1961 | msg.msg_iov = iov; |
1921 | msg.msg_iovlen = 1; | 1962 | msg.msg_iovlen = 1; |
1963 | + msg.msg_control = &msg_control; | ||
1964 | + msg.msg_controllen = sizeof(msg_control); | ||
1965 | + | ||
1966 | + ret = recvmsg(s->fd, &msg, 0); | ||
1967 | + if (ret > 0 && s->is_unix) | ||
1968 | + unix_process_msgfd(chr, &msg); | ||
1922 | 1969 | ||
1923 | - return recvmsg(s->fd, &msg, 0); | 1970 | + return ret; |
1924 | } | 1971 | } |
1925 | #else | 1972 | #else |
1926 | static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) | 1973 | static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) |
@@ -1957,6 +2004,10 @@ static void tcp_chr_read(void *opaque) | @@ -1957,6 +2004,10 @@ static void tcp_chr_read(void *opaque) | ||
1957 | tcp_chr_process_IAC_bytes(chr, s, buf, &size); | 2004 | tcp_chr_process_IAC_bytes(chr, s, buf, &size); |
1958 | if (size > 0) | 2005 | if (size > 0) |
1959 | qemu_chr_read(chr, buf, size); | 2006 | qemu_chr_read(chr, buf, size); |
2007 | + if (s->msgfd != -1) { | ||
2008 | + close(s->msgfd); | ||
2009 | + s->msgfd = -1; | ||
2010 | + } | ||
1960 | } | 2011 | } |
1961 | } | 2012 | } |
1962 | 2013 | ||
@@ -2118,12 +2169,14 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, | @@ -2118,12 +2169,14 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, | ||
2118 | s->connected = 0; | 2169 | s->connected = 0; |
2119 | s->fd = -1; | 2170 | s->fd = -1; |
2120 | s->listen_fd = -1; | 2171 | s->listen_fd = -1; |
2172 | + s->msgfd = -1; | ||
2121 | s->is_unix = is_unix; | 2173 | s->is_unix = is_unix; |
2122 | s->do_nodelay = do_nodelay && !is_unix; | 2174 | s->do_nodelay = do_nodelay && !is_unix; |
2123 | 2175 | ||
2124 | chr->opaque = s; | 2176 | chr->opaque = s; |
2125 | chr->chr_write = tcp_chr_write; | 2177 | chr->chr_write = tcp_chr_write; |
2126 | chr->chr_close = tcp_chr_close; | 2178 | chr->chr_close = tcp_chr_close; |
2179 | + chr->get_msgfd = tcp_get_msgfd; | ||
2127 | 2180 | ||
2128 | if (is_listen) { | 2181 | if (is_listen) { |
2129 | s->listen_fd = fd; | 2182 | s->listen_fd = fd; |
qemu-char.h
@@ -51,6 +51,7 @@ struct CharDriverState { | @@ -51,6 +51,7 @@ struct CharDriverState { | ||
51 | int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); | 51 | int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); |
52 | void (*chr_update_read_handler)(struct CharDriverState *s); | 52 | void (*chr_update_read_handler)(struct CharDriverState *s); |
53 | int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); | 53 | int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); |
54 | + int (*get_msgfd)(struct CharDriverState *s); | ||
54 | IOEventHandler *chr_event; | 55 | IOEventHandler *chr_event; |
55 | IOCanRWHandler *chr_can_read; | 56 | IOCanRWHandler *chr_can_read; |
56 | IOReadHandler *chr_read; | 57 | IOReadHandler *chr_read; |
@@ -81,6 +82,7 @@ void qemu_chr_reset(CharDriverState *s); | @@ -81,6 +82,7 @@ void qemu_chr_reset(CharDriverState *s); | ||
81 | void qemu_chr_initial_reset(void); | 82 | void qemu_chr_initial_reset(void); |
82 | int qemu_chr_can_read(CharDriverState *s); | 83 | int qemu_chr_can_read(CharDriverState *s); |
83 | void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); | 84 | void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); |
85 | +int qemu_chr_get_msgfd(CharDriverState *s); | ||
84 | void qemu_chr_accept_input(CharDriverState *s); | 86 | void qemu_chr_accept_input(CharDriverState *s); |
85 | void qemu_chr_info(Monitor *mon); | 87 | void qemu_chr_info(Monitor *mon); |
86 | 88 |