2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-22 18:07:57 +00:00
criu/sk-netlink.c

239 lines
5.2 KiB
C
Raw Normal View History

#include <unistd.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <poll.h>
#include "fdset.h"
#include "files.h"
#include "sockets.h"
#include "util.h"
#include "protobuf.h"
#include "protobuf/sk-netlink.pb-c.h"
#include "netlink_diag.h"
#include "libnetlink.h"
struct netlink_sk_desc {
struct socket_desc sd;
u32 portid;
u32 *groups;
u32 gsize;
u32 dst_portid;
u32 dst_group;
u8 state;
u8 protocol;
};
int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
{
struct rtattr *tb[NETLINK_DIAG_MAX+1];
struct netlink_diag_msg *m;
struct netlink_sk_desc *sd;
unsigned long *groups;
m = NLMSG_DATA(hdr);
pr_info("Collect netlink sock 0x%x\n", m->ndiag_ino);
sd = xmalloc(sizeof(*sd));
if (!sd)
return -1;
sd->protocol = m->ndiag_protocol;
sd->portid = m->ndiag_portid;
sd->dst_portid = m->ndiag_dst_portid;
sd->dst_group = m->ndiag_dst_group;
sd->state = m->ndiag_state;
parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr *)(m + 1),
hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
if (tb[NETLINK_DIAG_GROUPS]) {
sd->gsize = RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS]);
groups = RTA_DATA(tb[NETLINK_DIAG_GROUPS]);
sk-netlink: fix overflow break running./crtools check : *** buffer overflow detected ***: ./crtools terminated ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7fdaacb3e82c] /lib/x86_64-linux-gnu/libc.so.6(+0x109700)[0x7fdaacb3d700] ./crtools[0x423d00] ./crtools[0x41d021] ./crtools[0x41d259] ./crtools[0x41e4b6] ./crtools[0x418f03] ./crtools[0x404988] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fdaaca5576d] ./crtools[0x404ad9] ======= Memory map: ======== 00400000-00463000 r-xp 00000000 08:01 189158 /home/clb/crtools/crtools 00662000-00663000 r--p 00062000 08:01 189158 /home/clb/crtools/crtools 00663000-00671000 rw-p 00063000 08:01 189158 /home/clb/crtools/crtools 00671000-00677000 rw-p 00000000 00:00 0 01801000-01822000 rw-p 00000000 00:00 0 [heap] 7fdaac81e000-7fdaac833000 r-xp 00000000 08:01 410533 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fdaac833000-7fdaaca32000 ---p 00015000 08:01 410533 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fdaaca32000-7fdaaca33000 r--p 00014000 08:01 410533 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fdaaca33000-7fdaaca34000 rw-p 00015000 08:01 410533 /lib/x86_64-linux-gnu/libgcc_s.so.1 7fdaaca34000-7fdaacbe9000 r-xp 00000000 08:01 393459 /lib/x86_64-linux-gnu/libc-2.15.so 7fdaacbe9000-7fdaacde8000 ---p 001b5000 08:01 393459 /lib/x86_64-linux-gnu/libc-2.15.so 7fdaacde8000-7fdaacdec000 r--p 001b4000 08:01 393459 /lib/x86_64-linux-gnu/libc-2.15.so 7fdaacdec000-7fdaacdee000 rw-p 001b8000 08:01 393459 /lib/x86_64-linux-gnu/libc-2.15.so 7fdaacdee000-7fdaacdf3000 rw-p 00000000 00:00 0 7fdaacdf3000-7fdaace03000 r-xp 00000000 08:01 937695 /usr/local/lib/libprotobuf-c.so.0.0.0 7fdaace03000-7fdaad002000 ---p 00010000 08:01 937695 /usr/local/lib/libprotobuf-c.so.0.0.0 7fdaad002000-7fdaad003000 r--p 0000f000 08:01 937695 /usr/local/lib/libprotobuf-c.so.0.0.0 7fdaad003000-7fdaad004000 rw-p 00010000 08:01 937695 /usr/local/lib/libprotobuf-c.so.0.0.0 7fdaad004000-7fdaad01c000 r-xp 00000000 08:01 393528 /lib/x86_64-linux-gnu/libpthread-2.15.so 7fdaad01c000-7fdaad21b000 ---p 00018000 08:01 393528 /lib/x86_64-linux-gnu/libpthread-2.15.so 7fdaad21b000-7fdaad21c000 r--p 00017000 08:01 393528 /lib/x86_64-linux-gnu/libpthread-2.15.so 7fdaad21c000-7fdaad21d000 rw-p 00018000 08:01 393528 /lib/x86_64-linux-gnu/libpthread-2.15.so 7fdaad21d000-7fdaad221000 rw-p 00000000 00:00 0 7fdaad221000-7fdaad243000 r-xp 00000000 08:01 393441 /lib/x86_64-linux-gnu/ld-2.15.so 7fdaad437000-7fdaad43b000 rw-p 00000000 00:00 0 7fdaad440000-7fdaad443000 rw-p 00000000 00:00 0 7fdaad443000-7fdaad444000 r--p 00022000 08:01 393441 /lib/x86_64-linux-gnu/ld-2.15.so 7fdaad444000-7fdaad446000 rw-p 00023000 08:01 393441 /lib/x86_64-linux-gnu/ld-2.15.so 7fff9eb3c000-7fff9eb5d000 rw-p 00000000 00:00 0 [stack] 7fff9ebcf000-7fff9ebd1000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] I find this overflow by the phase: memcpy(sd->groups, groups, sd->gsize); The reason is sd->gsize = 8 Byte, but sd->groups = xmalloc(sizeof(sd->gsize)) is exact 4 Byte. Signed-off-by: Libo Chen <libo.chen@huawei.com> Signed-off-by: Qiang Huang <h.huangqiang@huawei.com> Acked-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
2013-04-29 16:09:04 +04:00
sd->groups = xmalloc(sd->gsize);
if (!sd->groups) {
xfree(sd);
return -1;
}
memcpy(sd->groups, groups, sd->gsize);
} else {
sd->groups = NULL;
sd->gsize = 0;
}
return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd);
}
static bool can_dump_netlink_sk(int lfd)
{
struct pollfd pfd = {lfd, POLLIN, 0};
int ret;
ret = poll(&pfd, 1, 0);
if (ret < 0) {
pr_perror("poll() failed");
} else if (ret == 1)
pr_err("The socket has data to read\n");
return ret == 0;
}
static int dump_one_netlink_fd(int lfd, u32 id, const struct fd_parms *p)
{
struct netlink_sk_desc *sk;
NetlinkSkEntry ne = NETLINK_SK_ENTRY__INIT;
SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
sk = (struct netlink_sk_desc *)lookup_socket(p->stat.st_ino, PF_NETLINK, 0);
if (IS_ERR(sk))
goto err;
ne.id = id;
ne.ino = p->stat.st_ino;
if (!can_dump_netlink_sk(lfd))
goto err;
if (sk) {
BUG_ON(sk->sd.already_dumped);
ne.protocol = sk->protocol;
ne.portid = sk->portid;
ne.groups = sk->groups;
ne.n_groups = sk->gsize / sizeof(ne.groups[0]);
/*
* On 64-bit sk->gsize is multiple to 8 bytes (sizeof(long)),
* so remove the last 4 bytes if they are empty.
*/
if (ne.n_groups && sk->groups[ne.n_groups - 1] == 0)
ne.n_groups -= 1;
if (ne.n_groups > 1) {
pr_err("%d %x\n", sk->gsize, sk->groups[1]);
pr_err("The netlink socket 0x%x has more than 32 groups\n", ne.ino);
return -1;
}
if (sk->groups && !sk->portid) {
pr_err("The netlink socket 0x%x is bound to groups but not to portid\n", ne.ino);
return -1;
}
ne.state = sk->state;
ne.dst_portid = sk->dst_portid;
ne.dst_group = sk->dst_group;
} else { /* unconnected and unbound socket */
int val;
socklen_t aux = sizeof(val);
if (getsockopt(lfd, SOL_SOCKET, SO_PROTOCOL, &val, &aux) < 0) {
pr_perror("Unable to get protocol for netlink socket");
goto err;
}
ne.protocol = val;
}
ne.fown = (FownEntry *)&p->fown;
ne.opts = &skopts;
if (dump_socket_opts(lfd, &skopts))
goto err;
if (pb_write_one(fdset_fd(glob_fdset, CR_FD_NETLINK_SK), &ne, PB_NETLINK_SK))
goto err;
return 0;
err:
return -1;
}
const struct fdtype_ops netlink_dump_ops = {
.type = FD_TYPES__NETLINKSK,
.dump = dump_one_netlink_fd,
};
struct netlink_sock_info {
NetlinkSkEntry *nse;
struct file_desc d;
};
static int open_netlink_sk(struct file_desc *d)
{
struct netlink_sock_info *nsi;
NetlinkSkEntry *nse;
struct sockaddr_nl addr;
int sk = -1;
nsi = container_of(d, struct netlink_sock_info, d);
nse = nsi->nse;
pr_info("Opening netlink socket id %#x\n", nse->id);
sk = socket(PF_NETLINK, SOCK_RAW, nse->protocol);
if (sk < 0) {
pr_perror("Can't create netlink sock");
goto err;
}
if (nse->portid) {
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
if (nse->n_groups > 1) {
pr_err("Groups above 32 are not supported yet\n");
goto err;
}
if (nse->n_groups)
addr.nl_groups = nse->groups[0];
addr.nl_pid = nse->portid;
if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
pr_perror("Can't bind netlink socket");
goto err;
}
}
if (nse->state == NETLINK_CONNECTED) {
addr.nl_family = AF_NETLINK;
addr.nl_groups = 1 << (nse->dst_group - 1);
addr.nl_pid = nse->dst_portid;
if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
pr_perror("Can't connect netlink socket");
goto err;
}
}
if (rst_file_params(sk, nse->fown, nse->flags))
goto err;
if (restore_socket_opts(sk, nse->opts))
goto err;
return sk;
err:
close(sk);
return -1;
}
static struct file_desc_ops netlink_sock_desc_ops = {
.type = FD_TYPES__NETLINKSK,
.open = open_netlink_sk,
};
static int collect_one_netlink_sk(void *o, ProtobufCMessage *base)
{
struct netlink_sock_info *si = o;
si->nse = pb_msg(base, NetlinkSkEntry);
return file_desc_add(&si->d, si->nse->id, &netlink_sock_desc_ops);
}
struct collect_image_info netlink_sk_cinfo = {
.fd_type = CR_FD_NETLINK_SK,
.pb_type = PB_NETLINK_SK,
.priv_size = sizeof(struct netlink_sock_info),
.collect = collect_one_netlink_sk,
.flags = COLLECT_OPTIONAL,
};