Date: Wed, 7 Jun 2000 18:11:04 -0700 (PDT) From: Kris Kennaway <kris@FreeBSD.org> To: current@freebsd.org Subject: mktemp() patch Message-ID: <Pine.BSF.4.21.0006071758550.11848-100000@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
This patch was developed by Peter Jeremy and myself and increases the number of possible temporary filenames which can be generated by the mktemp() family, by more densely encoding the PID and using a larger set of characters to randomly pad with. Instead of using only alphabetic characters, the patch uses the following character set: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#%^-_=+:,.~ which is not believed to cause any problems with shells. The PID is also base-64 encoded into 3 characters (instead of the usual 5 for a base-10 representation) with an extra bit of randomness added in to fill the space. All up, for the usual case of a program calling mktemp() with 6 X's in the argument, this patch gives 74^3*2=810448 possibilities instead of 52 (assuming the PID is known), and the number increases exponentially thereafter with additional X's. It's not a solution to mktemp() since there's still a race condition, and for applications which only use 6 X's there's still only a relatively small number of possible filenames, but it does incrementally improve the situation by making it less likely for an attacker to guess the correct name (i.e. harder to win the race). Unless anyone has comments, I'd like to commit this to -current. Peter, I hope I've got the right version of the patch - any remaining bugs are likely to be my fault (although I've been running this here for a long time without problems). Kris Index: mktemp.c =================================================================== RCS file: /home/ncvs/src/lib/libc/stdio/mktemp.c,v retrieving revision 1.19 diff -u -r1.19 mktemp.c --- mktemp.c 2000/01/27 23:06:46 1.19 +++ mktemp.c 2000/06/08 00:57:17 @@ -52,6 +52,11 @@ static int _gettemp __P((char *, int *, int, int)); +static unsigned char base64[] = + ".#0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static unsigned char padchar[] = +"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#%^-_=+:,.~"; + int mkstemps(path, slen) char *path; @@ -103,8 +108,10 @@ int slen; { register char *start, *trv, *suffp; + char *pad; struct stat sbuf; - int pid, rval; + int rval, n; + uint32_t pid; if (doopen && domkdir) { errno = EINVAL; @@ -120,20 +127,22 @@ errno = EINVAL; return (0); } - pid = getpid(); - while (*trv == 'X' && pid != 0) { - *trv-- = (pid % 10) + '0'; - pid /= 10; + + /* Encode the PID (with 1 bit of randomness) into 3 base-64 chars */ + pid = getpid() | (arc4random() & 0x00020000); + for (n = 0; *trv == 'X' && n < 3; n++) { + *trv-- = base64[pid & 0x3f]; + pid >>= 6; } - while (*trv == 'X') { - char c; + if (n < 3) { /* Not enough characters to encode PID */ + errno = EINVAL; + return(0); + } - pid = (arc4random() & 0xffff) % (26+26); - if (pid < 26) - c = pid + 'A'; - else - c = (pid - 26) + 'a'; - *trv-- = c; + /* Fill remaining space with random characters */ + while (*trv == 'X') { + pid = arc4random() % (sizeof(padchar) - 1); + *trv-- = padchar[pid]; } start = trv + 1; @@ -179,15 +188,11 @@ for (trv = start;;) { if (*trv == '\0' || trv == suffp) return(0); - if (*trv == 'Z') - *trv++ = 'a'; + pad = strchr(padchar, *trv); + if (pad == NULL || !*++pad) + *trv++ = padchar[0]; else { - if (isdigit((unsigned char)*trv)) - *trv = 'a'; - else if (*trv == 'z') /* inc from z to A */ - *trv = 'A'; - else - ++*trv; + *trv++ = *pad; break; } } -- In God we Trust -- all others must submit an X.509 certificate. -- Charles Forsythe <forsythe@alum.mit.edu> To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0006071758550.11848-100000>