git: 9cd0d6231311 - main - cd9660: Add various length checks when parsing RRIP extensions
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 22 Jun 2026 16:47:27 UTC
The branch main has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=9cd0d6231311bc5609403fb35377a7bb97a3cfaf
commit 9cd0d6231311bc5609403fb35377a7bb97a3cfaf
Author: John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2026-06-22 16:41:04 +0000
Commit: John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-06-22 16:41:04 +0000
cd9660: Add various length checks when parsing RRIP extensions
Pass the length of a RockRidge attribute to the handler functions and
validate that length in each handler. If a parsing error is detected,
abort the entire parsing pass.
Reviewed by: des
Differential Revision: https://reviews.freebsd.org/D57136
---
sys/fs/cd9660/cd9660_rrip.c | 186 ++++++++++++++++++++++++++++++++------------
sys/fs/cd9660/iso_rrip.h | 1 +
2 files changed, 136 insertions(+), 51 deletions(-)
diff --git a/sys/fs/cd9660/cd9660_rrip.c b/sys/fs/cd9660/cd9660_rrip.c
index db87f6d1223e..e3aab4fa6115 100644
--- a/sys/fs/cd9660/cd9660_rrip.c
+++ b/sys/fs/cd9660/cd9660_rrip.c
@@ -48,7 +48,7 @@
#include <fs/cd9660/cd9660_rrip.h>
#include <fs/cd9660/iso_rrip.h>
-typedef int rrt_func_t(void *, ISO_RRIP_ANALYZE *ana);
+typedef int rrt_func_t(void *, size_t, ISO_RRIP_ANALYZE *ana);
typedef struct {
char type[2];
@@ -57,32 +57,48 @@ typedef struct {
int result;
} RRIP_TABLE;
-static int cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_attr(ISO_RRIP_ATTR *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_cont(ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_attr(ISO_RRIP_ATTR *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_cont(ISO_RRIP_CONT *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
static void cd9660_rrip_defattr(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana);
static void cd9660_rrip_defname(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana);
static void cd9660_rrip_deftstamp(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_device(ISO_RRIP_DEVICE *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_extref(ISO_RRIP_EXTREF *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_device(ISO_RRIP_DEVICE *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_extref(ISO_RRIP_EXTREF *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_loop(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana, RRIP_TABLE *table);
-static int cd9660_rrip_pclink(ISO_RRIP_CLINK *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_stop(ISO_SUSP_HEADER *p, ISO_RRIP_ANALYZE *ana);
-static int cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_pclink(ISO_RRIP_CLINK *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_slink(ISO_RRIP_SLINK *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_stop(ISO_SUSP_HEADER *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
+static int cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, size_t len,
+ ISO_RRIP_ANALYZE *ana);
/*
* POSIX file attribute
*/
static int
-cd9660_rrip_attr(ISO_RRIP_ATTR *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_attr(ISO_RRIP_ATTR *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
+ if (len < sizeof(*p)) {
+ ana->error = true;
+ 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);
@@ -103,16 +119,23 @@ cd9660_rrip_defattr(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
* Symbolic Links
*/
static int
-cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_slink(ISO_RRIP_SLINK *p, size_t plen, ISO_RRIP_ANALYZE *ana)
{
ISO_RRIP_SLINK_COMPONENT *pcomp;
ISO_RRIP_SLINK_COMPONENT *pcompe;
+ ISO_RRIP_SLINK_COMPONENT *pcompn;
int len, wlen, cont;
char *outbuf, *inbuf;
char hostbuf[MAXHOSTNAMELEN];
+ /* This requires at least one byte of a component. */
+ if (plen < sizeof(*p)) {
+ ana->error = true;
+ return (0);
+ }
+
pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
- pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
+ pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + plen);
len = *ana->outlen;
outbuf = ana->outbuf;
cont = ana->cont;
@@ -120,10 +143,16 @@ cd9660_rrip_slink(ISO_RRIP_SLINK *p, 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 = pcompn) {
+ pcompn = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp +
+ ISO_RRIP_SLSIZ + isonum_711(pcomp->clen));
+
+ /* If this component overflows the buffer, abort parsing. */
+ if (pcompn > pcompe) {
+ ana->error = true;
+ return (0);
+ }
+
if (!cont) {
if (len < ana->maxlen) {
len++;
@@ -175,21 +204,15 @@ cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana)
/* Inserting component */
wlen = isonum_711(pcomp->clen);
inbuf = pcomp->name;
- if (inbuf + wlen > (char *)pcompe)
- wlen = ana->maxlen + 1;
break;
default:
printf("RRIP with incorrect flags?");
- wlen = ana->maxlen + 1;
- break;
+ ana->error = true;
+ return (0);
}
if (len + wlen > ana->maxlen) {
- /* indicate error to caller */
- ana->cont = 1;
- ana->fields = 0;
- ana->outbuf -= *ana->outlen;
- *ana->outlen = 0;
+ ana->error = true;
return (0);
}
@@ -212,13 +235,18 @@ cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana)
* Alternate name
*/
static int
-cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
char *inbuf;
int wlen;
int cont;
char hostbuf[MAXHOSTNAMELEN];
+ if (len < sizeof(*p)) {
+ ana->error = true;
+ return (0);
+ }
+
inbuf = "..";
wlen = 0;
cont = 0;
@@ -246,23 +274,18 @@ cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana)
/* FALLTHROUGH */
case 0:
/* Inserting component */
- wlen = isonum_711(p->h.length) - 5;
- inbuf = (char *)p + 5;
- if (wlen < 0)
- wlen = ana->maxlen + 1;
+ wlen = len - sizeof(*p);
+ inbuf = (char *)(p + 1);
break;
default:
printf("RRIP with incorrect NM flags?\n");
- wlen = ana->maxlen + 1;
- break;
+ ana->error = true;
+ return (0);
}
if ((*ana->outlen += wlen) > ana->maxlen) {
- /* treat as no name field */
- ana->fields &= ~ISO_SUSP_ALTNAME;
- ana->outbuf -= *ana->outlen - wlen;
- *ana->outlen = 0;
+ ana->error = true;
return (0);
}
@@ -299,8 +322,13 @@ cd9660_rrip_defname(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
* Parent or Child Link
*/
static int
-cd9660_rrip_pclink(ISO_RRIP_CLINK *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_pclink(ISO_RRIP_CLINK *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
+ if (len < sizeof(*p)) {
+ ana->error = true;
+ 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);
@@ -310,7 +338,7 @@ cd9660_rrip_pclink(ISO_RRIP_CLINK *p, ISO_RRIP_ANALYZE *ana)
* Relocated directory
*/
static int
-cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
/* special hack to make caller aware of RE field */
*ana->outlen = 0;
@@ -319,9 +347,29 @@ cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, ISO_RRIP_ANALYZE *ana)
}
static int
-cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
u_char *ptime;
+ u_int count;
+
+ if (len < sizeof(*p))
+ goto bad;
+
+ count = 0;
+ if (*p->flags & ISO_SUSP_TSTAMP_CREAT)
+ count++;
+ if (*p->flags & ISO_SUSP_TSTAMP_MODIFY)
+ count++;
+ if (*p->flags & ISO_SUSP_TSTAMP_ACCESS)
+ count++;
+ if (*p->flags & ISO_SUSP_TSTAMP_ATTR)
+ count++;
+ if (*p->flags & ISO_SUSP_TSTAMP_FORM17)
+ count *= 17;
+ else
+ count *= 7;
+ if (offsetof(ISO_RRIP_TSTAMP, time) + count > len)
+ goto bad;
ptime = p->time;
@@ -374,6 +422,10 @@ cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, ISO_RRIP_ANALYZE *ana)
}
ana->fields &= ~ISO_SUSP_TSTAMP;
return (ISO_SUSP_TSTAMP);
+
+bad:
+ ana->error = true;
+ return (0);
}
static void
@@ -387,10 +439,15 @@ cd9660_rrip_deftstamp(struct iso_directory_record *isodir,
* POSIX device modes
*/
static int
-cd9660_rrip_device(ISO_RRIP_DEVICE *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_device(ISO_RRIP_DEVICE *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
u_int high, low;
+ if (len < sizeof(*p)) {
+ ana->error = true;
+ return (0);
+ }
+
high = isonum_733(p->dev_t_high);
low = isonum_733(p->dev_t_low);
@@ -406,12 +463,17 @@ cd9660_rrip_device(ISO_RRIP_DEVICE *p, ISO_RRIP_ANALYZE *ana)
* Flag indicating
*/
static int
-cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
+ if (len < sizeof(*p)) {
+ ana->error = true;
+ return (0);
+ }
+
ana->fields &= isonum_711(p->flags) | ~0xff; /* don't touch high bits */
/* special handling of RE field */
if (ana->fields & ISO_SUSP_RELDIR)
- return (cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p, ana));
+ return (cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p, len, ana));
return (ISO_SUSP_IDFLAG);
}
@@ -420,8 +482,13 @@ cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana)
* Continuation pointer
*/
static int
-cd9660_rrip_cont(ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_cont(ISO_RRIP_CONT *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
+ if (len < sizeof(*p)) {
+ ana->error = true;
+ 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);
@@ -432,7 +499,7 @@ cd9660_rrip_cont(ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana)
* System Use end
*/
static int
-cd9660_rrip_stop(ISO_SUSP_HEADER *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_stop(ISO_SUSP_HEADER *p, size_t len, ISO_RRIP_ANALYZE *ana)
{
return (ISO_SUSP_STOP);
}
@@ -441,11 +508,18 @@ cd9660_rrip_stop(ISO_SUSP_HEADER *p, ISO_RRIP_ANALYZE *ana)
* Extension reference
*/
static int
-cd9660_rrip_extref(ISO_RRIP_EXTREF *p, ISO_RRIP_ANALYZE *ana)
+cd9660_rrip_extref(ISO_RRIP_EXTREF *p, size_t plen, ISO_RRIP_ANALYZE *ana)
{
- size_t len = isonum_711(p->len_id);
- char *data = (char *)(p + 1);
+ size_t len;
+ char *data;
+
+ if (plen < sizeof(*p)) {
+ ana->error = true;
+ return (0);
+ }
+ len = isonum_711(p->len_id);
+ data = (char *)(p + 1);
if ((len == 10 && memcmp(data, "RRIP_1991A", len) == 0) ||
(len == 10 && memcmp(data, "IEEE_P1282", len) == 0) ||
(len == 9 && memcmp(data, "IEEE_1282", len) == 0)) {
@@ -490,6 +564,7 @@ cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
result = 0;
+ ana->error = false;
while (1) {
ana->iso_ce_len = 0;
/*
@@ -515,10 +590,18 @@ cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
for (ptable = table; ptable->func; ptable++) {
if (phead->type[0] == ptable->type[0] &&
phead->type[1] == ptable->type[1]) {
- result |= ptable->func(phead, ana);
+ result |= ptable->func(phead,
+ isonum_711(phead->length),
+ ana);
break;
}
}
+ if (ana->error) {
+ *ana->outlen = 0;
+ result = 0;
+ goto error;
+ }
+
if (!ana->fields)
break;
}
@@ -550,6 +633,7 @@ cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
} else
break;
}
+error:
if (bp)
brelse(bp);
/*
diff --git a/sys/fs/cd9660/iso_rrip.h b/sys/fs/cd9660/iso_rrip.h
index 5a75beb08d93..934a9f7bd2da 100644
--- a/sys/fs/cd9660/iso_rrip.h
+++ b/sys/fs/cd9660/iso_rrip.h
@@ -68,6 +68,7 @@ typedef struct {
u_short *outlen; /* length of above */
u_short maxlen; /* maximum length of above */
int cont; /* continuation of above */
+ bool error; /* parsing error occurred */
} ISO_RRIP_ANALYZE;
struct iso_directory_record;