Commit 9f8ef2b8 authored by Pavel Emelyanov's avatar Pavel Emelyanov

Merge branch 'br-fetch'

parents 6a9fecb5 ce028b15
......@@ -29,6 +29,7 @@ struct socket_desc {
extern int dump_socket(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset);
extern int dump_socket_opts(int sk, SkOptsEntry *soe);
extern int restore_socket_opts(int sk, SkOptsEntry *soe);
extern void release_skopts(SkOptsEntry *);
extern int sk_collect_one(int ino, int family, struct socket_desc *d);
extern int collect_sockets(int pid);
......
......@@ -17,6 +17,8 @@ message sk_opts_entry {
optional bool so_no_check = 14;
optional uint32 so_bound_dev = 15;
repeated fixed64 so_filter = 16;
}
enum sk_shutdown {
......
......@@ -299,6 +299,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
break;
}
err:
release_skopts(&skopts);
xfree(ie.src_addr);
xfree(ie.dst_addr);
return ret;
......
......@@ -193,6 +193,7 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_PACKETSK), &psk, PB_PACKETSK);
out:
release_skopts(&skopts);
xfree(psk.rx_ring);
xfree(psk.tx_ring);
for (i = 0; i < psk.n_mclist; i++)
......
......@@ -232,6 +232,7 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
pr_info("Dumping unix socket at %d\n", p->fd);
show_one_unix("Dumping", sk);
show_one_unix_img("Dumped", &ue);
release_skopts(&skopts);
list_del_init(&sk->list);
sk->sd.already_dumped = 1;
......@@ -239,6 +240,7 @@ static int dump_one_unix_fd(int lfd, u32 id, const struct fd_parms *p)
return 0;
err:
release_skopts(&skopts);
return -1;
}
......
......@@ -5,6 +5,7 @@
#include <netinet/tcp.h>
#include <errno.h>
#include <linux/if.h>
#include <linux/filter.h>
#include "libnetlink.h"
#include "sockets.h"
......@@ -32,6 +33,10 @@
#define SK_HASH_SIZE 32
#ifndef SO_GET_FILTER
#define SO_GET_FILTER SO_ATTACH_FILTER
#endif
static int dump_bound_dev(int sk, SkOptsEntry *soe)
{
int dev = 0, ret;
......@@ -69,6 +74,95 @@ static int restore_bound_dev(int sk, SkOptsEntry *soe)
return do_restore_opt(sk, SOL_SOCKET, SO_BINDTODEVICE, n, IFNAMSIZ);
}
/*
* Protobuf handles le/be himself, but the sock_filter is not just u64,
* it's a structure and we have to preserve the fields order to be able
* to move socket image across architectures.
*/
static void encode_filter(struct sock_filter *f, uint64_t *img, int n)
{
int i;
BUILD_BUG_ON(sizeof(*f) != sizeof(*img));
for (i = 0; i < n; i++)
img[i] = ((uint64_t)f[i].code << 48) |
((uint64_t)f[i].jt << 40) |
((uint64_t)f[i].jf << 32) |
((uint64_t)f[i].k << 0);
}
static void decode_filter(uint64_t *img, struct sock_filter *f, int n)
{
int i;
for (i = 0; i < n; i++) {
f[i].code = img[i] >> 48;
f[i].jt = img[i] >> 40;
f[i].jf = img[i] >> 32;
f[i].k = img[i] >> 0;
}
}
static int dump_socket_filter(int sk, SkOptsEntry *soe)
{
socklen_t len = 0;
int ret;
struct sock_filter *flt;
ret = getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, NULL, &len);
if (ret && errno != ENOPROTOOPT) {
pr_perror("Can't get socket filter len");
return ret;
}
if (!len) {
pr_info("No filter for socket\n");
return 0;
}
flt = xmalloc(len * sizeof(*flt));
if (!flt)
return -1;
ret = getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, flt, &len);
if (ret) {
pr_perror("Can't get socket filter\n");
return ret;
}
soe->so_filter = xmalloc(len * sizeof(*soe->so_filter));
if (!soe->so_filter)
return -1;
encode_filter(flt, soe->so_filter, len);
soe->n_so_filter = len;
xfree(flt);
return 0;
}
static int restore_socket_filter(int sk, SkOptsEntry *soe)
{
int ret;
struct sock_fprog sfp;
if (!soe->n_so_filter)
return 0;
pr_info("Restoring socket filter\n");
sfp.len = soe->n_so_filter;
sfp.filter = xmalloc(soe->n_so_filter * sfp.len);
if (!sfp.filter)
return -1;
decode_filter(soe->so_filter, sfp.filter, sfp.len);
ret = restore_opt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &sfp);
xfree(sfp.filter);
return ret;
}
static struct socket_desc *sockets[SK_HASH_SIZE];
struct socket_desc *lookup_socket(int ino, int family)
......@@ -159,7 +253,8 @@ int restore_socket_opts(int sk, SkOptsEntry *soe)
tv.tv_usec = soe->so_rcv_tmo_usec;
ret |= restore_opt(sk, SOL_SOCKET, SO_RCVTIMEO, &tv);
ret = restore_bound_dev(sk, soe);
ret |= restore_bound_dev(sk, soe);
ret |= restore_socket_filter(sk, soe);
/* The restore of SO_REUSEADDR depends on type of socket */
......@@ -226,11 +321,17 @@ int dump_socket_opts(int sk, SkOptsEntry *soe)
soe->has_so_no_check = true;
soe->so_no_check = val ? true : false;
ret = dump_bound_dev(sk, soe);
ret |= dump_bound_dev(sk, soe);
ret |= dump_socket_filter(sk, soe);
return ret;
}
void release_skopts(SkOptsEntry *soe)
{
xfree(soe->so_filter);
}
int dump_socket(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset)
{
int family;
......
......@@ -46,6 +46,7 @@ static/cmdlinenv00
static/socket_listen
static/packet_sock
static/socket_udp
static/sock_filter
static/socket6_udp
static/socket_udplite
static/selfexe00
......
......@@ -27,6 +27,7 @@ TST_NOFILE = \
socket_udplite \
socket_aio \
packet_sock \
sock_filter \
msgque \
inotify_system \
inotify_system_nodel \
......
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/filter.h>
#include <linux/in.h>
#include "zdtmtst.h"
const char *test_doc = "Check socket filter";
const char *test_author = "Pavel Emelyanov <xemul@parallels.com>";
#ifndef SO_GET_FILTER
#define SO_GET_FILTER SO_ATTACH_FILTER
#endif
#define SFLEN 14
int main(int argc, char **argv)
{
int sk;
struct sock_fprog p;
struct sock_filter f[SFLEN] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 4, 0x00000800 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 8, 0, 0x7f000001 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 6, 7, 0x7f000001 },
{ 0x15, 1, 0, 0x00000806 },
{ 0x15, 0, 5, 0x00008035 },
{ 0x20, 0, 0, 0x0000001c },
{ 0x15, 2, 0, 0x7f000001 },
{ 0x20, 0, 0, 0x00000026 },
{ 0x15, 0, 1, 0x7f000001 },
{ 0x6, 0, 0, 0x0000ffff },
{ 0x6, 0, 0, 0x00000000 },
};
struct sock_filter f2[SFLEN], f3[SFLEN];
socklen_t len;
test_init(argc, argv);
sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sk < 0) {
err("No socket");
return 1;
}
p.len = SFLEN;
p.filter = f;
if (setsockopt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &p, sizeof(p))) {
err("No filter");
return 1;
}
len = 0;
if (getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, NULL, &len)) {
err("No len");
return 1;
}
if (len != SFLEN) {
err("Len mismatch");
return 1;
}
memset(f2, 0, sizeof(f2));
if (getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, f2, &len)) {
perror("No filter");
return 1;
}
if (len != SFLEN) {
err("Len mismatch2");
return 1;
}
test_daemon();
test_waitsig();
len = 0;
if (getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, NULL, &len)) {
fail("No len");
return 1;
}
if (len != SFLEN) {
fail("Len mismatch");
return 1;
}
memset(f3, 0, sizeof(f3));
if (getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, f3, &len)) {
fail("No filter");
return 1;
}
if (len != SFLEN) {
fail("Len mismatch2");
return 1;
}
if (memcmp(f2, f3, sizeof(f2))) {
fail("Filters mismatch");
return 1;
}
pass();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment