+ /*
+ * First we do some simple sanity checking.
+ * +) See if entry is within the buffer's range;
+ *
+ * +) Check the attribute name length; if it's longer than the
+ * maximum, we truncate it down. (We could error out as well;
+ * I'm not sure which is the better way to go here.)
+ *
+ * +) If, given the name length, it goes beyond the end of
+ * the buffer, error out.
+ *
+ * +) If the last byte isn't a NUL, make it a NUL. (Since we
+ * truncated the name length above, we truncate the name here.)
+ *
+ * +) If entry->offset is so large that it causes dataptr to
+ * go beyond the end of the buffer -- or, worse, so large that
+ * it wraps around! -- we error out.
+ *
+ * +) If entry->length would cause the entry to go beyond the
+ * end of the buffer (or, worse, wrap around to before it),
+ * *or* if the length is larger than the hdrsize, we error out.
+ * (An explanation of that: what we're checking for there is
+ * the small range of values such that offset+length would cause
+ * it to go beyond endptr, and then wrap around past buffer. We
+ * care about this because we are passing entry->length down to
+ * fgetxattr() below, and an erroneously large value could cause
+ * problems there. By making sure that it's less than hdrsize,
+ * which has already been sanity-checked above, we're safe.
+ * That may mean that the check against < buffer is unnecessary.)
+ */
+ if ((void*)entry >= endptr || (void*)entry < buffer) {
+ if (COPYFILE_VERBOSE & s->flags)
+ copyfile_warn("Incomplete or corrupt attribute entry");
+ error = -1;
+ goto exit;
+ }
+
+ if (((void*)entry + sizeof(*entry)) > endptr) {
+ if (COPYFILE_VERBOSE & s->flags)
+ copyfile_warn("Incomplete or corrupt attribute entry");
+ error = -1;
+ goto exit;
+ }
+
+ if (entry->namelen > ATTR_MAX_NAME_LEN) {
+ entry->namelen = ATTR_MAX_NAME_LEN;
+ }
+ if ((void*)(entry->name + entry->namelen) >= endptr) {
+ if (COPYFILE_VERBOSE & s->flags)
+ copyfile_warn("Incomplete or corrupt attribute entry");
+ error = -1;
+ goto exit;
+ }
+
+ if (entry->name[entry->namelen] != 0) {
+ entry->name[entry->namelen] = 0;
+ }
+
+ copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
+ entry->name, entry->length, entry->offset);
+
+ dataptr = (char *)attrhdr + entry->offset;
+
+ if (dataptr >= endptr || dataptr < buffer) {
+ copyfile_debug(1, "Entry %d overflows: offset = %u", entry->offset);
+ error = -1;
+ goto exit;
+ }
+ if ((dataptr + entry->length) > endptr ||
+ ((dataptr + entry->length) < buffer) ||
+ (entry->length > hdrsize)) {
+ if (COPYFILE_VERBOSE & s->flags)
+ copyfile_warn("Incomplete or corrupt attribute entry");
+ copyfile_debug(1, "Entry %d length overflows: dataptr = %u, offset = %u, length = %u, buffer = %u, endptr = %u",
+ i, dataptr, entry->offset, entry->length, buffer, endptr);
+ error = -1;
+ goto exit;
+ }
+
+ if (COPYFILE_ACL & s->flags && strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)