linux: fix sscanf() overflows reading from /proc

Use `"%" PRIu64` and uint64_t for sscanf-ing large values, not `"%lu"`
and unsigned long. The latter can overflow when libuv is a 32 bits
application running on a 64 bits machine.

Fixes: https://github.com/libuv/libuv/issues/2297
PR-URL: https://github.com/libuv/libuv/pull/2305
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
Ben Noordhuis 2019-05-21 09:54:28 +02:00 committed by cjihrig
parent fddcd14825
commit d7f0055b80
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5

View File

@ -26,6 +26,7 @@
#include "uv.h"
#include "internal.h"
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@ -79,7 +80,7 @@ static int read_times(FILE* statfile_fp,
unsigned int numcpus,
uv_cpu_info_t* ci);
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
static unsigned long read_cpufreq(unsigned int cpunum);
static uint64_t read_cpufreq(unsigned int cpunum);
int uv__platform_loop_init(uv_loop_t* loop) {
@ -719,20 +720,20 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
static int read_times(FILE* statfile_fp,
unsigned int numcpus,
uv_cpu_info_t* ci) {
unsigned long clock_ticks;
struct uv_cpu_times_s ts;
unsigned long user;
unsigned long nice;
unsigned long sys;
unsigned long idle;
unsigned long dummy;
unsigned long irq;
unsigned int num;
unsigned int len;
uint64_t clock_ticks;
uint64_t user;
uint64_t nice;
uint64_t sys;
uint64_t idle;
uint64_t dummy;
uint64_t irq;
uint64_t num;
uint64_t len;
char buf[1024];
clock_ticks = sysconf(_SC_CLK_TCK);
assert(clock_ticks != (unsigned long) -1);
assert(clock_ticks != (uint64_t) -1);
assert(clock_ticks != 0);
rewind(statfile_fp);
@ -765,7 +766,8 @@ static int read_times(FILE* statfile_fp,
* fields, they're not allowed in C89 mode.
*/
if (6 != sscanf(buf + len,
"%lu %lu %lu %lu %lu %lu",
"%" PRIu64 " %" PRIu64 " %" PRIu64
"%" PRIu64 " %" PRIu64 " %" PRIu64,
&user,
&nice,
&sys,
@ -787,8 +789,8 @@ static int read_times(FILE* statfile_fp,
}
static unsigned long read_cpufreq(unsigned int cpunum) {
unsigned long val;
static uint64_t read_cpufreq(unsigned int cpunum) {
uint64_t val;
char buf[1024];
FILE* fp;
@ -801,7 +803,7 @@ static unsigned long read_cpufreq(unsigned int cpunum) {
if (fp == NULL)
return 0;
if (fscanf(fp, "%lu", &val) != 1)
if (fscanf(fp, "%" PRIu64, &val) != 1)
val = 0;
fclose(fp);
@ -942,7 +944,7 @@ void uv__set_process_title(const char* title) {
static uint64_t uv__read_proc_meminfo(const char* what) {
unsigned long rc;
uint64_t rc;
ssize_t n;
char* p;
int fd;
@ -967,7 +969,7 @@ static uint64_t uv__read_proc_meminfo(const char* what) {
p += strlen(what);
if (1 != sscanf(p, "%lu kB", &rc))
if (1 != sscanf(p, "%" PRIu64 " kB", &rc))
goto out;
rc *= 1024;
@ -1032,7 +1034,7 @@ static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {
if (n > 0) {
buf[n] = '\0';
sscanf(buf, "%llu", &rc);
sscanf(buf, "%" PRIu64, &rc);
}
if (uv__close_nocheckstdio(fd))