From 415ab35a441eca767d033a2702223e785b9d5190 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Wed, 24 Feb 2016 11:41:33 +0530 Subject: [PATCH 01/12] net: ne2000: check ring buffer control registers Ne2000 NIC uses ring buffer of NE2000_MEM_SIZE(49152) bytes to process network packets. Registers PSTART & PSTOP define ring buffer size & location. Setting these registers to invalid values could lead to infinite loop or OOB r/w access issues. Add check to avoid it. Reported-by: Yang Hongke Tested-by: Yang Hongke Signed-off-by: Prasad J Pandit Signed-off-by: Jason Wang --- hw/net/ne2000.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index e408083a58..f0feaf96b0 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -155,6 +155,10 @@ static int ne2000_buffer_full(NE2000State *s) { int avail, index, boundary; + if (s->stop <= s->start) { + return 1; + } + index = s->curpag << 8; boundary = s->boundary << 8; if (index < boundary) From 5dd2d45e344b50b018912b6d98ab47493f946eb6 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 15 Feb 2016 12:52:34 +0800 Subject: [PATCH 02/12] net: filter: correctly remove filter from the list during finalization Qemu may crash when we want to add two filters on the same netdev but the initialization of second fails (e.g missing parameters): ./qemu-system-x86_64 -netdev user,id=un0 \ -object filter-buffer,id=f0,netdev=un0,interval=10 \ -object filter-buffer,id=f1,netdev=un0 Segmentation fault (core dumped) This is because we don't check whether or not the filter was in the list of netdev. This patch fixes this. Cc: Yang Hongyang Reviewed-by: Yang Hongyang Signed-off-by: Jason Wang --- net/filter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/filter.c b/net/filter.c index d2a514eb8d..7cdbc6c615 100644 --- a/net/filter.c +++ b/net/filter.c @@ -196,7 +196,8 @@ static void netfilter_finalize(Object *obj) nfc->cleanup(nf); } - if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters)) { + if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) && + nf->next.tqe_prev) { QTAILQ_REMOVE(&nf->netdev->filters, nf, next); } g_free(nf->netdev_id); From d24b2b1cccbf598d004bc211a22af30e064dee65 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 25 Feb 2016 12:56:24 +0100 Subject: [PATCH 03/12] MAINTAINERS: Add entries for include/net/ files The include/net/ files correspond to the files in the net/ directory, thus there should be corresponding entries in the MAINTAINERS file. Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9d0255c72c..c47709d860 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1123,6 +1123,7 @@ Network device backends M: Jason Wang S: Maintained F: net/ +F: include/net/ T: git git://github.com/jasowang/qemu.git net Netmap network backend @@ -1222,6 +1223,7 @@ M: Jan Kiszka S: Maintained F: slirp/ F: net/slirp.c +F: include/net/slirp.h T: git git://git.kiszka.org/qemu.git queues/slirp Tracing From 3a2d44f6dd1d6cc1e5a5ebfa736a72e035c41d1b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Feb 2016 00:05:57 +0100 Subject: [PATCH 04/12] net: simplify net_init_tap_one logic net_init_tap_one receives in vhostfdname a fd name from vhostfd= or vhostfds=, or NULL if there is no vhostfd=/vhostfds=. It is simpler to just check vhostfdname, than it is to check for vhostfd= or vhostfds=. This also calms down Coverity, which otherwise thinks that monitor_fd_param could dereference a NULL vhostfdname. Signed-off-by: Paolo Bonzini Signed-off-by: Jason Wang --- net/tap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tap.c b/net/tap.c index cfb6831988..cd7a7fc860 100644 --- a/net/tap.c +++ b/net/tap.c @@ -662,7 +662,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, options.backend_type = VHOST_BACKEND_TYPE_KERNEL; options.net_backend = &s->nc; - if (tap->has_vhostfd || tap->has_vhostfds) { + if (vhostfdname) { vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err); if (vhostfd == -1) { error_propagate(errp, err); @@ -684,7 +684,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, "vhost-net requested but could not be initialized"); return; } - } else if (tap->has_vhostfd || tap->has_vhostfds) { + } else if (vhostfdname) { error_setg(errp, "vhostfd= is not valid without vhost"); } } From 9fbad2ca36f099699ebdf91c523a9ddc34d6b1c4 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 24 Feb 2016 11:30:41 +0100 Subject: [PATCH 05/12] net: netmap: probe netmap interface for virtio-net header Previous implementation of has_ufo, has_vnet_hdr, has_vnet_hdr_len, etc. did not really probe for virtio-net header support for the netmap interface attached to the backend. These callbacks were correct for VALE ports, but incorrect for hardware NICs, pipes, monitors, etc. This patch fixes the implementation to work properly with all kinds of netmap ports. Signed-off-by: Vincenzo Maffione Signed-off-by: Jason Wang --- net/netmap.c | 75 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/net/netmap.c b/net/netmap.c index 971032120c..1b427287a7 100644 --- a/net/netmap.c +++ b/net/netmap.c @@ -323,30 +323,8 @@ static void netmap_cleanup(NetClientState *nc) } /* Offloading manipulation support callbacks. */ -static bool netmap_has_ufo(NetClientState *nc) +static int netmap_fd_set_vnet_hdr_len(NetmapState *s, int len) { - return true; -} - -static bool netmap_has_vnet_hdr(NetClientState *nc) -{ - return true; -} - -static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len) -{ - return len == 0 || len == sizeof(struct virtio_net_hdr) || - len == sizeof(struct virtio_net_hdr_mrg_rxbuf); -} - -static void netmap_using_vnet_hdr(NetClientState *nc, bool enable) -{ -} - -static void netmap_set_vnet_hdr_len(NetClientState *nc, int len) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - int err; struct nmreq req; /* Issue a NETMAP_BDG_VNET_HDR command to change the virtio-net header @@ -357,10 +335,50 @@ static void netmap_set_vnet_hdr_len(NetClientState *nc, int len) req.nr_version = NETMAP_API; req.nr_cmd = NETMAP_BDG_VNET_HDR; req.nr_arg1 = len; - err = ioctl(s->nmd->fd, NIOCREGIF, &req); + + return ioctl(s->nmd->fd, NIOCREGIF, &req); +} + +static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len) +{ + NetmapState *s = DO_UPCAST(NetmapState, nc, nc); + int prev_len = s->vnet_hdr_len; + + /* Check that we can set the new length. */ + if (netmap_fd_set_vnet_hdr_len(s, len)) { + return false; + } + + /* Restore the previous length. */ + if (netmap_fd_set_vnet_hdr_len(s, prev_len)) { + error_report("Failed to restore vnet-hdr length %d on %s: %s", + prev_len, s->ifname, strerror(errno)); + abort(); + } + + return true; +} + +/* A netmap interface that supports virtio-net headers always + * supports UFO, so we use this callback also for the has_ufo hook. */ +static bool netmap_has_vnet_hdr(NetClientState *nc) +{ + return netmap_has_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr)); +} + +static void netmap_using_vnet_hdr(NetClientState *nc, bool enable) +{ +} + +static void netmap_set_vnet_hdr_len(NetClientState *nc, int len) +{ + NetmapState *s = DO_UPCAST(NetmapState, nc, nc); + int err; + + err = netmap_fd_set_vnet_hdr_len(s, len); if (err) { - error_report("Unable to execute NETMAP_BDG_VNET_HDR on %s: %s", - s->ifname, strerror(errno)); + error_report("Unable to set vnet-hdr length %d on %s: %s", + len, s->ifname, strerror(errno)); } else { /* Keep track of the current length. */ s->vnet_hdr_len = len; @@ -373,8 +391,7 @@ static void netmap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, NetmapState *s = DO_UPCAST(NetmapState, nc, nc); /* Setting a virtio-net header length greater than zero automatically - * enables the offloadings. - */ + * enables the offloadings. */ if (!s->vnet_hdr_len) { netmap_set_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr)); } @@ -388,7 +405,7 @@ static NetClientInfo net_netmap_info = { .receive_iov = netmap_receive_iov, .poll = netmap_poll, .cleanup = netmap_cleanup, - .has_ufo = netmap_has_ufo, + .has_ufo = netmap_has_vnet_hdr, .has_vnet_hdr = netmap_has_vnet_hdr, .has_vnet_hdr_len = netmap_has_vnet_hdr_len, .using_vnet_hdr = netmap_using_vnet_hdr, From 0ab9cd9a4b3f3c464d63fd30e5f958bfdf690af3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 25 Feb 2016 15:31:55 +0100 Subject: [PATCH 06/12] rocker: forbid to change world type Port to world assignment should be permitted only by qemu user. Driver should not be able to do it, so forbid that possibility. Signed-off-by: Jiri Pirko Signed-off-by: Jason Wang --- hw/net/rocker/rocker.c | 8 +++++++- hw/net/rocker/rocker_fp.c | 5 +++++ hw/net/rocker/rocker_fp.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index f3e994d563..a1d921dc1c 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -400,7 +400,13 @@ static int cmd_set_port_settings(Rocker *r, if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) { mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]); - fp_port_set_world(fp_port, r->worlds[mode]); + if (mode >= ROCKER_WORLD_TYPE_MAX) { + return -ROCKER_EINVAL; + } + /* We don't support world change. */ + if (!fp_port_check_world(fp_port, r->worlds[mode])) { + return -ROCKER_EINVAL; + } } if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) { diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c index af37fefc0a..0149899c62 100644 --- a/hw/net/rocker/rocker_fp.c +++ b/hw/net/rocker/rocker_fp.c @@ -186,6 +186,11 @@ void fp_port_set_world(FpPort *port, World *world) port->world = world; } +bool fp_port_check_world(FpPort *port, World *world) +{ + return port->world == world; +} + bool fp_port_enabled(FpPort *port) { return port->enabled; diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h index ab80fd833c..04592bbfd2 100644 --- a/hw/net/rocker/rocker_fp.h +++ b/hw/net/rocker/rocker_fp.h @@ -40,6 +40,7 @@ int fp_port_set_settings(FpPort *port, uint32_t speed, bool fp_port_from_pport(uint32_t pport, uint32_t *port); World *fp_port_get_world(FpPort *port); void fp_port_set_world(FpPort *port, World *world); +bool fp_port_check_world(FpPort *port, World *world); bool fp_port_enabled(FpPort *port); void fp_port_enable(FpPort *port); void fp_port_disable(FpPort *port); From 39e0c4f47d263453cd10920d0c372b370ffaf990 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 25 Feb 2016 15:31:56 +0100 Subject: [PATCH 07/12] rocker: return -ENOMEM in case of some world alloc fails Until now, 0 is returned in this error case. Fix it ro return -ENOMEM. Signed-off-by: Jiri Pirko Signed-off-by: Jason Wang --- hw/net/rocker/rocker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index a1d921dc1c..104c097852 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -1301,6 +1301,7 @@ static int pci_rocker_init(PCIDevice *dev) for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { if (!r->worlds[i]) { + err = -ENOMEM; goto err_world_alloc; } } From 031143c8d5ad9d82623a252551ef323219cbe642 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 25 Feb 2016 15:31:57 +0100 Subject: [PATCH 08/12] rocker: add name field into WorldOps ale let world specify its name Also use this in world_name getter function. Signed-off-by: Jiri Pirko Signed-off-by: Jason Wang --- hw/net/rocker/rocker_of_dpa.c | 1 + hw/net/rocker/rocker_world.c | 7 +------ hw/net/rocker/rocker_world.h | 1 + 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index da3fc541d8..0a134ebca8 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -2614,6 +2614,7 @@ RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, } static WorldOps of_dpa_ops = { + .name = "ofdpa", .init = of_dpa_init, .uninit = of_dpa_uninit, .ig = of_dpa_ig, diff --git a/hw/net/rocker/rocker_world.c b/hw/net/rocker/rocker_world.c index 1ed0fcd163..89777e9684 100644 --- a/hw/net/rocker/rocker_world.c +++ b/hw/net/rocker/rocker_world.c @@ -98,10 +98,5 @@ enum rocker_world_type world_type(World *world) const char *world_name(World *world) { - switch (world->type) { - case ROCKER_WORLD_TYPE_OF_DPA: - return "OF_DPA"; - default: - return "unknown"; - } + return world->ops->name; } diff --git a/hw/net/rocker/rocker_world.h b/hw/net/rocker/rocker_world.h index 18d277b927..58ade47335 100644 --- a/hw/net/rocker/rocker_world.h +++ b/hw/net/rocker/rocker_world.h @@ -33,6 +33,7 @@ typedef int (world_cmd)(World *world, DescInfo *info, RockerTlv *cmd_info_tlv); typedef struct world_ops { + const char *name; world_init *init; world_uninit *uninit; world_ig *ig; From 9fe7101f1d3c08b01fc8b4eab736a3f8c8b44f45 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 25 Feb 2016 15:31:58 +0100 Subject: [PATCH 09/12] rocker: allow user to specify rocker world by property Add property to specify rocker world. All ports will be assigned to this world. Signed-off-by: Jiri Pirko Signed-off-by: Jason Wang --- hw/net/rocker/rocker.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 104c097852..30f2ce417b 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -43,6 +43,7 @@ struct rocker { /* switch configuration */ char *name; /* switch name */ + char *world_name; /* world name */ uint32_t fp_ports; /* front-panel port count */ NICPeers *fp_ports_peers; MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */ @@ -1286,6 +1287,18 @@ static void rocker_msix_uninit(Rocker *r) rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports)); } +static World *rocker_world_type_by_name(Rocker *r, const char *name) +{ + int i; + + for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { + if (strcmp(name, world_name(r->worlds[i])) == 0) { + return r->worlds[i]; + } + } + return NULL; +} + static int pci_rocker_init(PCIDevice *dev) { Rocker *r = to_rocker(dev); @@ -1297,7 +1310,6 @@ static int pci_rocker_init(PCIDevice *dev) /* allocate worlds */ r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r); - r->world_dflt = r->worlds[ROCKER_WORLD_TYPE_OF_DPA]; for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { if (!r->worlds[i]) { @@ -1306,6 +1318,19 @@ static int pci_rocker_init(PCIDevice *dev) } } + if (!r->world_name) { + r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA])); + } + + r->world_dflt = rocker_world_type_by_name(r, r->world_name); + if (!r->world_dflt) { + fprintf(stderr, + "rocker: requested world \"%s\" does not exist\n", + r->world_name); + err = -EINVAL; + goto err_world_type_by_name; + } + /* set up memory-mapped region at BAR0 */ memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r, @@ -1439,6 +1464,7 @@ err_duplicate: err_msix_init: object_unparent(OBJECT(&r->msix_bar)); object_unparent(OBJECT(&r->mmio)); +err_world_type_by_name: err_world_alloc: for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) { if (r->worlds[i]) { @@ -1510,6 +1536,7 @@ static void rocker_reset(DeviceState *dev) static Property rocker_properties[] = { DEFINE_PROP_STRING("name", Rocker, name), + DEFINE_PROP_STRING("world", Rocker, world_name), DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker, fp_start_macaddr), DEFINE_PROP_UINT64("switch_id", Rocker, From 338d3f415e131673ea51719b0c30edf65f69d806 Mon Sep 17 00:00:00 2001 From: zhanghailiang Date: Tue, 1 Mar 2016 13:37:02 +0800 Subject: [PATCH 10/12] filter: Add 'status' property for filter object With this property, users can control if this filter is 'on' or 'off'. The default behavior for filter is 'on'. For some types of filters, they may need to react to status changing, So here, we introduced status changing callback/notifier for filter class. We will skip the disabled ('off') filter when delivering packets in net layer. Signed-off-by: zhanghailiang Cc: Jason Wang Cc: Yang Hongyang Signed-off-by: Jason Wang --- include/net/filter.h | 4 ++++ net/filter.c | 41 +++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 4 +++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/net/filter.h b/include/net/filter.h index 56399763cc..cfb11728df 100644 --- a/include/net/filter.h +++ b/include/net/filter.h @@ -36,12 +36,15 @@ typedef ssize_t (FilterReceiveIOV)(NetFilterState *nc, int iovcnt, NetPacketSent *sent_cb); +typedef void (FilterStatusChanged) (NetFilterState *nf, Error **errp); + typedef struct NetFilterClass { ObjectClass parent_class; /* optional */ FilterSetup *setup; FilterCleanup *cleanup; + FilterStatusChanged *status_changed; /* mandatory */ FilterReceiveIOV *receive_iov; } NetFilterClass; @@ -55,6 +58,7 @@ struct NetFilterState { char *netdev_id; NetClientState *netdev; NetFilterDirection direction; + bool on; QTAILQ_ENTRY(NetFilterState) next; }; diff --git a/net/filter.c b/net/filter.c index 7cdbc6c615..a08ef68ae6 100644 --- a/net/filter.c +++ b/net/filter.c @@ -17,6 +17,11 @@ #include "qom/object_interfaces.h" #include "qemu/iov.h" +static inline bool qemu_can_skip_netfilter(NetFilterState *nf) +{ + return !nf->on; +} + ssize_t qemu_netfilter_receive(NetFilterState *nf, NetFilterDirection direction, NetClientState *sender, @@ -25,6 +30,9 @@ ssize_t qemu_netfilter_receive(NetFilterState *nf, int iovcnt, NetPacketSent *sent_cb) { + if (qemu_can_skip_netfilter(nf)) { + return 0; + } if (nf->direction == direction || nf->direction == NET_FILTER_DIRECTION_ALL) { return NETFILTER_GET_CLASS(OBJECT(nf))->receive_iov( @@ -134,8 +142,38 @@ static void netfilter_set_direction(Object *obj, int direction, Error **errp) nf->direction = direction; } +static char *netfilter_get_status(Object *obj, Error **errp) +{ + NetFilterState *nf = NETFILTER(obj); + + return nf->on ? g_strdup("on") : g_strdup("off"); +} + +static void netfilter_set_status(Object *obj, const char *str, Error **errp) +{ + NetFilterState *nf = NETFILTER(obj); + NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); + + if (strcmp(str, "on") && strcmp(str, "off")) { + error_setg(errp, "Invalid value for netfilter status, " + "should be 'on' or 'off'"); + return; + } + if (nf->on == !strcmp(str, "on")) { + return; + } + nf->on = !nf->on; + if (nfc->status_changed) { + nfc->status_changed(nf, errp); + } +} + static void netfilter_init(Object *obj) { + NetFilterState *nf = NETFILTER(obj); + + nf->on = true; + object_property_add_str(obj, "netdev", netfilter_get_netdev_id, netfilter_set_netdev_id, NULL); @@ -143,6 +181,9 @@ static void netfilter_init(Object *obj) NetFilterDirection_lookup, netfilter_get_direction, netfilter_set_direction, NULL); + object_property_add_str(obj, "status", + netfilter_get_status, netfilter_set_status, + NULL); } static void netfilter_complete(UserCreatable *uc, Error **errp) diff --git a/qemu-options.hx b/qemu-options.hx index 2aa6577c14..2b3ed86849 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3788,11 +3788,13 @@ version by providing the @var{passwordid} parameter. This provides the ID of a previously created @code{secret} object containing the password for decryption. -@item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}] +@item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}][,status=@var{on|off}] Interval @var{t} can't be 0, this filter batches the packet delivery: all packets arriving in a given interval on netdev @var{netdevid} are delayed until the end of the interval. Interval is in microseconds. +@option{status} is optional that indicate whether the netfilter is +on (enabled) or off (disabled), the default status for netfilter will be 'on'. queue @var{all|rx|tx} is an option that can be applied to any netfilter. From f1b2bc601af5037f0af6d55575e619b912e348b5 Mon Sep 17 00:00:00 2001 From: zhanghailiang Date: Tue, 1 Mar 2016 13:37:03 +0800 Subject: [PATCH 11/12] filter-buffer: Add status_changed callback processing While the status of filter-buffer changing from 'on' to 'off', it need to release all the buffered packets, and delete the related timer, while switch from 'off' to 'on', it need to resume the release packets timer. Here, we extract the process of setup timer into a new helper, which will be used in the new status_changed callback. Signed-off-by: zhanghailiang Cc: Jason Wang Cc: Yang Hongyang Signed-off-by: Jason Wang --- net/filter-buffer.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/net/filter-buffer.c b/net/filter-buffer.c index 12ad2e30d4..972177b453 100644 --- a/net/filter-buffer.c +++ b/net/filter-buffer.c @@ -100,6 +100,19 @@ static void filter_buffer_cleanup(NetFilterState *nf) } } +static void filter_buffer_setup_timer(NetFilterState *nf) +{ + FilterBufferState *s = FILTER_BUFFER(nf); + + if (s->interval) { + timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL, + filter_buffer_release_timer, nf); + /* Timer armed to fire in s->interval microseconds. */ + timer_mod(&s->release_timer, + qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval); + } +} + static void filter_buffer_setup(NetFilterState *nf, Error **errp) { FilterBufferState *s = FILTER_BUFFER(nf); @@ -115,12 +128,20 @@ static void filter_buffer_setup(NetFilterState *nf, Error **errp) } s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf); - if (s->interval) { - timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL, - filter_buffer_release_timer, nf); - /* Timer armed to fire in s->interval microseconds. */ - timer_mod(&s->release_timer, - qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval); + filter_buffer_setup_timer(nf); +} + +static void filter_buffer_status_changed(NetFilterState *nf, Error **errp) +{ + FilterBufferState *s = FILTER_BUFFER(nf); + + if (!nf->on) { + if (s->interval) { + timer_del(&s->release_timer); + } + filter_buffer_flush(nf); + } else { + filter_buffer_setup_timer(nf); } } @@ -131,6 +152,7 @@ static void filter_buffer_class_init(ObjectClass *oc, void *data) nfc->setup = filter_buffer_setup; nfc->cleanup = filter_buffer_cleanup; nfc->receive_iov = filter_buffer_receive_iov; + nfc->status_changed = filter_buffer_status_changed; } static void filter_buffer_get_interval(Object *obj, Visitor *v, From 362786f14a753d8a5256ef97d7c10ed576d6572b Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Wed, 2 Mar 2016 17:29:58 +0530 Subject: [PATCH 12/12] net: check packet payload length While computing IP checksum, 'net_checksum_calculate' reads payload length from the packet. It could exceed the given 'data' buffer size. Add a check to avoid it. Reported-by: Liu Ling Signed-off-by: Prasad J Pandit Signed-off-by: Jason Wang --- net/checksum.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/checksum.c b/net/checksum.c index b5016ab40c..d0fa424cc1 100644 --- a/net/checksum.c +++ b/net/checksum.c @@ -60,6 +60,11 @@ void net_checksum_calculate(uint8_t *data, int length) int hlen, plen, proto, csum_offset; uint16_t csum; + /* Ensure data has complete L2 & L3 headers. */ + if (length < 14 + 20) { + return; + } + if ((data[14] & 0xf0) != 0x40) return; /* not IPv4 */ hlen = (data[14] & 0x0f) * 4; @@ -77,8 +82,9 @@ void net_checksum_calculate(uint8_t *data, int length) return; } - if (plen < csum_offset+2) - return; + if (plen < csum_offset + 2 || 14 + hlen + plen > length) { + return; + } data[14+hlen+csum_offset] = 0; data[14+hlen+csum_offset+1] = 0;