Commit d4735a22 authored by Pavel Emelyanov's avatar Pavel Emelyanov

packet: Support mmap-ing of packet sockets

Three parts.

Proc: open of map_files' link doesn't work on sockets. We fstatat
it and check that it's a socket (it will be packet), then save
the socket inode on vma_area.

Dump: we resolve socket inode to socket id and save it on vma.
We use id, not inode, since on restore we'll have to mmap some
opened file, not just abstract socket with inode.

Restore: when reading vma-s we just need to find out on what fd
the respective packet socket is opened (i.e. -- no map-and-close
sockets supported by now) and dup() it to let restorer mmap it
back.

All this make it possible to c/r the tcpdump tool!
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent a385c6fa
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "mount.h" #include "mount.h"
#include "tty.h" #include "tty.h"
#include "net.h" #include "net.h"
#include "sk-packet.h"
#ifndef CONFIG_X86_64 #ifndef CONFIG_X86_64
# error No x86-32 support yet # error No x86-32 support yet
...@@ -479,6 +480,8 @@ static int dump_task_mappings(pid_t pid, const struct list_head *vma_area_list, ...@@ -479,6 +480,8 @@ static int dump_task_mappings(pid_t pid, const struct list_head *vma_area_list,
else if (vma_entry_is(vma, VMA_FILE_PRIVATE) || else if (vma_entry_is(vma, VMA_FILE_PRIVATE) ||
vma_entry_is(vma, VMA_FILE_SHARED)) vma_entry_is(vma, VMA_FILE_SHARED))
ret = dump_filemap(pid, vma, vma_area->vm_file_fd, cr_fdset); ret = dump_filemap(pid, vma, vma_area->vm_file_fd, cr_fdset);
else if (vma_entry_is(vma, VMA_AREA_SOCKET))
ret = dump_socket_map(vma_area);
else else
ret = 0; ret = 0;
......
...@@ -224,6 +224,8 @@ static int read_and_open_vmas(int pid, struct list_head *vmas, int *nr_vmas) ...@@ -224,6 +224,8 @@ static int read_and_open_vmas(int pid, struct list_head *vmas, int *nr_vmas)
else if (vma_entry_is(&vma->vma, VMA_FILE_PRIVATE) || else if (vma_entry_is(&vma->vma, VMA_FILE_PRIVATE) ||
vma_entry_is(&vma->vma, VMA_FILE_SHARED)) vma_entry_is(&vma->vma, VMA_FILE_SHARED))
ret = get_filemap_fd(pid, &vma->vma); ret = get_filemap_fd(pid, &vma->vma);
else if (vma_entry_is(&vma->vma, VMA_AREA_SOCKET))
ret = get_socket_fd(pid, &vma->vma);
else else
continue; continue;
......
...@@ -211,7 +211,11 @@ void free_mappings(struct list_head *vma_area_list); ...@@ -211,7 +211,11 @@ void free_mappings(struct list_head *vma_area_list);
struct vma_area { struct vma_area {
struct list_head list; struct list_head list;
VmaEntry vma; VmaEntry vma;
int vm_file_fd;
union {
int vm_file_fd;
int vm_socket_id;
};
}; };
#define vma_area_is(vma_area, s) vma_entry_is(&((vma_area)->vma), s) #define vma_area_is(vma_area, s) vma_entry_is(&((vma_area)->vma), s)
......
...@@ -92,6 +92,7 @@ ...@@ -92,6 +92,7 @@
#define VMA_ANON_PRIVATE (1 << 9) #define VMA_ANON_PRIVATE (1 << 9)
#define VMA_AREA_SYSVIPC (1 << 10) #define VMA_AREA_SYSVIPC (1 << 10)
#define VMA_AREA_SOCKET (1 << 11)
#define vma_entry_is(vma, s) (((vma)->status & (s)) == (s)) #define vma_entry_is(vma, s) (((vma)->status & (s)) == (s))
#define vma_entry_len(vma) ((vma)->end - (vma)->start) #define vma_entry_len(vma) ((vma)->end - (vma)->start)
......
...@@ -8,11 +8,15 @@ ...@@ -8,11 +8,15 @@
struct cr_fdset; struct cr_fdset;
struct fd_parms; struct fd_parms;
struct cr_options; struct cr_options;
struct vma_area;
int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds); int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds);
int collect_packet_sockets(void); int collect_packet_sockets(void);
void show_packetsk(int fd, struct cr_options *); void show_packetsk(int fd, struct cr_options *);
int dump_socket_map(struct vma_area *vma);
int get_socket_fd(int pid, VmaEntry *vma);
extern int packet_receive_one(struct nlmsghdr *h, void *arg); extern int packet_receive_one(struct nlmsghdr *h, void *arg);
#ifndef PACKET_VNET_HDR #ifndef PACKET_VNET_HDR
......
...@@ -174,10 +174,20 @@ int parse_smaps(pid_t pid, struct list_head *vma_area_list, bool use_map_files) ...@@ -174,10 +174,20 @@ int parse_smaps(pid_t pid, struct list_head *vma_area_list, bool use_map_files)
*/ */
vma_area->vm_file_fd = openat(dirfd(map_files_dir), path, O_RDONLY); vma_area->vm_file_fd = openat(dirfd(map_files_dir), path, O_RDONLY);
if (vma_area->vm_file_fd < 0) { if (vma_area->vm_file_fd < 0) {
if (errno != ENOENT) { if (errno == ENXIO) {
pr_perror("Can't open %d's map %lx", pid, start); struct stat buf;
goto err;
} if (fstatat(dirfd(map_files_dir), path, &buf, 0))
goto err_bogus_mapfile;
if (!S_ISSOCK(buf.st_mode))
goto err_bogus_mapfile;
pr_info("Found socket %lu mapping @%lx\n", buf.st_ino, start);
vma_area->vma.status |= VMA_AREA_SOCKET | VMA_AREA_REGULAR;
vma_area->vm_socket_id = buf.st_ino;
} else if (errno != ENOENT)
goto err_bogus_mapfile;
} }
} }
...@@ -202,7 +212,9 @@ int parse_smaps(pid_t pid, struct list_head *vma_area_list, bool use_map_files) ...@@ -202,7 +212,9 @@ int parse_smaps(pid_t pid, struct list_head *vma_area_list, bool use_map_files)
goto err; goto err;
} }
if (strstr(buf, "[vsyscall]")) { if (vma_area->vma.status != 0) {
goto done;
} else if (strstr(buf, "[vsyscall]")) {
vma_area->vma.status |= VMA_AREA_VSYSCALL; vma_area->vma.status |= VMA_AREA_VSYSCALL;
} else if (strstr(buf, "[vdso]")) { } else if (strstr(buf, "[vdso]")) {
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO; vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
...@@ -261,7 +273,7 @@ int parse_smaps(pid_t pid, struct list_head *vma_area_list, bool use_map_files) ...@@ -261,7 +273,7 @@ int parse_smaps(pid_t pid, struct list_head *vma_area_list, bool use_map_files)
} }
vma_area->vma.flags |= MAP_ANONYMOUS; vma_area->vma.flags |= MAP_ANONYMOUS;
} }
done:
list_add_tail(&vma_area->list, vma_area_list); list_add_tail(&vma_area->list, vma_area_list);
nr++; nr++;
} }
...@@ -284,6 +296,10 @@ err_bogus_mapping: ...@@ -284,6 +296,10 @@ err_bogus_mapping:
vma_area->vma.start, vma_area->vma.end, vma_area->vma.start, vma_area->vma.end,
vma_area->vma.flags, vma_area->vm_file_fd); vma_area->vma.flags, vma_area->vm_file_fd);
goto err; goto err;
err_bogus_mapfile:
pr_perror("Can't open %d's mapfile link %lx", pid, start);
goto err;
} }
int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s) int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s)
......
...@@ -30,6 +30,7 @@ struct packet_mreq_max { ...@@ -30,6 +30,7 @@ struct packet_mreq_max {
struct packet_sock_desc { struct packet_sock_desc {
struct socket_desc sd; struct socket_desc sd;
unsigned int file_id;
unsigned int type; unsigned int type;
unsigned short proto; unsigned short proto;
struct packet_diag_info nli; struct packet_diag_info nli;
...@@ -158,7 +159,7 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p) ...@@ -158,7 +159,7 @@ static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
BUG_ON(sd->sd.already_dumped); BUG_ON(sd->sd.already_dumped);
sd->sd.already_dumped = 1; sd->sd.already_dumped = 1;
psk.id = id; psk.id = sd->file_id = id;
psk.type = sd->type; psk.type = sd->type;
psk.flags = p->flags; psk.flags = p->flags;
psk.fown = (FownEntry *)&p->fown; psk.fown = (FownEntry *)&p->fown;
...@@ -212,6 +213,26 @@ int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds) ...@@ -212,6 +213,26 @@ int dump_one_packet_sk(struct fd_parms *p, int lfd, const struct cr_fdset *fds)
return do_dump_gen_file(p, lfd, &packet_dump_ops, fds); return do_dump_gen_file(p, lfd, &packet_dump_ops, fds);
} }
int dump_socket_map(struct vma_area *vma)
{
struct packet_sock_desc *sd;
sd = (struct packet_sock_desc *)lookup_socket(vma->vm_socket_id, PF_PACKET);
if (!sd) {
pr_err("Can't find packet socket %u to mmap\n", vma->vm_socket_id);
return -1;
}
if (!sd->file_id) {
pr_err("Mmap-ed socket %u not open\n", vma->vm_socket_id);
return -1;
}
pr_info("Dumping socket map %x -> %lx\n", sd->file_id, vma->vma.start);
vma->vma.shmid = sd->file_id;
return 0;
}
static int packet_save_mreqs(struct packet_sock_desc *sd, struct rtattr *mc) static int packet_save_mreqs(struct packet_sock_desc *sd, struct rtattr *mc)
{ {
sd->mreq_n = RTA_PAYLOAD(mc) / sizeof(struct packet_diag_mclist); sd->mreq_n = RTA_PAYLOAD(mc) / sizeof(struct packet_diag_mclist);
...@@ -249,6 +270,7 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg) ...@@ -249,6 +270,7 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg)
if (!sd) if (!sd)
return -1; return -1;
sd->file_id = 0;
sd->type = m->pdiag_type; sd->type = m->pdiag_type;
sd->proto = htons(m->pdiag_num); sd->proto = htons(m->pdiag_num);
memcpy(&sd->nli, RTA_DATA(tb[PACKET_DIAG_INFO]), sizeof(sd->nli)); memcpy(&sd->nli, RTA_DATA(tb[PACKET_DIAG_INFO]), sizeof(sd->nli));
...@@ -276,6 +298,40 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg) ...@@ -276,6 +298,40 @@ int packet_receive_one(struct nlmsghdr *hdr, void *arg)
return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd); return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd);
} }
int get_socket_fd(int pid, VmaEntry *vma)
{
struct file_desc *fd;
struct fdinfo_list_entry *le;
pr_info("Getting packet socket fd for %d:%x\n",
pid, (int)vma->shmid);
fd = find_file_desc_raw(FD_TYPES__PACKETSK, vma->shmid);
if (!fd) {
pr_err("No packet socket %x\n", (int)vma->shmid);
return -1;
}
list_for_each_entry(le, &fd->fd_info_head, desc_list)
if (le->pid == pid) {
int fd;
/*
* Restorer will close the mmap-ed fd
*/
fd = dup(le->fe->fd);
if (!fd) {
pr_perror("Can't dup packet sk");
return -1;
}
return fd;
}
pr_err("No open packet socket %x by %d\n", (int)vma->shmid, pid);
return -1;
}
static int restore_mreqs(int sk, PacketSockEntry *pse) static int restore_mreqs(int sk, PacketSockEntry *pse)
{ {
int i; int i;
......
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