From dbfaab61647893fc0b1f4ae9b15e857dcdcb8337 Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Sat, 28 May 2022 18:47:09 +0200 Subject: [PATCH] Fix uid resolution failing after some time with root Since the indroduction of netlink-based UID resolution in a626e11, UID resolution will break after some time due to netlink sequence number mismatches. This fix recovers from off-by-one sequence number mismathes and falls-back to slower UID resolution if some other netlink error occurs --- app/src/main/jni/pcapd/nl_utils.c | 29 +++++++++++++++++++++-------- app/src/main/jni/pcapd/pcapd.c | 13 +++++++++++-- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/app/src/main/jni/pcapd/nl_utils.c b/app/src/main/jni/pcapd/nl_utils.c index 823f8bee..d68adfb7 100644 --- a/app/src/main/jni/pcapd/nl_utils.c +++ b/app/src/main/jni/pcapd/nl_utils.c @@ -29,6 +29,7 @@ #include #include "nl_utils.h" #include "common/uid_resolver.h" +#include "common/utils.h" int nl_route_socket(uint32_t groups) { struct sockaddr_nl snl; @@ -165,6 +166,7 @@ static int diag_uid_lookup(int nlsock, int family, int ipproto, u_char buf[512]; static int seq = 0; ssize_t rv; + uint8_t do_retry = 1; struct nlmsghdr *nmsg = (struct nlmsghdr*) buf; struct inet_diag_req_v2 *req = (struct inet_diag_req_v2*) (nmsg + 1); @@ -208,17 +210,28 @@ static int diag_uid_lookup(int nlsock, int family, int ipproto, iov.iov_base = buf; iov.iov_len = sizeof(buf); +retry: // Recv reply if((rv = recvmsg(nlsock, &msg, 0)) <= 0) return -3; // NOTE: nmsg points to buf - if(nmsg->nlmsg_len < (int)sizeof(*nmsg) || nmsg->nlmsg_len > rv || - nmsg->nlmsg_seq != seq) { + if(nmsg->nlmsg_len < (int)sizeof(*nmsg) || nmsg->nlmsg_len > rv) { errno = EINVAL; return -4; } + if(nmsg->nlmsg_seq != seq) { + if(do_retry && (nmsg->nlmsg_seq == (seq - 1))) { + do_retry = 0; + goto retry; // this issue is recoverable, retry once + } + + log_e("out of sequence: %d/%d", nmsg->nlmsg_seq, seq); + errno = EINVAL; + return -5; + } + if(nmsg->nlmsg_type == NLMSG_ERROR) { const struct nlmsgerr *err = NLMSG_DATA(nmsg); @@ -229,7 +242,7 @@ static int diag_uid_lookup(int nlsock, int family, int ipproto, } else errno = EINVAL; - return -5; + return -6; } if(nmsg->nlmsg_type == NLMSG_DONE) @@ -237,7 +250,7 @@ static int diag_uid_lookup(int nlsock, int family, int ipproto, if(nmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct inet_diag_msg))) { errno = EINVAL; - return -6; + return -7; } struct inet_diag_msg *diag_msg = (struct inet_diag_msg*) NLMSG_DATA(nmsg); @@ -280,13 +293,13 @@ int nl_get_uid(int nlsock, const zdtun_5tuple_t *tuple) { const pd_sockaddr_t *remote = (ipproto == IPPROTO_UDP) ? &src : &dst; uid = diag_uid_lookup(nlsock, family, ipproto, local, remote, NLM_F_REQUEST); - if(uid >= 0) + if((uid >= 0) || (uid != UID_UNKNOWN)) return uid; // Search for IPv4-mapped IPv6 addresses if(family == AF_INET) { uid = diag_uid_lookup(nlsock, AF_INET6, ipproto, local, remote, NLM_F_REQUEST); - if(uid >= 0) + if((uid >= 0) || (uid != UID_UNKNOWN)) return uid; } @@ -296,13 +309,13 @@ int nl_get_uid(int nlsock, const zdtun_5tuple_t *tuple) { pd_sockaddr_t wildcard = {0}; uid = diag_uid_lookup(nlsock, family, ipproto, &src, &wildcard, NLM_F_REQUEST | NLM_F_DUMP); - if(uid >= 0) + if((uid >= 0) || (uid != UID_UNKNOWN)) return uid; // Search for IPv4-mapped IPv6 addresses if(family == AF_INET) { uid = diag_uid_lookup(nlsock, AF_INET6, ipproto, &src, &wildcard, NLM_F_REQUEST | NLM_F_DUMP); - if(uid >= 0) + if((uid >= 0) || (uid != UID_UNKNOWN)) return uid; } } diff --git a/app/src/main/jni/pcapd/pcapd.c b/app/src/main/jni/pcapd/pcapd.c index 8b8db981..06411c8f 100644 --- a/app/src/main/jni/pcapd/pcapd.c +++ b/app/src/main/jni/pcapd/pcapd.c @@ -752,10 +752,19 @@ static int read_pkt(pcapd_runtime_t *rt, pcapd_iface_t *iface, time_t now) { uid = uid_lru_find(rt->lru, &zpkt.tuple); if(uid == -2) { - if((rt->nldiag_sock > 0) && (zpkt.tuple.ipproto != IPPROTO_ICMP)) + if((rt->nldiag_sock > 0) && (zpkt.tuple.ipproto != IPPROTO_ICMP)) { // retrieve via netlink uid = nl_get_uid(rt->nldiag_sock, &zpkt.tuple); - else + + if((uid < 0) && (uid != UID_UNKNOWN)) { + log_e("nl_get_uid failed with error %d [%d]: %s", uid, errno, strerror(errno)); + close(rt->nldiag_sock); + rt->nldiag_sock = -1; + + // fallback to slow method + uid = get_uid(rt->resolver, &zpkt.tuple); + } + } else // slow method uid = get_uid(rt->resolver, &zpkt.tuple);