Commit 99bb68ff authored by Vadim Kochan's avatar Vadim Kochan Committed by Stephen Hemminger

ss: fix crash when dump stats from /proc with '-p'

It really partially reverts:

    ec4d0d8a (ss: Replace unixstat struct by new sockstat struct)

but adds few fields (name & peer_name) from removed unixstat to sockstat struct to easy
return original code.

Fixes: ec4d0d8a (ss: Replace unixstat struct by new sockstat struct)
Reported-by: default avatarMarc Dietrich <marvin24@gmx.de>
Signed-off-by: default avatarVadim Kochan <vadim4j@gmail.com>
parent 92de1c2c
...@@ -676,18 +676,6 @@ static int get_slabstat(struct slabstat *s) ...@@ -676,18 +676,6 @@ static int get_slabstat(struct slabstat *s)
return 0; return 0;
} }
static inline void sock_addr_set_str(inet_prefix *prefix, char **ptr)
{
memcpy(prefix->data, ptr, sizeof(char *));
}
static inline char *sock_addr_get_str(const inet_prefix *prefix)
{
char *tmp ;
memcpy(&tmp, prefix->data, sizeof(char *));
return tmp;
}
static unsigned long long cookie_sk_get(const uint32_t *cookie) static unsigned long long cookie_sk_get(const uint32_t *cookie)
{ {
return (((unsigned long long)cookie[1] << 31) << 1) | cookie[0]; return (((unsigned long long)cookie[1] << 31) << 1) | cookie[0];
...@@ -739,6 +727,8 @@ struct sockstat ...@@ -739,6 +727,8 @@ struct sockstat
int refcnt; int refcnt;
unsigned int iface; unsigned int iface;
unsigned long long sk; unsigned long long sk;
char *name;
char *peer_name;
}; };
struct dctcpstat struct dctcpstat
...@@ -1063,9 +1053,9 @@ static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p, ...@@ -1063,9 +1053,9 @@ static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
static int unix_match(const inet_prefix *a, const inet_prefix *p) static int unix_match(const inet_prefix *a, const inet_prefix *p)
{ {
char *addr = sock_addr_get_str(a); char *addr, *pattern;
char *pattern = sock_addr_get_str(p); memcpy(&addr, a->data, sizeof(addr));
memcpy(&pattern, p->data, sizeof(pattern));
if (pattern == NULL) if (pattern == NULL)
return 1; return 1;
if (addr == NULL) if (addr == NULL)
...@@ -1081,7 +1071,8 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) ...@@ -1081,7 +1071,8 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
static int low, high=65535; static int low, high=65535;
if (s->local.family == AF_UNIX) { if (s->local.family == AF_UNIX) {
char *p = sock_addr_get_str(&s->local); char *p;
memcpy(&p, s->local.data, sizeof(p));
return p == NULL || (p[0] == '@' && strlen(p) == 6 && return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
strspn(p+1, "0123456789abcdef") == 5); strspn(p+1, "0123456789abcdef") == 5);
} }
...@@ -1401,7 +1392,7 @@ void *parse_hostcond(char *addr, bool is_port) ...@@ -1401,7 +1392,7 @@ void *parse_hostcond(char *addr, bool is_port)
addr+=5; addr+=5;
p = strdup(addr); p = strdup(addr);
a.addr.bitlen = 8*strlen(p); a.addr.bitlen = 8*strlen(p);
sock_addr_set_str(&a.addr, &p); memcpy(a.addr.data, &p, sizeof(p));
fam = AF_UNIX; fam = AF_UNIX;
goto out; goto out;
} }
...@@ -2508,11 +2499,9 @@ static void unix_list_free(struct sockstat *list) ...@@ -2508,11 +2499,9 @@ static void unix_list_free(struct sockstat *list)
{ {
while (list) { while (list) {
struct sockstat *s = list; struct sockstat *s = list;
char *name = sock_addr_get_str(&s->local);
list = list->next; list = list->next;
free(s->name);
free(name);
free(s); free(s);
} }
} }
...@@ -2555,7 +2544,7 @@ static bool unix_use_proc(void) ...@@ -2555,7 +2544,7 @@ static bool unix_use_proc(void)
static void unix_stats_print(struct sockstat *list, struct filter *f) static void unix_stats_print(struct sockstat *list, struct filter *f)
{ {
struct sockstat *s; struct sockstat *s;
char *local, *peer; char *peer;
char *ctx_buf = NULL; char *ctx_buf = NULL;
bool use_proc = unix_use_proc(); bool use_proc = unix_use_proc();
char port_name[30] = {}; char port_name[30] = {};
...@@ -2566,8 +2555,9 @@ static void unix_stats_print(struct sockstat *list, struct filter *f) ...@@ -2566,8 +2555,9 @@ static void unix_stats_print(struct sockstat *list, struct filter *f)
if (unix_type_skip(s, f)) if (unix_type_skip(s, f))
continue; continue;
local = sock_addr_get_str(&s->local); peer = "*";
peer = "*"; if (s->peer_name)
peer = s->peer_name;
if (s->rport && use_proc) { if (s->rport && use_proc) {
struct sockstat *p; struct sockstat *p;
...@@ -2580,24 +2570,26 @@ static void unix_stats_print(struct sockstat *list, struct filter *f) ...@@ -2580,24 +2570,26 @@ static void unix_stats_print(struct sockstat *list, struct filter *f)
if (!p) { if (!p) {
peer = "?"; peer = "?";
} else { } else {
peer = sock_addr_get_str(&p->local); peer = p->name ? : "*";
peer = peer ? : "*";
} }
} }
if (use_proc && f->f) { if (use_proc && f->f) {
struct sockstat st;
st.local.family = AF_UNIX;
st.remote.family = AF_UNIX;
memcpy(st.local.data, &s->name, sizeof(s->name));
if (strcmp(peer, "*") == 0) if (strcmp(peer, "*") == 0)
memset(s->remote.data, 0, sizeof(char *)); memset(st.remote.data, 0, sizeof(peer));
else else
sock_addr_set_str(&s->remote, &peer); memcpy(st.remote.data, &peer, sizeof(peer));
if (run_ssfilter(f->f, &st) == 0)
if (run_ssfilter(f->f, s) == 0)
continue; continue;
} }
sock_state_print(s, unix_netid_name(s->type)); sock_state_print(s, unix_netid_name(s->type));
sock_addr_print(local ?: "*", " ", sock_addr_print(s->name ?: "*", " ",
int_to_str(s->lport, port_name), NULL); int_to_str(s->lport, port_name), NULL);
sock_addr_print(peer, " ", int_to_str(s->rport, port_name), sock_addr_print(peer, " ", int_to_str(s->rport, port_name),
NULL); NULL);
...@@ -2625,8 +2617,8 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, ...@@ -2625,8 +2617,8 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
struct filter *f = (struct filter *)arg; struct filter *f = (struct filter *)arg;
struct unix_diag_msg *r = NLMSG_DATA(nlh); struct unix_diag_msg *r = NLMSG_DATA(nlh);
struct rtattr *tb[UNIX_DIAG_MAX+1]; struct rtattr *tb[UNIX_DIAG_MAX+1];
char *name = NULL; char name[128];
struct sockstat stat = {}; struct sockstat stat = { .name = "*", .peer_name = "*" };
parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1), parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
...@@ -2647,12 +2639,12 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, ...@@ -2647,12 +2639,12 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
if (tb[UNIX_DIAG_NAME]) { if (tb[UNIX_DIAG_NAME]) {
int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]); int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
name = malloc(len + 1);
memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len); memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
name[len] = '\0'; name[len] = '\0';
if (name[0] == '\0') if (name[0] == '\0')
name[0] = '@'; name[0] = '@';
sock_addr_set_str(&stat.local, &name); stat.name = &name[0];
memcpy(stat.local.data, &stat.name, sizeof(stat.name));
} }
if (tb[UNIX_DIAG_PEER]) if (tb[UNIX_DIAG_PEER])
stat.rport = rta_getattr_u32(tb[UNIX_DIAG_PEER]); stat.rport = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
...@@ -2676,7 +2668,6 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, ...@@ -2676,7 +2668,6 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
if (show_mem || show_details) if (show_mem || show_details)
printf("\n"); printf("\n");
free(name);
return 0; return 0;
} }
...@@ -2745,6 +2736,8 @@ static int unix_show(struct filter *f) ...@@ -2745,6 +2736,8 @@ static int unix_show(struct filter *f)
if (!(u = malloc(sizeof(*u)))) if (!(u = malloc(sizeof(*u))))
break; break;
u->name = NULL;
u->peer_name = NULL;
if (sscanf(buf, "%x: %x %x %x %x %x %d %s", if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
&u->rport, &u->rq, &u->wq, &flags, &u->type, &u->rport, &u->rq, &u->wq, &flags, &u->type,
...@@ -2780,8 +2773,9 @@ static int unix_show(struct filter *f) ...@@ -2780,8 +2773,9 @@ static int unix_show(struct filter *f)
*insp = u; *insp = u;
if (name[0]) { if (name[0]) {
char *tmp = strdup(name); if ((u->name = malloc(strlen(name)+1)) == NULL)
sock_addr_set_str(&u->local, &tmp); break;
strcpy(u->name, name);
} }
if (++cnt > MAX_UNIX_REMEMBER) { if (++cnt > MAX_UNIX_REMEMBER) {
unix_stats_print(list, f); unix_stats_print(list, f);
......
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