1
0
mirror of https://github.com/openbsd/src.git synced 2026-04-27 15:46:02 +00:00

sys/cd9660: fix altname underflow and validate RRIP entry lengths

Underflow was reported by Adam Crosser <adam.crosser@praetorian.com>

OK: kn@
This commit is contained in:
kirill
2026-03-19 22:26:50 +00:00
parent e289c8a40f
commit 1e53cfe3c7

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: cd9660_rrip.c,v 1.17 2023/03/08 04:43:08 guenther Exp $ */
/* $OpenBSD: cd9660_rrip.c,v 1.18 2026/03/19 22:26:50 kirill Exp $ */
/* $NetBSD: cd9660_rrip.c,v 1.17 1997/01/24 00:27:32 cgd Exp $ */
/*-
@@ -85,6 +85,9 @@ cd9660_rrip_attr(void *v, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_ATTR *p = v;
if (isonum_711(p->h.length) < sizeof(*p))
return (0);
ana->inop->inode.iso_mode = isonum_733(p->mode);
ana->inop->inode.iso_uid = isonum_733(p->uid);
ana->inop->inode.iso_gid = isonum_733(p->gid);
@@ -112,12 +115,16 @@ cd9660_rrip_slink(void *v, ISO_RRIP_ANALYZE *ana)
ISO_RRIP_SLINK *p = v;
ISO_RRIP_SLINK_COMPONENT *pcomp;
ISO_RRIP_SLINK_COMPONENT *pcompe;
u_int entrylen, clen;
int len, wlen, cont;
char *outbuf, *inbuf;
entrylen = isonum_711(p->h.length);
if (entrylen < sizeof(*p))
goto invalid;
pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
pcompe =
(ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
(ISO_RRIP_SLINK_COMPONENT *)((char *)p + entrylen);
len = *ana->outlen;
outbuf = ana->outbuf;
cont = ana->cont;
@@ -125,9 +132,13 @@ cd9660_rrip_slink(void *v, ISO_RRIP_ANALYZE *ana)
/*
* Gathering a Symbolic name from each component with path
*/
for (; pcomp < pcompe;
pcomp = (ISO_RRIP_SLINK_COMPONENT *)
((char *)pcomp + ISO_RRIP_SLSIZ + isonum_711(pcomp->clen))) {
for (; pcomp < pcompe; pcomp = (ISO_RRIP_SLINK_COMPONENT *)
((char *)pcomp + ISO_RRIP_SLSIZ + clen)) {
if ((char *)pcomp + ISO_RRIP_SLSIZ > (char *)pcompe)
goto invalid;
clen = isonum_711(pcomp->clen);
if ((char *)pcomp + ISO_RRIP_SLSIZ + clen > (char *)pcompe)
goto invalid;
if (!cont) {
if (len < ana->maxlen) {
@@ -179,7 +190,7 @@ cd9660_rrip_slink(void *v, ISO_RRIP_ANALYZE *ana)
/* FALLTHROUGH */
case 0:
/* Inserting component */
wlen = isonum_711(pcomp->clen);
wlen = clen;
inbuf = pcomp->name;
break;
default:
@@ -210,6 +221,13 @@ cd9660_rrip_slink(void *v, ISO_RRIP_ANALYZE *ana)
return (ISO_SUSP_SLINK);
}
return (0);
invalid:
ana->cont = 1;
ana->fields = 0;
ana->outbuf -= *ana->outlen;
*ana->outlen = 0;
return (0);
}
/*
@@ -220,12 +238,17 @@ cd9660_rrip_altname(void *v, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_ALTNAME *p = v;
char *inbuf;
u_int len;
int wlen;
int cont;
inbuf = "..";
wlen = 0;
cont = 0;
len = isonum_711(p->h.length);
if (len < sizeof(*p))
goto invalid;
switch (*p->flags) {
case ISO_SUSP_CFLAG_CURRENT:
@@ -249,8 +272,8 @@ cd9660_rrip_altname(void *v, ISO_RRIP_ANALYZE *ana)
/* FALLTHROUGH */
case 0:
/* Inserting component */
wlen = isonum_711(p->h.length) - 5;
inbuf = (char *)p + 5;
wlen = len - sizeof(*p);
inbuf = (char *)p + sizeof(*p);
break;
default:
@@ -259,13 +282,10 @@ cd9660_rrip_altname(void *v, ISO_RRIP_ANALYZE *ana)
break;
}
if ((*ana->outlen += wlen) > ana->maxlen) {
/* treat as no name field */
ana->fields &= ~ISO_SUSP_ALTNAME;
ana->outbuf -= *ana->outlen - wlen;
*ana->outlen = 0;
return (0);
}
if (*ana->outlen > ana->maxlen || wlen < 0 ||
(u_int)wlen > ana->maxlen - *ana->outlen)
goto invalid;
*ana->outlen += wlen;
bcopy(inbuf, ana->outbuf, wlen);
ana->outbuf += wlen;
@@ -275,6 +295,13 @@ cd9660_rrip_altname(void *v, ISO_RRIP_ANALYZE *ana)
return (ISO_SUSP_ALTNAME);
}
return (0);
invalid:
/* treat as no name field */
ana->fields &= ~ISO_SUSP_ALTNAME;
ana->outbuf -= *ana->outlen;
*ana->outlen = 0;
return (0);
}
static void
@@ -306,6 +333,8 @@ cd9660_rrip_pclink(void *v, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_CLINK *p = v;
if (isonum_711(p->h.length) < sizeof(*p))
return (0);
*ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
ana->fields &= ~(ISO_SUSP_CLINK | ISO_SUSP_PLINK);
return (*p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK);
@@ -328,16 +357,35 @@ static int
cd9660_rrip_tstamp(void *v, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_TSTAMP *p = v;
u_int len, need;
u_char flags;
int tlen;
u_char *ptime;
len = isonum_711(p->h.length);
if (len < sizeof(*p))
return (0);
flags = *p->flags;
tlen = (flags & ISO_SUSP_TSTAMP_FORM17) ? 17 : 7;
need = sizeof(*p);
if (flags & ISO_SUSP_TSTAMP_CREAT)
need += tlen;
if (flags & ISO_SUSP_TSTAMP_MODIFY)
need += tlen;
if (flags & ISO_SUSP_TSTAMP_ACCESS)
need += tlen;
if (flags & ISO_SUSP_TSTAMP_ATTR)
need += tlen;
if (need > len)
return (0);
ptime = p->time;
/* Check a format of time stamp (7bytes/17bytes) */
if (!(*p->flags & ISO_SUSP_TSTAMP_FORM17)) {
if (*p->flags & ISO_SUSP_TSTAMP_CREAT)
if (!(flags & ISO_SUSP_TSTAMP_FORM17)) {
if (flags & ISO_SUSP_TSTAMP_CREAT)
ptime += 7;
if (*p->flags & ISO_SUSP_TSTAMP_MODIFY) {
if (flags & ISO_SUSP_TSTAMP_MODIFY) {
cd9660_tstamp_conv7(ptime,
&ana->inop->inode.iso_mtime);
ptime += 7;
@@ -345,7 +393,7 @@ cd9660_rrip_tstamp(void *v, ISO_RRIP_ANALYZE *ana)
bzero(&ana->inop->inode.iso_mtime,
sizeof(struct timespec));
if (*p->flags & ISO_SUSP_TSTAMP_ACCESS) {
if (flags & ISO_SUSP_TSTAMP_ACCESS) {
cd9660_tstamp_conv7(ptime,
&ana->inop->inode.iso_atime);
ptime += 7;
@@ -353,7 +401,7 @@ cd9660_rrip_tstamp(void *v, ISO_RRIP_ANALYZE *ana)
ana->inop->inode.iso_atime =
ana->inop->inode.iso_mtime;
if (*p->flags & ISO_SUSP_TSTAMP_ATTR)
if (flags & ISO_SUSP_TSTAMP_ATTR)
cd9660_tstamp_conv7(ptime,
&ana->inop->inode.iso_ctime);
else
@@ -361,10 +409,10 @@ cd9660_rrip_tstamp(void *v, ISO_RRIP_ANALYZE *ana)
ana->inop->inode.iso_mtime;
} else {
if (*p->flags & ISO_SUSP_TSTAMP_CREAT)
if (flags & ISO_SUSP_TSTAMP_CREAT)
ptime += 17;
if (*p->flags & ISO_SUSP_TSTAMP_MODIFY) {
if (flags & ISO_SUSP_TSTAMP_MODIFY) {
cd9660_tstamp_conv17(ptime,
&ana->inop->inode.iso_mtime);
ptime += 17;
@@ -372,7 +420,7 @@ cd9660_rrip_tstamp(void *v, ISO_RRIP_ANALYZE *ana)
bzero(&ana->inop->inode.iso_mtime,
sizeof(struct timespec));
if (*p->flags & ISO_SUSP_TSTAMP_ACCESS) {
if (flags & ISO_SUSP_TSTAMP_ACCESS) {
cd9660_tstamp_conv17(ptime,
&ana->inop->inode.iso_atime);
ptime += 17;
@@ -380,7 +428,7 @@ cd9660_rrip_tstamp(void *v, ISO_RRIP_ANALYZE *ana)
ana->inop->inode.iso_atime =
ana->inop->inode.iso_mtime;
if (*p->flags & ISO_SUSP_TSTAMP_ATTR)
if (flags & ISO_SUSP_TSTAMP_ATTR)
cd9660_tstamp_conv17(ptime,
&ana->inop->inode.iso_ctime);
else
@@ -409,6 +457,8 @@ cd9660_rrip_device(void *v, ISO_RRIP_ANALYZE *ana)
ISO_RRIP_DEVICE *p = v;
u_int high, low;
if (isonum_711(p->h.length) < sizeof(*p))
return (0);
high = isonum_733(p->dev_t_high);
low = isonum_733(p->dev_t_low);
@@ -428,6 +478,8 @@ cd9660_rrip_idflag(void *v, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_IDFLAG *p = v;
if (isonum_711(p->h.length) < sizeof(*p))
return (0);
/* don't touch high bits */
ana->fields &= isonum_711(p->flags) | ~0xff;
/* special handling of RE field */
@@ -445,6 +497,8 @@ cd9660_rrip_cont(void *v, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_CONT *p = v;
if (isonum_711(p->h.length) < sizeof(*p))
return (0);
ana->iso_ce_blk = isonum_733(p->location);
ana->iso_ce_off = isonum_733(p->offset);
ana->iso_ce_len = isonum_733(p->length);
@@ -467,16 +521,22 @@ static int
cd9660_rrip_extref(void *v, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_EXTREF *p = v;
u_int len, idlen;
len = isonum_711(p->h.length);
if (len < sizeof(*p))
return (0);
if (isonum_711(p->version) != 1)
return (0);
if (isonum_711(p->len_id) != 9 &&
isonum_711(p->len_id) != 10)
idlen = isonum_711(p->len_id);
if (idlen != 9 && idlen != 10)
return (0);
if (isonum_711(p->len_id) == 9 &&
if (len < sizeof(*p) + idlen)
return (0);
if (idlen == 9 &&
bcmp((char *)p + 8, "IEEE_1282", 9))
return (0);
if (isonum_711(p->len_id) == 10 &&
if (idlen == 10 &&
bcmp((char *)p + 8, "IEEE_P1282", 10) &&
bcmp((char *)p + 8, "RRIP_1991A", 10))
return (0);
@@ -494,6 +554,7 @@ cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
ISO_SUSP_HEADER *pend;
struct buf *bp = NULL;
char *pwhead;
u_int len;
u_char c;
int result;
@@ -523,6 +584,10 @@ cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
* Note: "pend" should be more than one SUSP header
*/
while (pend >= phead + 1) {
len = isonum_711(phead->length);
if (len < sizeof(*phead) ||
(char *)phead + len > (char *)pend)
break;
if (isonum_711(phead->version) == 1) {
for (ptable = table; ptable->func; ptable++) {
if (*phead->type == *ptable->type &&
@@ -540,15 +605,12 @@ cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
result &= ~ISO_SUSP_STOP;
break;
}
/* plausibility check */
if (isonum_711(phead->length) < sizeof(*phead))
break;
/*
* move to next SUSP
* Hopefully this works with newer versions, too
*/
phead = (ISO_SUSP_HEADER *)
((char *)phead + isonum_711(phead->length));
((char *)phead + len);
}
if (ana->fields && ana->iso_ce_len) {
@@ -710,13 +772,19 @@ cd9660_rrip_offset(struct iso_directory_record *isodir, struct iso_mnt *imp)
{
ISO_RRIP_OFFSET *p;
ISO_RRIP_ANALYZE analyze;
char *pend;
imp->rr_skip0 = 0;
p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
pend = (char *)isodir + isonum_711(isodir->length);
if ((char *)p + sizeof(*p) > pend)
return (-1);
if (bcmp(p, "SP\7\1\276\357", 6)) {
/* Maybe, it's a CDROM XA disc? */
imp->rr_skip0 = 15;
p = (ISO_RRIP_OFFSET *)((char *)p + 15);
if ((char *)p + sizeof(*p) > pend)
return (-1);
if (bcmp(p, "SP\7\1\276\357", 6))
return (-1);
}