a937c7a5d3
where the path component includes a quoted slash.
111 lines
4.2 KiB
Plaintext
111 lines
4.2 KiB
Plaintext
$OpenBSD: patch-unix_unix_c,v 1.2 2003/08/17 23:48:40 brad Exp $
|
|
--- unix/unix.c.orig 2002-01-21 17:54:42.000000000 -0500
|
|
+++ unix/unix.c 2003-08-17 19:25:19.000000000 -0400
|
|
@@ -421,7 +421,8 @@ int mapname(__G__ renamed)
|
|
*/
|
|
{
|
|
char pathcomp[FILNAMSIZ]; /* path-component buffer */
|
|
- char *pp, *cp=(char *)NULL; /* character pointers */
|
|
+ char *pp, *cp=(char *)NULL, /* character pointers */
|
|
+ *dp=(char *)NULL;
|
|
char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
|
|
#ifdef ACORN_FTYPE_NFS
|
|
char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */
|
|
@@ -429,6 +430,8 @@ int mapname(__G__ renamed)
|
|
#endif
|
|
int quote = FALSE; /* flags */
|
|
int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */
|
|
+ int killed_qslash = FALSE; /* is set when skipping "^V/" pathcomp */
|
|
+ int snarf_ddot = FALSE; /* Is set while scanning for "../" */
|
|
int error = MPN_OK;
|
|
register unsigned workch; /* hold the character being tested */
|
|
|
|
@@ -467,6 +470,18 @@ int mapname(__G__ renamed)
|
|
while ((workch = (uch)*cp++) != 0) {
|
|
|
|
if (quote) { /* if character quoted, */
|
|
+ if (pp == pathcomp) {
|
|
+ quote = FALSE;
|
|
+ if (workch == '.')
|
|
+ /* Oh no you don't... */
|
|
+ goto ddot_hack;
|
|
+ if (workch == '/') {
|
|
+ /* We *never* allow quote-slash at the beginning */
|
|
+ killed_qslash = TRUE;
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
*pp++ = (char)workch; /* include it literally */
|
|
quote = FALSE;
|
|
} else
|
|
@@ -481,15 +496,45 @@ int mapname(__G__ renamed)
|
|
break;
|
|
|
|
case '.':
|
|
- if (pp == pathcomp) { /* nothing appended yet... */
|
|
+ if (pp == pathcomp) {
|
|
+ddot_hack:
|
|
+ /* nothing appended yet... */
|
|
if (*cp == '/') { /* don't bother appending "./" to */
|
|
++cp; /* the path: skip behind the '/' */
|
|
break;
|
|
- } else if (!uO.ddotflag && *cp == '.' && cp[1] == '/') {
|
|
- /* "../" dir traversal detected */
|
|
- cp += 2; /* skip over behind the '/' */
|
|
- killed_ddot = TRUE; /* set "show message" flag */
|
|
- break;
|
|
+ } else if (!uO.ddotflag) {
|
|
+
|
|
+ /*
|
|
+ * SECURITY: Skip past control characters if the user
|
|
+ * didn't OK use of absolute pathnames. lhh - this is
|
|
+ * a very quick, ugly, inefficient fix; it traverses
|
|
+ * the WHOLE path, eating up these as it comes to it.
|
|
+ */
|
|
+ dp = cp;
|
|
+ do {
|
|
+ workch = (uch)(*dp);
|
|
+ if (workch == '/' && snarf_ddot) {
|
|
+ /* "../" dir traversal detected */
|
|
+ cp = dp + 1; /* skip past the '/' */
|
|
+ killed_ddot = TRUE; /* set "show msg" flag */
|
|
+ break;
|
|
+ } else if (workch == '.' && !snarf_ddot) {
|
|
+ snarf_ddot = TRUE;
|
|
+ } else if (isprint(workch) ||
|
|
+ ((workch > 127) && (workch <= 254))) {
|
|
+ /*
|
|
+ * Since we found a printable, non-ctrl char,
|
|
+ * we can stop looking for '../', the amount
|
|
+ * in ../!
|
|
+ */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ dp++;
|
|
+ } while (*dp != 0);
|
|
+
|
|
+ if (killed_ddot)
|
|
+ break;
|
|
}
|
|
}
|
|
*pp++ = '.';
|
|
@@ -534,6 +579,16 @@ int mapname(__G__ renamed)
|
|
error = (error & MPN_MASK) | PK_WARN;
|
|
}
|
|
|
|
+ /* Show warning when stripping insecure quoted-slash at beginning of
|
|
+ path components */
|
|
+ if (killed_qslash && QCOND2) {
|
|
+ Info(slide, 0, ((char *)slide,
|
|
+ "warning: skipped root directory component(s) in %s\n",
|
|
+ FnFilter1(G.filename)));
|
|
+ if (!(error & ~MPN_MASK))
|
|
+ error = (error & MPN_MASK) | PK_WARN;
|
|
+ }
|
|
+
|
|
/*---------------------------------------------------------------------------
|
|
Report if directory was created (and no file to create: filename ended
|
|
in '/'), check name to be sure it exists, and combine path and name be-
|