File sysstat-12.0.2-CVE-2018-19416-and-CVE-2018-19517.patch of Package sysstat.9580
From fbc691eaaa10d0bcea6741d5a223dc3906106548 Mon Sep 17 00:00:00 2001
From: Sebastien GODARD <sysstat@users.noreply.github.com>
Date: Mon, 26 Nov 2018 14:32:05 +0100
Subject: [PATCH] Fix #196 and #199: Out of bound reads security issues
Check args before calling memmove() and memset() in remap_struct()
function to avoid out of bound reads which would possibly lead to
unknown code execution and/or sadf command crash.
Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
---
sa.h | 5 ++--
sa_common.c | 66 ++++++++++++++++++++++++++++++++++++-----------------
sadf.c | 2 +-
sar.c | 13 ++++++-----
4 files changed, 56 insertions(+), 30 deletions(-)
Index: sysstat-12.0.2/sa.h
===================================================================
--- sysstat-12.0.2.orig/sa.h
+++ sysstat-12.0.2/sa.h
@@ -1355,11 +1355,11 @@ void read_file_stat_bunch
__nr_t read_nr_value
(int, char *, struct file_magic *, int, int, int);
int read_record_hdr
- (int, void *, struct record_header *, struct file_header *, int, int);
+ (int, void *, struct record_header *, struct file_header *, int, int, size_t);
void reallocate_all_buffers
(struct activity *, __nr_t);
void remap_struct
- (unsigned int [], unsigned int [], void *, unsigned int, unsigned int);
+ (unsigned int [], unsigned int [], void *, unsigned int, unsigned int, size_t);
void replace_nonprintable_char
(int, char *);
int sa_fread
Index: sysstat-12.0.2/sa_common.c
===================================================================
--- sysstat-12.0.2.orig/sa_common.c
+++ sysstat-12.0.2/sa_common.c
@@ -1280,12 +1280,14 @@ void swap_struct(unsigned int types_nr[]
* @f_size Size of the structure containing statistics. This is the
* size of the structure *read from file*.
* @g_size Size of the structure expected by current sysstat version.
+ * @b_size Size of the buffer pointed by @ps.
***************************************************************************
*/
void remap_struct(unsigned int gtypes_nr[], unsigned int ftypes_nr[],
- void *ps, unsigned int f_size, unsigned int g_size)
+ void *ps, unsigned int f_size, unsigned int g_size, size_t b_size)
{
int d;
+ size_t n;
/* Sanity check */
if (MAP_SIZE(ftypes_nr) > f_size)
@@ -1294,10 +1296,14 @@ void remap_struct(unsigned int gtypes_nr
/* Remap [unsigned] long fields */
d = gtypes_nr[0] - ftypes_nr[0];
if (d) {
+ n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
+ g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH);
+ if ((ftypes_nr[0] * ULL_ALIGNMENT_WIDTH >= b_size) ||
+ (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size) ||
+ (ftypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size))
+ return;
memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH,
- ((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
- MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
- g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH));
+ ((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH, n);
if (d > 0) {
memset(((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
0, d * ULL_ALIGNMENT_WIDTH);
@@ -1306,14 +1312,21 @@ void remap_struct(unsigned int gtypes_nr
/* Remap [unsigned] int fields */
d = gtypes_nr[1] - ftypes_nr[1];
if (d) {
+ n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ - ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
+ g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ - gtypes_nr[1] * UL_ALIGNMENT_WIDTH);
+ if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
+ ftypes_nr[1] * UL_ALIGNMENT_WIDTH >= b_size) ||
+ (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size) ||
+ (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
+ ftypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size))
+ return;
memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH,
((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
- + ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
- MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
- - ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
- g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
- - gtypes_nr[1] * UL_ALIGNMENT_WIDTH));
+ + ftypes_nr[1] * UL_ALIGNMENT_WIDTH, n);
if (d > 0) {
memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
@@ -1323,18 +1336,28 @@ void remap_struct(unsigned int gtypes_nr
/* Remap possible fields (like strings of chars) following int fields */
d = gtypes_nr[2] - ftypes_nr[2];
if (d) {
+ n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ - ftypes_nr[1] * UL_ALIGNMENT_WIDTH
+ - ftypes_nr[2] * U_ALIGNMENT_WIDTH,
+ g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ - gtypes_nr[1] * UL_ALIGNMENT_WIDTH
+ - gtypes_nr[2] * U_ALIGNMENT_WIDTH);
+ if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
+ ftypes_nr[2] * U_ALIGNMENT_WIDTH >= b_size) ||
+ (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
+ gtypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size) ||
+ (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
+ ftypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size))
+ return;
memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH
+ gtypes_nr[2] * U_ALIGNMENT_WIDTH,
((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH
- + ftypes_nr[2] * U_ALIGNMENT_WIDTH,
- MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
- - ftypes_nr[1] * UL_ALIGNMENT_WIDTH
- - ftypes_nr[2] * U_ALIGNMENT_WIDTH,
- g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
- - gtypes_nr[1] * UL_ALIGNMENT_WIDTH
- - gtypes_nr[2] * U_ALIGNMENT_WIDTH));
+ + ftypes_nr[2] * U_ALIGNMENT_WIDTH, n);
if (d > 0) {
memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
+ gtypes_nr[1] * UL_ALIGNMENT_WIDTH
@@ -1396,6 +1419,7 @@ int sa_fread(int ifd, void *buffer, size
* @endian_mismatch
* TRUE if data read from file don't match current machine's
* endianness.
+ * @b_size @buffer size.
*
* OUT:
* @record_hdr Record header for current sample.
@@ -1405,7 +1429,8 @@ int sa_fread(int ifd, void *buffer, size
***************************************************************************
*/
int read_record_hdr(int ifd, void *buffer, struct record_header *record_hdr,
- struct file_header *file_hdr, int arch_64, int endian_mismatch)
+ struct file_header *file_hdr, int arch_64, int endian_mismatch,
+ size_t b_size)
{
if (sa_fread(ifd, buffer, (size_t) file_hdr->rec_size, SOFT_SIZE))
/* End of sa data file */
@@ -1413,7 +1438,7 @@ int read_record_hdr(int ifd, void *buffe
/* Remap record header structure to that expected by current version */
remap_struct(rec_types_nr, file_hdr->rec_types_nr, buffer,
- file_hdr->rec_size, RECORD_HEADER_SIZE);
+ file_hdr->rec_size, RECORD_HEADER_SIZE, b_size);
memcpy(record_hdr, buffer, RECORD_HEADER_SIZE);
/* Normalize endianness */
@@ -1622,7 +1647,7 @@ void read_file_stat_bunch(struct activit
for (j = 0; j < (nr_value * act[p]->nr2); j++) {
remap_struct(act[p]->gtypes_nr, act[p]->ftypes_nr,
(char *) act[p]->buf[curr] + j * act[p]->msize,
- act[p]->fsize, act[p]->msize);
+ act[p]->fsize, act[p]->msize, act[p]->msize);
}
}
}
@@ -1804,7 +1829,7 @@ void check_file_actlst(int *ifd, char *d
* then copy its contents to the expected structure.
*/
remap_struct(hdr_types_nr, file_magic->hdr_types_nr, buffer,
- file_magic->header_size, FILE_HEADER_SIZE);
+ file_magic->header_size, FILE_HEADER_SIZE, file_magic->header_size);
memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
free(buffer);
buffer = NULL;
@@ -1853,7 +1878,7 @@ void check_file_actlst(int *ifd, char *d
* then copy its contents to the expected structure.
*/
remap_struct(act_types_nr, file_hdr->act_types_nr, buffer,
- file_hdr->act_size, FILE_ACTIVITY_SIZE);
+ file_hdr->act_size, FILE_ACTIVITY_SIZE, file_hdr->act_size);
memcpy(fal, buffer, FILE_ACTIVITY_SIZE);
/* Normalize endianness for file_activity structures */
Index: sysstat-12.0.2/sadf.c
===================================================================
--- sysstat-12.0.2.orig/sadf.c
+++ sysstat-12.0.2/sadf.c
@@ -232,7 +232,7 @@ int read_next_sample(int ifd, int action
/* Read current record */
if (read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr], &file_hdr,
- arch_64, endian_mismatch))
+ arch_64, endian_mismatch, sizeof(rec_hdr_tmp)))
/* End of sa file */
return TRUE;
Index: sysstat-12.0.2/sar.c
===================================================================
--- sysstat-12.0.2.orig/sar.c
+++ sysstat-12.0.2/sar.c
@@ -727,6 +727,7 @@ void read_sadc_stat_bunch(int curr)
* @endian_mismatch
* TRUE if file's data don't match current machine's endianness.
* @arch_64 TRUE if file's data come from a 64 bit machine.
+ * @b_size Size of @rec_hdr_tmp buffer.
*
* OUT:
* @curr Index in array for next sample statistics.
@@ -740,7 +741,7 @@ void handle_curr_act_stats(int ifd, off_
int rows, unsigned int act_id, int *reset,
struct file_activity *file_actlst, char *file,
struct file_magic *file_magic, void *rec_hdr_tmp,
- int endian_mismatch, int arch_64)
+ int endian_mismatch, int arch_64, size_t b_size)
{
int p, reset_cd;
unsigned long lines = 0;
@@ -774,7 +775,7 @@ void handle_curr_act_stats(int ifd, off_
* Start with reading current sample's record header.
*/
*eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[*curr],
- &file_hdr, arch_64, endian_mismatch);
+ &file_hdr, arch_64, endian_mismatch, b_size);
rtype = record_hdr[*curr].record_type;
if (!*eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
@@ -1003,7 +1004,7 @@ void read_stats_from_file(char from_file
*/
do {
if (read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[0], &file_hdr,
- arch_64, endian_mismatch)) {
+ arch_64, endian_mismatch, sizeof(rec_hdr_tmp))) {
/* End of sa data file */
return;
}
@@ -1069,7 +1070,7 @@ void read_stats_from_file(char from_file
handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
act[p]->id, &reset, file_actlst,
from_file, &file_magic, rec_hdr_tmp,
- endian_mismatch, arch_64);
+ endian_mismatch, arch_64, sizeof(rec_hdr_tmp));
}
else {
unsigned int optf, msk;
@@ -1083,7 +1084,7 @@ void read_stats_from_file(char from_file
handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
rows, act[p]->id, &reset, file_actlst,
from_file, &file_magic, rec_hdr_tmp,
- endian_mismatch, arch_64);
+ endian_mismatch, arch_64, sizeof(rec_hdr_tmp));
act[p]->opt_flags = optf;
}
}
@@ -1095,7 +1096,7 @@ void read_stats_from_file(char from_file
do {
/* Read next record header */
eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr],
- &file_hdr, arch_64, endian_mismatch);
+ &file_hdr, arch_64, endian_mismatch, sizeof(rec_hdr_tmp));
rtype = record_hdr[curr].record_type;
if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {