Description: fix arbitrary code execution via crafted PPD file . From upstream changelog entry: . foomaticrip.c: SECURITY FIX: It was possible to make CUPS executing arbitrary commands as the system user "lp" when foomatic-rip was used as CUPS filter. Fixed by not parsing named options (like "--ppd lj.ppd") when foomatic-rip is running as CUPS filter, as CUPS does not supply named options to their filters. Author: Till Kamppeter Acked-by: Marc Deslauriers Origin: upstream, http://bzr.linuxfoundation.org/loggerhead/openprinting/foomatic/foomatic-filters/revision/252 Bug-CVE: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-2964 Last-Update: 2011-07-24 Index: foomatic-filters-4.0.5/foomaticrip.c =================================================================== --- foomatic-filters-4.0.5.orig/foomaticrip.c 2010-08-10 06:08:04.000000000 -0400 +++ foomatic-filters-4.0.5/foomaticrip.c 2011-08-03 11:23:00.551600057 -0400 @@ -1230,8 +1230,11 @@ } /* Check for LPRng first so we do not pick up bogus ppd files by the -ppd option */ - if (arglist_remove_flag(arglist, "--lprng")) - spooler = SPOOLER_LPRNG; + if (spooler != SPOOLER_CUPS && spooler != SPOOLER_PPR && + spooler != SPOOLER_PPR_INT) { + if (arglist_remove_flag(arglist, "--lprng")) + spooler = SPOOLER_LPRNG; + } /* 'PRINTCAP_ENTRY' environment variable is : LPRng the :ppd=/path/to/ppdfile printcap entry should be used */ @@ -1253,96 +1256,104 @@ } } - /* PPD file name given via the command line - allow duplicates, and use the last specified one */ - if (spooler != SPOOLER_LPRNG) { - while ((str = arglist_get_value(arglist, "-p"))) { - strncpy(job->ppdfile, str, 256); - arglist_remove(arglist, "-p"); + /* CUPS calls foomatic-rip only with 5 or 6 positional parameters, + not with named options, like for example "-p ". Also PPR + does not used named options. */ + if (spooler != SPOOLER_CUPS && spooler != SPOOLER_PPR && + spooler != SPOOLER_PPR_INT) { + /* Check for LPD/GNUlpr by typical options which the spooler puts onto + the filter's command line (options "-w": text width, "-l": text + length, "-i": indent, "-x", "-y": graphics size, "-c": raw printing, + "-n": user name, "-h": host name) */ + if ((str = arglist_get_value(arglist, "-h"))) { + if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG) + spooler = SPOOLER_LPD; + strncpy(job->host, str, 127); + job->host[127] = '\0'; + arglist_remove(arglist, "-h"); } - } - while ((str = arglist_get_value(arglist, "--ppd"))) { - strncpy(job->ppdfile, str, 256); - arglist_remove(arglist, "--ppd"); - } - - /* Check for LPD/GNUlpr by typical options which the spooler puts onto - the filter's command line (options "-w": text width, "-l": text - length, "-i": indent, "-x", "-y": graphics size, "-c": raw printing, - "-n": user name, "-h": host name) */ - if ((str = arglist_get_value(arglist, "-h"))) { - if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG) - spooler = SPOOLER_LPD; - strncpy(job->host, str, 127); - job->host[127] = '\0'; - arglist_remove(arglist, "-h"); - } - if ((str = arglist_get_value(arglist, "-n"))) { - if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG) - spooler = SPOOLER_LPD; - - strncpy(job->user, str, 127); - job->user[127] = '\0'; - arglist_remove(arglist, "-n"); - } - if (arglist_remove(arglist, "-w") || - arglist_remove(arglist, "-l") || - arglist_remove(arglist, "-x") || - arglist_remove(arglist, "-y") || - arglist_remove(arglist, "-i") || - arglist_remove_flag(arglist, "-c")) { + if ((str = arglist_get_value(arglist, "-n"))) { if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG) spooler = SPOOLER_LPD; - } - /* LPRng delivers the option settings via the "-Z" argument */ - if ((str = arglist_get_value(arglist, "-Z"))) { - spooler = SPOOLER_LPRNG; - dstrcatf(job->optstr, "%s ", str); - arglist_remove(arglist, "-Z"); - } - /* Job title and options for stock LPD */ - if ((str = arglist_get_value(arglist, "-j")) || (str = arglist_get_value(arglist, "-J"))) { - strncpy_omit(job->title, str, 128, omit_shellescapes); - if (spooler == SPOOLER_LPD) - dstrcatf(job->optstr, "%s ", job->title); - if (!arglist_remove(arglist, "-j")) - arglist_remove(arglist, "-J"); - } - /* Check for CPS */ - if (arglist_remove_flag(arglist, "--cps") > 0) - spooler = SPOOLER_CPS; - - /* Options for spooler-less printing, CPS, or PDQ */ - while ((str = arglist_get_value(arglist, "-o"))) { - strncpy_omit(tmp, str, 1024, omit_shellescapes); - dstrcatf(job->optstr, "%s ", tmp); - arglist_remove(arglist, "-o"); - /* If we don't print as PPR RIP or as CPS filter, we print - without spooler (we check for PDQ later) */ - if (spooler != SPOOLER_PPR && spooler != SPOOLER_CPS) - spooler = SPOOLER_DIRECT; - } - /* Printer for spooler-less printing or PDQ */ - if ((str = arglist_get_value(arglist, "-d"))) { - strncpy_omit(job->printer, str, 256, omit_shellescapes); - arglist_remove(arglist, "-d"); - } + strncpy(job->user, str, 127); + job->user[127] = '\0'; + arglist_remove(arglist, "-n"); + } + if (arglist_remove(arglist, "-w") || + arglist_remove(arglist, "-l") || + arglist_remove(arglist, "-x") || + arglist_remove(arglist, "-y") || + arglist_remove(arglist, "-i") || + arglist_remove_flag(arglist, "-c")) { + if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG) + spooler = SPOOLER_LPD; + } + /* LPRng delivers the option settings via the "-Z" argument */ + if ((str = arglist_get_value(arglist, "-Z"))) { + spooler = SPOOLER_LPRNG; + dstrcatf(job->optstr, "%s ", str); + arglist_remove(arglist, "-Z"); + } + /* Job title and options for stock LPD */ + if ((str = arglist_get_value(arglist, "-j")) || (str = arglist_get_value(arglist, "-J"))) { + strncpy_omit(job->title, str, 128, omit_shellescapes); + if (spooler == SPOOLER_LPD) + dstrcatf(job->optstr, "%s ", job->title); + if (!arglist_remove(arglist, "-j")) + arglist_remove(arglist, "-J"); + } - /* Printer for spooler-less printing, PDQ, or LPRng */ - if ((str = arglist_get_value(arglist, "-P"))) { - strncpy_omit(job->printer, str, 256, omit_shellescapes); - arglist_remove(arglist, "-P"); - } + /* Check for CPS */ + if (arglist_remove_flag(arglist, "--cps") > 0) + spooler = SPOOLER_CPS; + + /* PPD file name given via the command line + allow duplicates, and use the last specified one */ + if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG && + spooler != SPOOLER_LPD) { + while ((str = arglist_get_value(arglist, "-p"))) { + strncpy(job->ppdfile, str, 256); + arglist_remove(arglist, "-p"); + } + while ((str = arglist_get_value(arglist, "--ppd"))) { + strncpy(job->ppdfile, str, 256); + arglist_remove(arglist, "--ppd"); + } + } - /* Were we called from a PDQ wrapper? */ - if (arglist_remove_flag(arglist, "--pdq")) - spooler = SPOOLER_PDQ; - - /* Were we called to build the PDQ driver declaration file? */ - genpdqfile = check_pdq_file(arglist); - if (genpdqfile) - spooler = SPOOLER_PDQ; + /* Options for spooler-less printing, CPS, or PDQ */ + while ((str = arglist_get_value(arglist, "-o"))) { + strncpy_omit(tmp, str, 1024, omit_shellescapes); + dstrcatf(job->optstr, "%s ", tmp); + arglist_remove(arglist, "-o"); + /* If we don't print as PPR RIP or as CPS filter, we print + without spooler (we check for PDQ later) */ + if (spooler != SPOOLER_PPR && spooler != SPOOLER_CPS) + spooler = SPOOLER_DIRECT; + } + + /* Printer for spooler-less printing or PDQ */ + if ((str = arglist_get_value(arglist, "-d"))) { + strncpy_omit(job->printer, str, 256, omit_shellescapes); + arglist_remove(arglist, "-d"); + } + + /* Printer for spooler-less printing, PDQ, or LPRng */ + if ((str = arglist_get_value(arglist, "-P"))) { + strncpy_omit(job->printer, str, 256, omit_shellescapes); + arglist_remove(arglist, "-P"); + } + + /* Were we called from a PDQ wrapper? */ + if (arglist_remove_flag(arglist, "--pdq")) + spooler = SPOOLER_PDQ; + + /* Were we called to build the PDQ driver declaration file? */ + genpdqfile = check_pdq_file(arglist); + if (genpdqfile) + spooler = SPOOLER_PDQ; + } /* spooler specific initialization */ switch (spooler) {