libnetlink.c, ss.c: properly handle fread() errors
fread(3) returns size_t data type which is unsigned, thus check `if (fread(...) < 0)' is always false. To check if fread(3) has failed, user should check error indicator with ferror(3). This commit also changes read logic a little bit by being less forgiving for errors. Previous logic was checking if fread(3) read *at least* required ammount of data, now code checks if fread(3) read *exactly* expected ammount of data. This makes sense because code parses very specific binary file, and reading even 1 less/more byte than expected, will later corrupt data anyway. Signed-off-by: Michał Łyszczek <michal.lyszczek@bofc.pl> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
parent
cb83101626
commit
eca5123948
|
|
@ -1174,7 +1174,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
|
||||||
int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
|
int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
|
||||||
void *jarg)
|
void *jarg)
|
||||||
{
|
{
|
||||||
int status;
|
size_t status;
|
||||||
char buf[16384];
|
char buf[16384];
|
||||||
struct nlmsghdr *h = (struct nlmsghdr *)buf;
|
struct nlmsghdr *h = (struct nlmsghdr *)buf;
|
||||||
|
|
||||||
|
|
@ -1184,14 +1184,15 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
|
||||||
|
|
||||||
status = fread(&buf, 1, sizeof(*h), rtnl);
|
status = fread(&buf, 1, sizeof(*h), rtnl);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status == 0 && feof(rtnl))
|
||||||
if (errno == EINTR)
|
return 0;
|
||||||
continue;
|
if (status != sizeof(*h)) {
|
||||||
perror("rtnl_from_file: fread");
|
if (ferror(rtnl))
|
||||||
|
perror("rtnl_from_file: fread");
|
||||||
|
if (feof(rtnl))
|
||||||
|
fprintf(stderr, "rtnl-from_file: truncated message\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (status == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
len = h->nlmsg_len;
|
len = h->nlmsg_len;
|
||||||
l = len - sizeof(*h);
|
l = len - sizeof(*h);
|
||||||
|
|
@ -1204,12 +1205,11 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
|
||||||
|
|
||||||
status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
|
status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status != NLMSG_ALIGN(l)) {
|
||||||
perror("rtnl_from_file: fread");
|
if (ferror(rtnl))
|
||||||
return -1;
|
perror("rtnl_from_file: fread");
|
||||||
}
|
if (feof(rtnl))
|
||||||
if (status < l) {
|
fprintf(stderr, "rtnl-from_file: truncated message\n");
|
||||||
fprintf(stderr, "rtnl-from_file: truncated message\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
26
misc/ss.c
26
misc/ss.c
|
|
@ -3329,28 +3329,28 @@ static int tcp_show_netlink_file(struct filter *f)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int status, err2;
|
int err2;
|
||||||
|
size_t status, nitems;
|
||||||
struct nlmsghdr *h = (struct nlmsghdr *)buf;
|
struct nlmsghdr *h = (struct nlmsghdr *)buf;
|
||||||
struct sockstat s = {};
|
struct sockstat s = {};
|
||||||
|
|
||||||
status = fread(buf, 1, sizeof(*h), fp);
|
status = fread(buf, 1, sizeof(*h), fp);
|
||||||
if (status < 0) {
|
|
||||||
perror("Reading header from $TCPDIAG_FILE");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (status != sizeof(*h)) {
|
if (status != sizeof(*h)) {
|
||||||
perror("Unexpected EOF reading $TCPDIAG_FILE");
|
if (ferror(fp))
|
||||||
|
perror("Reading header from $TCPDIAG_FILE");
|
||||||
|
if (feof(fp))
|
||||||
|
fprintf(stderr, "Unexpected EOF reading $TCPDIAG_FILE");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = fread(h+1, 1, NLMSG_ALIGN(h->nlmsg_len-sizeof(*h)), fp);
|
nitems = NLMSG_ALIGN(h->nlmsg_len - sizeof(*h));
|
||||||
|
status = fread(h+1, 1, nitems, fp);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status != nitems) {
|
||||||
perror("Reading $TCPDIAG_FILE");
|
if (ferror(fp))
|
||||||
break;
|
perror("Reading $TCPDIAG_FILE");
|
||||||
}
|
if (feof(fp))
|
||||||
if (status + sizeof(*h) < h->nlmsg_len) {
|
fprintf(stderr, "Unexpected EOF reading $TCPDIAG_FILE");
|
||||||
perror("Unexpected EOF reading $TCPDIAG_FILE");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue