File netatalk-CVE-2022-23121.patch of Package netatalk.26996
Index: netatalk-3.1.0/libatalk/adouble/ad_open.c
===================================================================
--- netatalk-3.1.0.orig/libatalk/adouble/ad_open.c 2013-10-28 14:43:14.000000000 +0100
+++ netatalk-3.1.0/libatalk/adouble/ad_open.c 2022-03-22 13:50:00.331317475 +0100
@@ -387,13 +387,13 @@ static int new_ad_header(struct adouble
return 0;
}
-/* -------------------------------------
- read in the entries
-*/
-static void parse_entries(struct adouble *ad, char *buf, uint16_t nentries)
+/**
+ * Read an AppleDouble buffer, returns 0 on success, -1 if an entry was malformatted
+ **/
+static int parse_entries(struct adouble *ad, uint16_t nentries, size_t valid_data_len)
{
uint32_t eid, len, off;
- int warning = 0;
+ uint8_t *buf = ad->ad_data + AD_HEADER_LEN;
/* now, read in the entry bits */
for (; nentries > 0; nentries-- ) {
@@ -407,17 +407,20 @@ static void parse_entries(struct adouble
len = ntohl( len );
buf += sizeof( len );
- if (eid
- && eid < ADEID_MAX
- && off < sizeof(ad->ad_data)
- && (off + len <= sizeof(ad->ad_data) || eid == ADEID_RFORK)) {
- ad->ad_eid[ eid ].ade_off = off;
- ad->ad_eid[ eid ].ade_len = len;
- } else if (!warning) {
- warning = 1;
- LOG(log_warning, logtype_ad, "parse_entries: bogus eid: %d", eid);
+ if (!eid
+ || eid > ADEID_MAX
+ || off >= valid_data_len
+ || ((eid != ADEID_RFORK) && (off + len > valid_data_len)))
+ {
+ LOG(log_warning, logtype_ad, "parse_entries: bogus eid: %u, off: %u, len: %u",
+ (uint)eid, (uint)off, (uint)len);
+ return -1;
}
+ ad->ad_eid[eid].ade_off = off;
+ ad->ad_eid[eid].ade_len = len;
}
+
+ return 0;
}
/* this reads enough of the header so that we can figure out all of
@@ -431,7 +434,6 @@ static int ad_header_read(const char *pa
{
char *buf = ad->ad_data;
uint16_t nentries;
- int len;
ssize_t header_len;
struct stat st;
@@ -457,25 +459,24 @@ static int ad_header_read(const char *pa
memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
nentries = ntohs( nentries );
+ if (nentries > 16) {
+ LOG(log_error, logtype_ad, "ad_open: too many entries: %"PRIu16, nentries);
+ errno = EIO;
+ return -1;
+ }
- /* read in all the entry headers. if we have more than the
- * maximum, just hope that the rfork is specified early on. */
- len = nentries*AD_ENTRY_LEN;
-
- if (len + AD_HEADER_LEN > sizeof(ad->ad_data))
- len = sizeof(ad->ad_data) - AD_HEADER_LEN;
-
- buf += AD_HEADER_LEN;
- if (len > header_len - AD_HEADER_LEN) {
- LOG(log_error, logtype_ad, "ad_header_read: can't read entry info.");
+ if ((nentries * AD_ENTRY_LEN) + AD_HEADER_LEN > header_len) {
+ LOG(log_error, logtype_ad, "ad_header_read: too many entries: %zd", header_len);
errno = EIO;
return -1;
}
- /* figure out all of the entry offsets and lengths. if we aren't
- * able to read a resource fork entry, bail. */
- nentries = len / AD_ENTRY_LEN;
- parse_entries(ad, buf, nentries);
+ if (parse_entries(ad, nentries, header_len) != 0) {
+ LOG(log_warning, logtype_ad, "ad_header_read(%s): malformed AppleDouble",
+ path ? fullpathname(path) : "");
+ errno = EIO;
+ return -1;
+ }
if (!ad_getentryoff(ad, ADEID_RFORK)
|| (ad_getentryoff(ad, ADEID_RFORK) > sizeof(ad->ad_data))
) {
@@ -555,7 +556,6 @@ static int ad_header_read_osx(const char
struct adouble adosx;
char *buf = &adosx.ad_data[0];
uint16_t nentries;
- int len;
ssize_t header_len;
struct stat st;
@@ -582,20 +582,24 @@ static int ad_header_read_osx(const char
memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
nentries = ntohs(nentries);
- len = nentries * AD_ENTRY_LEN;
-
- if (len + AD_HEADER_LEN > sizeof(adosx.ad_data))
- len = sizeof(adosx.ad_data) - AD_HEADER_LEN;
+ if (nentries > 16) {
+ LOG(log_error, logtype_ad, "ad_header_read_osx: too many entries: %"PRIu16, nentries);
+ errno = EIO;
+ return -1;
+ }
- buf += AD_HEADER_LEN;
- if (len > header_len - AD_HEADER_LEN) {
- LOG(log_error, logtype_ad, "ad_header_read_osx: can't read entry info.");
+ if ((nentries * AD_ENTRY_LEN) + AD_HEADER_LEN > header_len) {
+ LOG(log_error, logtype_ad, "ad_header_read_osx: too many entries: %zd", header_len);
errno = EIO;
return -1;
}
- nentries = len / AD_ENTRY_LEN;
- parse_entries(&adosx, buf, nentries);
+ if (parse_entries(&adosx, nentries, header_len) != 0) {
+ LOG(log_warning, logtype_ad, "ad_header_read(%s): malformed AppleDouble",
+ path ? fullpathname(path) : "");
+ errno = EIO;
+ EC_FAIL;
+ }
if (ad_getentryoff(&adosx, ADEID_RFORK) == 0
|| ad_getentryoff(&adosx, ADEID_RFORK) > sizeof(ad->ad_data)
@@ -662,7 +666,12 @@ static int ad_header_read_ea(const char
}
/* Now parse entries */
- parse_entries(ad, buf + AD_HEADER_LEN, nentries);
+ if (parse_entries(ad, nentries, header_len)) {
+ LOG(log_warning, logtype_ad, "ad_header_read(%s): malformed AppleDouble",
+ path ? fullpathname(path) : "");
+ errno = EINVAL;
+ EC_FAIL;
+ }
if (nentries != ADEID_NUM_EA
|| !ad_entry(ad, ADEID_FINDERI)