mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-28 09:41:55 +00:00
tc segfaults if gact action is used without action or index:
$ ip link add type dummy
$ tc actions add action pipe index 1
$ tc filter add dev dummy0 parent ffff: protocol ip \
pref 10 u32 match ip src 127.0.0.2 flowid 1:10 action gact
Segmentation fault
We expect tc to fail gracefully with an error message.
This happens if gact is the last argument of the incomplete
command. In this case the "gact" action is parsed, the macro
NEXT_ARG_FWD() is executed and the next matches() crashes
because of null argv pointer.
To avoid this, simply use NEXT_ARG() instead.
With this change in place:
$ ip link add type dummy
$ tc actions add action pipe index 1
$ tc filter add dev dummy0 parent ffff: protocol ip \
pref 10 u32 match ip src 127.0.0.2 flowid 1:10 action gact
Command line is not complete. Try option "help"
Fixes: fa49588973 ("tc: Fix binding of gact action by index.")
Reported-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
221 lines
5.0 KiB
C
221 lines
5.0 KiB
C
/*
|
|
* m_gact.c generic actions module
|
|
*
|
|
* This program is free software; you can distribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
* Authors: J Hadi Salim (hadi@cyberus.ca)
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <string.h>
|
|
|
|
#include "utils.h"
|
|
#include "tc_util.h"
|
|
#include <linux/tc_act/tc_gact.h>
|
|
|
|
/* define to turn on probablity stuff */
|
|
|
|
#ifdef CONFIG_GACT_PROB
|
|
static const char *prob_n2a(int p)
|
|
{
|
|
if (p == PGACT_NONE)
|
|
return "none";
|
|
if (p == PGACT_NETRAND)
|
|
return "netrand";
|
|
if (p == PGACT_DETERM)
|
|
return "determ";
|
|
return "none";
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
explain(void)
|
|
{
|
|
#ifdef CONFIG_GACT_PROB
|
|
fprintf(stderr, "Usage: ... gact <ACTION> [RAND] [INDEX]\n");
|
|
fprintf(stderr,
|
|
"Where: \tACTION := reclassify | drop | continue | pass | pipe |\n"
|
|
" \t goto chain <CHAIN_INDEX> | jump <JUMP_COUNT>\n"
|
|
"\tRAND := random <RANDTYPE> <ACTION> <VAL>\n"
|
|
"\tRANDTYPE := netrand | determ\n"
|
|
"\tVAL : = value not exceeding 10000\n"
|
|
"\tJUMP_COUNT := Absolute jump from start of action list\n"
|
|
"\tINDEX := index value used\n"
|
|
"\n");
|
|
#else
|
|
fprintf(stderr, "Usage: ... gact <ACTION> [INDEX]\n"
|
|
"Where: \tACTION := reclassify | drop | continue | pass | pipe |\n"
|
|
" \t goto chain <CHAIN_INDEX> | jump <JUMP_COUNT>\n"
|
|
"\tINDEX := index value used\n"
|
|
"\tJUMP_COUNT := Absolute jump from start of action list\n"
|
|
"\n");
|
|
#endif
|
|
}
|
|
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
explain();
|
|
exit(-1);
|
|
}
|
|
|
|
static int
|
|
parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
|
|
int tca_id, struct nlmsghdr *n)
|
|
{
|
|
int argc = *argc_p;
|
|
char **argv = *argv_p;
|
|
struct tc_gact p = { 0 };
|
|
#ifdef CONFIG_GACT_PROB
|
|
int rd = 0;
|
|
struct tc_gact_p pp;
|
|
#endif
|
|
struct rtattr *tail;
|
|
|
|
if (argc < 0)
|
|
return -1;
|
|
|
|
if (!matches(*argv, "gact"))
|
|
NEXT_ARG();
|
|
/* we're binding existing gact action to filter by index. */
|
|
if (!matches(*argv, "index"))
|
|
goto skip_args;
|
|
if (parse_action_control(&argc, &argv, &p.action, false))
|
|
usage(); /* does not return */
|
|
|
|
#ifdef CONFIG_GACT_PROB
|
|
if (argc > 0) {
|
|
if (matches(*argv, "random") == 0) {
|
|
rd = 1;
|
|
NEXT_ARG();
|
|
if (matches(*argv, "netrand") == 0) {
|
|
NEXT_ARG();
|
|
pp.ptype = PGACT_NETRAND;
|
|
} else if (matches(*argv, "determ") == 0) {
|
|
NEXT_ARG();
|
|
pp.ptype = PGACT_DETERM;
|
|
} else {
|
|
fprintf(stderr, "Illegal \"random type\"\n");
|
|
return -1;
|
|
}
|
|
|
|
if (parse_action_control(&argc, &argv,
|
|
&pp.paction, false) == -1)
|
|
usage();
|
|
if (get_u16(&pp.pval, *argv, 10)) {
|
|
fprintf(stderr,
|
|
"Illegal probability val 0x%x\n",
|
|
pp.pval);
|
|
return -1;
|
|
}
|
|
if (pp.pval > 10000) {
|
|
fprintf(stderr,
|
|
"Illegal probability val 0x%x\n",
|
|
pp.pval);
|
|
return -1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
} else if (matches(*argv, "help") == 0) {
|
|
usage();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (argc > 0) {
|
|
if (matches(*argv, "index") == 0) {
|
|
skip_args:
|
|
NEXT_ARG();
|
|
if (get_u32(&p.index, *argv, 10)) {
|
|
fprintf(stderr, "Illegal \"index\"\n");
|
|
return -1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
} else if (matches(*argv, "help") == 0) {
|
|
usage();
|
|
}
|
|
}
|
|
|
|
tail = addattr_nest(n, MAX_MSG, tca_id);
|
|
addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p));
|
|
#ifdef CONFIG_GACT_PROB
|
|
if (rd)
|
|
addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp));
|
|
#endif
|
|
addattr_nest_end(n, tail);
|
|
|
|
*argc_p = argc;
|
|
*argv_p = argv;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
print_gact(struct action_util *au, FILE *f, struct rtattr *arg)
|
|
{
|
|
#ifdef CONFIG_GACT_PROB
|
|
struct tc_gact_p *pp = NULL;
|
|
struct tc_gact_p pp_dummy;
|
|
#endif
|
|
struct tc_gact *p = NULL;
|
|
struct rtattr *tb[TCA_GACT_MAX + 1];
|
|
|
|
if (arg == NULL)
|
|
return -1;
|
|
|
|
parse_rtattr_nested(tb, TCA_GACT_MAX, arg);
|
|
|
|
if (tb[TCA_GACT_PARMS] == NULL) {
|
|
fprintf(stderr, "Missing gact parameters\n");
|
|
return -1;
|
|
}
|
|
p = RTA_DATA(tb[TCA_GACT_PARMS]);
|
|
|
|
print_string(PRINT_ANY, "kind", "%s ", "gact");
|
|
print_action_control(f, "action ", p->action, "");
|
|
#ifdef CONFIG_GACT_PROB
|
|
if (tb[TCA_GACT_PROB] != NULL) {
|
|
pp = RTA_DATA(tb[TCA_GACT_PROB]);
|
|
} else {
|
|
/* need to keep consistent output */
|
|
memset(&pp_dummy, 0, sizeof(pp_dummy));
|
|
pp = &pp_dummy;
|
|
}
|
|
open_json_object("prob");
|
|
print_string(PRINT_ANY, "random_type", "\n\t random type %s",
|
|
prob_n2a(pp->ptype));
|
|
print_action_control(f, " ", pp->paction, " ");
|
|
print_int(PRINT_ANY, "val", "val %d", pp->pval);
|
|
close_json_object();
|
|
#endif
|
|
print_uint(PRINT_ANY, "index", "\n\t index %u", p->index);
|
|
print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
|
|
print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
|
|
if (show_stats) {
|
|
if (tb[TCA_GACT_TM]) {
|
|
struct tcf_t *tm = RTA_DATA(tb[TCA_GACT_TM]);
|
|
|
|
print_tm(f, tm);
|
|
}
|
|
}
|
|
print_string(PRINT_FP, NULL, "%s", "\n");
|
|
return 0;
|
|
}
|
|
|
|
struct action_util gact_action_util = {
|
|
.id = "gact",
|
|
.parse_aopt = parse_gact,
|
|
.print_aopt = print_gact,
|
|
};
|