diff --git a/SOURCES/0001-epson2-Rewrite-network-I-O.patch b/SOURCES/0001-epson2-Rewrite-network-I-O.patch new file mode 100644 index 0000000..cb49af9 --- /dev/null +++ b/SOURCES/0001-epson2-Rewrite-network-I-O.patch @@ -0,0 +1,225 @@ +diff -up sane-backends-1.0.27/backend/epson2_net.c.epsonds-issues sane-backends-1.0.27/backend/epson2_net.c +--- sane-backends-1.0.27/backend/epson2_net.c.epsonds-issues 2016-10-06 02:02:57.000000000 +0200 ++++ sane-backends-1.0.27/backend/epson2_net.c 2020-07-28 15:04:58.385405722 +0200 +@@ -32,11 +32,12 @@ + + #include "sane/sanei_debug.h" + +-static int ++static ssize_t + sanei_epson_net_read_raw(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, + SANE_Status *status) + { +- int ready, read = -1; ++ int ready; ++ ssize_t read = -1; + fd_set readable; + struct timeval tv; + +@@ -62,111 +63,136 @@ sanei_epson_net_read_raw(Epson_Scanner * + return read; + } + +-int +-sanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, ++static ssize_t ++sanei_epson_net_read_buf(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, + SANE_Status * status) + { +- ssize_t size; + ssize_t read = 0; +- unsigned char header[12]; + +- /* read from buffer, if available */ +- if (s->netptr != s->netbuf) { +- DBG(23, "reading %lu from buffer at %p, %lu available\n", +- (u_long) wanted, s->netptr, (u_long) s->netlen); ++ DBG(23, "%s: reading up to %lu from buffer at %p, %lu available\n", ++ __func__, (u_long) wanted, s->netptr, (u_long) s->netlen); + +- memcpy(buf, s->netptr, wanted); +- read = wanted; ++ if ((size_t) wanted > s->netlen) { ++ *status = SANE_STATUS_IO_ERROR; ++ wanted = s->netlen; ++ } + +- s->netlen -= wanted; ++ memcpy(buf, s->netptr, wanted); ++ read = wanted; + +- if (s->netlen == 0) { +- DBG(23, "%s: freeing %p\n", __func__, s->netbuf); +- free(s->netbuf); +- s->netbuf = s->netptr = NULL; +- s->netlen = 0; +- } ++ s->netptr += read; ++ s->netlen -= read; + +- return read; ++ if (s->netlen == 0) { ++ DBG(23, "%s: freeing %p\n", __func__, s->netbuf); ++ free(s->netbuf); ++ s->netbuf = s->netptr = NULL; ++ s->netlen = 0; ++ } ++ ++ return read; ++} ++ ++ssize_t ++sanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, ++ SANE_Status * status) ++{ ++ if (wanted < 0) { ++ *status = SANE_STATUS_INVAL; ++ return 0; ++ } ++ ++ size_t size; ++ ssize_t read = 0; ++ unsigned char header[12]; ++ ++ /* read from remainder of buffer */ ++ if (s->netptr) { ++ return sanei_epson_net_read_buf(s, buf, wanted, status); + } + + /* receive net header */ +- size = sanei_epson_net_read_raw(s, header, 12, status); +- if (size != 12) { ++ read = sanei_epson_net_read_raw(s, header, 12, status); ++ if (read != 12) { + return 0; + } + ++ /* validate header */ + if (header[0] != 'I' || header[1] != 'S') { + DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]); + *status = SANE_STATUS_IO_ERROR; + return 0; + } + ++ /* parse payload size */ + size = be32atoh(&header[6]); + +- DBG(23, "%s: wanted = %lu, available = %lu\n", __func__, +- (u_long) wanted, (u_long) size); +- + *status = SANE_STATUS_GOOD; + +- if (size == wanted) { +- +- DBG(15, "%s: full read\n", __func__); ++ if (!s->netbuf) { ++ DBG(15, "%s: direct read\n", __func__); ++ DBG(23, "%s: wanted = %lu, available = %lu\n", __func__, ++ (u_long) wanted, (u_long) size); + +- read = sanei_epson_net_read_raw(s, buf, size, status); +- +- if (s->netbuf) { +- free(s->netbuf); +- s->netbuf = NULL; +- s->netlen = 0; ++ if ((size_t) wanted > size) { ++ wanted = size; + } + +- if (read < 0) { +- return 0; +- } +- +-/* } else if (wanted < size && s->netlen == size) { */ ++ read = sanei_epson_net_read_raw(s, buf, wanted, status); + } else { +- DBG(23, "%s: partial read\n", __func__); ++ DBG(15, "%s: buffered read\n", __func__); ++ DBG(23, "%s: bufferable = %lu, available = %lu\n", __func__, ++ (u_long) s->netlen, (u_long) size); + +- read = sanei_epson_net_read_raw(s, s->netbuf, size, status); +- if (read != size) { +- return 0; ++ if (s->netlen > size) { ++ s->netlen = size; + } + +- s->netlen = size - wanted; +- s->netptr += wanted; +- read = wanted; +- +- DBG(23, "0,4 %02x %02x\n", s->netbuf[0], s->netbuf[4]); +- DBG(23, "storing %lu to buffer at %p, next read at %p, %lu bytes left\n", +- (u_long) size, s->netbuf, s->netptr, (u_long) s->netlen); ++ /* fill buffer */ ++ read = sanei_epson_net_read_raw(s, s->netbuf, s->netlen, status); ++ s->netptr = s->netbuf; ++ s->netlen = (read > 0 ? read : 0); + +- memcpy(buf, s->netbuf, wanted); ++ /* copy wanted part */ ++ read = sanei_epson_net_read_buf(s, buf, wanted, status); + } + + return read; + } + +- +-int ++size_t + sanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *buf, + size_t buf_size, size_t reply_len, SANE_Status *status) + { + unsigned char *h1, *h2, *payload; + unsigned char *packet = malloc(12 + 8 + buf_size); + +- /* XXX check allocation failure */ ++ if (!packet) { ++ *status = SANE_STATUS_NO_MEM; ++ return 0; ++ } + + h1 = packet; + h2 = packet + 12; + payload = packet + 12 + 8; + + if (reply_len) { +- s->netbuf = s->netptr = malloc(reply_len); ++ if (s->netbuf) { ++ DBG(23, "%s, freeing %p, %ld bytes unprocessed\n", ++ __func__, s->netbuf, (u_long) s->netlen); ++ free(s->netbuf); ++ s->netbuf = s->netptr = NULL; ++ s->netlen = 0; ++ } ++ s->netbuf = malloc(reply_len); ++ if (!s->netbuf) { ++ free(packet); ++ *status = SANE_STATUS_NO_MEM; ++ return 0; ++ } + s->netlen = reply_len; +- DBG(24, "allocated %lu bytes at %p\n", +- (u_long) reply_len, s->netbuf); ++ DBG(24, "%s: allocated %lu bytes at %p\n", __func__, ++ (u_long) s->netlen, s->netbuf); + } + + DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n", +diff -up sane-backends-1.0.27/backend/epson2_net.h.epsonds-issues sane-backends-1.0.27/backend/epson2_net.h +--- sane-backends-1.0.27/backend/epson2_net.h.epsonds-issues 2016-10-06 02:02:57.000000000 +0200 ++++ sane-backends-1.0.27/backend/epson2_net.h 2020-07-28 14:51:59.666593530 +0200 +@@ -4,9 +4,9 @@ + #include + #include "../include/sane/sane.h" + +-extern int sanei_epson_net_read(struct Epson_Scanner *s, unsigned char *buf, ssize_t buf_size, ++extern ssize_t sanei_epson_net_read(struct Epson_Scanner *s, unsigned char *buf, ssize_t buf_size, + SANE_Status *status); +-extern int sanei_epson_net_write(struct Epson_Scanner *s, unsigned int cmd, const unsigned char *buf, ++extern size_t sanei_epson_net_write(struct Epson_Scanner *s, unsigned int cmd, const unsigned char *buf, + size_t buf_size, size_t reply_len, + SANE_Status *status); + extern SANE_Status sanei_epson_net_lock(struct Epson_Scanner *s); diff --git a/SOURCES/0001-epsonds-Prevent-possible-buffer-overflow-when-readin.patch b/SOURCES/0001-epsonds-Prevent-possible-buffer-overflow-when-readin.patch new file mode 100644 index 0000000..9f74c38 --- /dev/null +++ b/SOURCES/0001-epsonds-Prevent-possible-buffer-overflow-when-readin.patch @@ -0,0 +1,72 @@ +From b9b0173409df73e235da2aa0dae5edd21fb55967 Mon Sep 17 00:00:00 2001 +From: Olaf Meeuwissen +Date: Mon, 27 Apr 2020 18:48:29 +0900 +Subject: [PATCH] epsonds: Prevent possible buffer overflow when reading image + data + +Addresses GHSL-2020-084, re #279. +--- + backend/epsonds-cmd.c | 5 +++++ + backend/epsonds.c | 12 +++++++----- + backend/epsonds.h | 1 + + 3 files changed, 13 insertions(+), 5 deletions(-) + +diff --git a/backend/epsonds-cmd.c b/backend/epsonds-cmd.c +index 9a4db3080..c182aa51a 100644 +--- a/backend/epsonds-cmd.c ++++ b/backend/epsonds-cmd.c +@@ -876,6 +876,11 @@ esci2_img(struct epsonds_scanner *s, SANE_Int *length) + return parse_status; + } + ++ /* more data than was accounted for in s->buf */ ++ if (more > s->bsz) { ++ return SANE_STATUS_IO_ERROR; ++ } ++ + /* ALWAYS read image data */ + if (s->hw->connection == SANE_EPSONDS_NET) { + epsonds_net_request_read(s, more); +diff --git a/backend/epsonds.c b/backend/epsonds.c +index ff5d68106..fb9694a88 100644 +--- a/backend/epsonds.c ++++ b/backend/epsonds.c +@@ -1230,16 +1230,18 @@ sane_start(SANE_Handle handle) + if (s->line_buffer == NULL) + return SANE_STATUS_NO_MEM; + +- /* ring buffer for front page, twice bsz */ ++ /* transfer buffer size, bsz */ + /* XXX read value from scanner */ +- status = eds_ring_init(&s->front, (65536 * 4) * 2); ++ s->bsz = (65536 * 4); ++ ++ /* ring buffer for front page */ ++ status = eds_ring_init(&s->front, s->bsz * 2); + if (status != SANE_STATUS_GOOD) { + return status; + } + +- /* transfer buffer, bsz */ +- /* XXX read value from scanner */ +- s->buf = realloc(s->buf, 65536 * 4); ++ /* transfer buffer */ ++ s->buf = realloc(s->buf, s->bsz); + if (s->buf == NULL) + return SANE_STATUS_NO_MEM; + +diff --git a/backend/epsonds.h b/backend/epsonds.h +index 0427ef3b4..401b0f32c 100644 +--- a/backend/epsonds.h ++++ b/backend/epsonds.h +@@ -160,6 +160,7 @@ struct epsonds_scanner + Option_Value val[NUM_OPTIONS]; + SANE_Parameters params; + ++ size_t bsz; /* transfer buffer size */ + SANE_Byte *buf, *line_buffer; + ring_buffer *current, front, back; + +-- +2.25.4 + diff --git a/SPECS/sane-backends.spec b/SPECS/sane-backends.spec index 259f081..b826b14 100644 --- a/SPECS/sane-backends.spec +++ b/SPECS/sane-backends.spec @@ -33,7 +33,7 @@ Summary: Scanner access software Name: sane-backends Version: 1.0.27 -Release: 19%{?dist} +Release: 22%{?dist} # lib/ is LGPLv2+, backends are GPLv2+ with exceptions # Tools are GPLv2+, docs are public domain # see LICENSE for details @@ -59,6 +59,10 @@ Patch3: sane-backends-saned-manpage.patch Patch4: sane-backends-canon-lide-100.patch # Revert samsung patch from upstream (upstream tracker https://alioth.debian.org/tracker/index.php?func=detail&aid=315876&group_id=30186&atid=410366) Patch5: sane-backends-revert-samsung-patch.patch +# 1852468, 1852467, 1852466, 1852465 - prevent buffer overflow in esci2_img +Patch6: 0001-epsonds-Prevent-possible-buffer-overflow-when-readin.patch +# 1852663, 1848097 - NULL pointer dereference in sanei_epson_net_read function +Patch7: 0001-epson2-Rewrite-network-I-O.patch URL: http://www.sane-project.org @@ -90,6 +94,10 @@ Obsoletes: sane-backends < 1.0.25-3 Conflicts: sane-backends < 1.0.25-3 %endif +# fix for 1852668, 1852667, 1852666, 1852665 - autodiscovery is not supported in epsonds +# backend, so disable it during post scriptlet (grep and sed are needed for the scriptlet) +Requires: grep, sed + %description Scanner Access Now Easy (SANE) is a universal scanner interface. The SANE application programming interface (API) provides standardized @@ -194,6 +202,8 @@ access image acquisition devices available on the local host. %patch3 -p1 -b .saned-manpage %patch4 -p1 -b .canon-lide-100 %patch5 -p1 -b .revert-samsung-patch +%patch6 -p1 -b .prevent-buffer-overflow +%patch7 -p1 -b .rework-epsonds-io %build CFLAGS="%optflags -fno-strict-aliasing" @@ -273,6 +283,14 @@ install -m 644 saned@.service %{buildroot}%{_unitdir} %post udevadm hwdb --update >/dev/null 2>&1 || : +# check if there is autodiscovery enabled in epsonds.conf +autodiscovery=`%{_bindir}/grep -E '^[[:space:]]*net[[:space:]]*autodiscovery' /etc/sane.d/epsonds.conf` +if [ -n "$autodiscovery" ] +then + # comment out 'net autodiscovery' if it is not commented out + %{_bindir}/sed -i 's,^[[:space:]]*net[[:space:]]*autodiscovery,#net autodiscovery,g' /etc/sane.d/epsonds.conf +fi + %postun udevadm hwdb --update >/dev/null 2>&1 || : @@ -355,6 +373,16 @@ exit 0 %{_unitdir}/saned@.service %changelog +* Tue Sep 08 2020 Zdenek Dohnal - 1.0.27-22 +- related 1852663 - needed to rebuild due infrastructure error + +* Thu Sep 03 2020 Zdenek Dohnal - 1.0.27-21 +- 1852663, 1848097 - NULL pointer dereference in sanei_epson_net_read function + +* Wed Jul 01 2020 Zdenek Dohnal - 1.0.27-20 +- 1852468, 1852467, 1852466, 1852465 - prevent buffer overflow in esci2_img +- 1852668, 1852667, 1852666, 1852665 - disable autodiscovery for epsonds backend + * Tue Jul 24 2018 Zdenek Dohnal - 1.0.27-19 - corrected license