Ian Jackson writes ("dpkg fd and error handling bugs (with patch to fix)"):
> The attached patch fixes various error-handling bugs in dpkg.  Most of
> them are minor but there is one particularly important bug which is
> the erroneous repeated closure of the fsys tarfile pipe fd, which
> in principle could cause arbitrary weirdness.

It turns out that that patch was wrong.  tarfn.c didn't #include
dpkg.h and as a result you get implicit declarations of m_malloc.  I
wish we could have -Werror back.

Anyway, here's the revised patch; disregard the previous one.

Ian.

diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/debian/changelog 
dpkg-1.14.5ubuntu12/debian/changelog
--- old/dpkg-1.14.5ubuntu14/debian/changelog    2007-09-18 17:21:02.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/debian/changelog        2007-09-21 19:14:07.000000000 
+0100
@@ -1,3 +1,33 @@
+dpkg (1.14.5ubuntu16) gutsy; urgency=low
+
+  * Fix some portability problems revealed by compiler warnings:
+    - missing <dpkg.h> in tarfn.c, implicit declaration of m_malloc
+    - missing cast for %ld ohshite at info.c:98
+    - unused yyunput (missing %option nounput) in trigdeferred.l
+
+ -- Ian Jackson <[EMAIL PROTECTED]>  Fri, 21 Sep 2007 19:03:36 +0100
+
+dpkg (1.14.5ubuntu15) gutsy; urgency=low
+
+  * Bugfixes to fd cleanup handling:
+    - avoid closing fsys tarfile pipe twice even in normal
+      operation - normally EBADF but might sometimes close some other
+      desired fd and cause hideous doom.  (LP: #137191.)
+    - avoid duplicate attempts to [f]close in obscure error
+      situations which might conceiveably close wrong fds
+    - cast &fd to void* when passing to push_cleanup cu_closefd
+    - fix parse.c:parsedb to use ehflag_normaltidy in a sane way
+    - when passing &fd to push_cleanup cu_closefd, make fd always static
+  * Bugfix in trigger deferred file processing: reset lexer start state
+    when calling yyrestart (has no effect except after parsing/reading
+    errors in the deferred file).
+  * Fix some error handling bugs in tarfn.c:
+    - Avoid freeing uninitialised h.[Link]Name (can cause crash if .deb
+      becomes unreadable while we start up).  (LP: #138887.)
+    - Use m_malloc instead of malloc (and ditch ad-hoc error handling).
+
+ -- Ian Jackson <[EMAIL PROTECTED]>  Thu, 20 Sep 2007 18:12:20 +0100
+
 dpkg (1.14.5ubuntu14) gutsy; urgency=low
 
   * Change syntax of `processing:...' status fd outputs so
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/dpkg-deb/info.c 
dpkg-1.14.5ubuntu12/dpkg-deb/info.c
--- old/dpkg-1.14.5ubuntu14/dpkg-deb/info.c     2007-07-04 15:26:33.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/dpkg-deb/info.c 2007-09-21 18:58:14.000000000 +0100
@@ -95,7 +95,7 @@
     pathlen = strlen(directory) + strlen(component) + 2;
     controlfile = (void *) realloc((void *) controlfile, pathlen);
     if (!controlfile)
-      ohshite(_("realloc failed (%ld bytes)"), pathlen);
+      ohshite(_("realloc failed (%lu bytes)"), (unsigned long)pathlen);
     memset(controlfile, 0, sizeof(controlfile));
 
     strcat(controlfile, directory);
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/lib/dpkg.h 
dpkg-1.14.5ubuntu12/lib/dpkg.h
--- old/dpkg-1.14.5ubuntu14/lib/dpkg.h  2007-09-18 12:13:17.000000000 +0100
+++ dpkg-1.14.5ubuntu12/lib/dpkg.h      2007-09-20 16:52:46.000000000 +0100
@@ -236,6 +236,16 @@
 void cu_closefd(int argc, void **argv);
 void cu_closedir(int argc, void **argv);
 
+int ferror_fclose_pop_cleanup(FILE *f);
+ /* calls ferror and fclose on f, and pop_cleanup
+  *   file= fopen
+  *   push_cleanup(cu_closefile,~ehflag_normaltidy, 0,0, 1,(void*)file
+  * return is 0 on success or EOF if fclose or ferror failed
+  * all three calls are always made regardless, and in the right order
+  * so you can just call ohshite if this returns EOF
+  */
+    
+
 /*** from mlib.c ***/
 
 void setcloexec(int fd, const char* fn);
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/lib/ehandle.c 
dpkg-1.14.5ubuntu12/lib/ehandle.c
--- old/dpkg-1.14.5ubuntu14/lib/ehandle.c       2007-09-18 12:13:49.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/lib/ehandle.c   2007-09-20 17:03:31.000000000 +0100
@@ -330,6 +330,14 @@
   if (f) fclose(f);
 }
 
+int ferror_fclose_pop_cleanup(FILE *f) {
+  int r1, r2;
+  r1= ferror(f);
+  pop_cleanup(ehflag_normaltidy);
+  r2= fclose(f);
+  return r1 ? r1 : r2;
+}
+
 void cu_closedir(int argc, void **argv) {
   DIR *d= (DIR*)(argv[0]);
   if (d) closedir(d);
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/lib/parse.c 
dpkg-1.14.5ubuntu12/lib/parse.c
--- old/dpkg-1.14.5ubuntu14/lib/parse.c 2007-08-16 00:44:00.000000000 +0100
+++ dpkg-1.14.5ubuntu12/lib/parse.c     2007-09-20 17:19:53.000000000 +0100
@@ -87,7 +87,7 @@
    * If donep is not null only one package's information is expected.
    */
   
-  int fd;
+  static int fd;
   struct pkginfo newpig, *pigp;
   struct pkginfoperfile *newpifp, *pifp;
   struct arbitraryfield *arp, **larpp;
@@ -109,7 +109,7 @@
   fd= open(filename, O_RDONLY);
   if (fd == -1) ohshite(_("failed to open package info file `%.255s' for 
reading"),filename);
 
-  push_cleanup(cu_parsedb,~0, NULL,0, 1,&fd);
+  push_cleanup(cu_parsedb,~ehflag_normaltidy, NULL,0, 1,&fd);
 
   if (fstat(fd, &stat) == -1)
     ohshite(_("can't stat package info file `%.255s'"),filename);
@@ -355,7 +355,6 @@
     if (EOF_mmap(dataptr, endptr)) break;
     if (c == '\n') lno++;
   }
-  pop_cleanup(0);
   if (data != NULL) {
 #ifdef HAVE_MMAP
     munmap(data, stat.st_size);
@@ -364,6 +363,7 @@
 #endif
   }
   free(value);
+  pop_cleanup(ehflag_normaltidy);
   if (close(fd)) ohshite(_("failed to close after read: `%.255s'"),filename);
   if (donep && !pdone) ohshit(_("no package information in 
`%.255s'"),filename);
 
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/lib/tarfn.c 
dpkg-1.14.5ubuntu12/lib/tarfn.c
--- old/dpkg-1.14.5ubuntu14/lib/tarfn.c 2007-07-04 15:26:32.000000000 +0100
+++ dpkg-1.14.5ubuntu12/lib/tarfn.c     2007-09-21 18:54:31.000000000 +0100
@@ -14,6 +14,7 @@
 #include <grp.h>
 #include <errno.h>
 #include <tarfn.h>
+#include <dpkg.h>
 
 struct TarHeader {
   char Name[100];
@@ -61,7 +62,7 @@
   char *  str;
 
   len = strnlen(s, size);
-  str = malloc(len + 1);
+  str = m_malloc(len + 1);
   memcpy(str, s, len);
   str[len] = 0;
 
@@ -137,9 +138,11 @@
        next_long_name = NULL;
        next_long_link = NULL;
        long_read = 0;
-  symListBottom = symListPointer = symListTop = malloc(sizeof(symlinkList));
+  symListBottom = symListPointer = symListTop = m_malloc(sizeof(symlinkList));
   symListTop->next = NULL;
 
+  h.Name = NULL;
+  h.LinkName = NULL;
   h.UserData = userData;
 
   while ( (status = functions->Read(userData, buffer, 512)) == 512 ) {
@@ -206,13 +209,7 @@
         errno = 0;
         break;
       }
-      if ((symListBottom->next = malloc(sizeof(symlinkList))) == NULL) {
-        free(symListBottom->h.LinkName);
-        free(symListBottom->h.Name);
-        status = -1;
-        errno = 0;
-        break;
-      }
+      symListBottom->next = m_malloc(sizeof(symlinkList));
       symListBottom = symListBottom->next;
       symListBottom->next = NULL;
       status = 0;
@@ -233,12 +230,7 @@
                  if (*longp)
                    free(*longp);
 
-                 if (NULL == (*longp = (char *)malloc(h.Size))) {
-                   /* malloc failed, so bail */
-                   errno = 0;
-       status = -1;
-       break;
-                 }
+                 *longp = (char *)m_malloc(h.Size);
                  bp = *longp;
 
                  // the way the GNU long{link,name} stuff works is like this:  
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/lib/trigdeferred.l 
dpkg-1.14.5ubuntu12/lib/trigdeferred.l
--- old/dpkg-1.14.5ubuntu14/lib/trigdeferred.l  2007-08-21 15:22:28.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/lib/trigdeferred.l      2007-09-21 18:58:31.000000000 
+0100
@@ -24,6 +24,7 @@
 %option prefix="trigdef_yy"
 %option outfile="trigdeferred.c"
 %option noyywrap
+%option nounput
 %option batch
 %option nodefault
 %option perf-report
@@ -142,6 +143,7 @@
     return 1;
 
   trigdef_yyrestart(old_deferred);
+  BEGIN(0);
   return 2;
 }
 
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/lib/triglib.c 
dpkg-1.14.5ubuntu12/lib/triglib.c
--- old/dpkg-1.14.5ubuntu14/lib/triglib.c       2007-08-16 16:52:53.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/lib/triglib.c   2007-09-20 17:38:53.000000000 +0100
@@ -296,9 +296,8 @@
   }
   if (signum > 0)
     fprintf(nf,"%s\n",pkg->name);
-  if (ferror(nf) || fclose(nf))
+  if (ferror_fclose_pop_cleanup(nf))
     ohshite(_("unable to write new trigger interest file `%.250s'"),newfn.buf);
-  pop_cleanup(ehflag_normaltidy);
 
   if (rename(newfn.buf,trk_explicit_fn.buf))
     ohshite(_("unable to install new trigger interest file `%.250s'"),
@@ -369,10 +368,9 @@
   for (tfi=filetriggers.head; tfi; tfi=tfi->inoverall.next)
     fprintf(nf, "%s %s\n", trigh.namenode_name(tfi->fnn), tfi->pkg->name);
 
-  if (ferror(nf) || fclose(nf))
+  if (ferror_fclose_pop_cleanup(nf))
     ohshite(_("unable to write new file triggers file `%.250s'"),
            triggersnewfilefile);
-  pop_cleanup(ehflag_normaltidy);
 
   if (rename(triggersnewfilefile, triggersfilefile))
     ohshite(_("unable to install new file triggers file as `%.250s'"),
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/src/archives.c 
dpkg-1.14.5ubuntu12/src/archives.c
--- old/dpkg-1.14.5ubuntu14/src/archives.c      2007-09-18 12:17:35.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/src/archives.c  2007-09-20 16:56:46.000000000 +0100
@@ -367,11 +367,12 @@
 
 int tarobject(struct TarInfo *ti) {
   static struct varbuf conffderefn, hardlinkfn, symlinkfn;
+  static int fd;
   const char *usename;
 
   struct conffile *conff;
   struct tarcontext *tc= (struct tarcontext*)ti->UserData;
-  int statr, fd, i, existingdirectory, keepexisting;
+  int statr, i, existingdirectory, keepexisting;
   size_t r;
   struct stat stab, stabtmp;
   char databuf[TARBLKSZ];
@@ -641,7 +642,7 @@
      */
     fd= open(fnamenewvb.buf, (O_CREAT|O_EXCL|O_WRONLY), 0);
     if (fd < 0) ohshite(_("unable to create `%.255s'"),ti->Name);
-    push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,&fd);
+    push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,(void*)&fd);
     debug(dbg_eachfiledetail,"tarobject NormalFile[01] open size=%lu",
           (unsigned long)ti->Size);
     { char fnamebuf[256];
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/src/configure.c 
dpkg-1.14.5ubuntu12/src/configure.c
--- old/dpkg-1.14.5ubuntu14/src/configure.c     2007-09-18 12:10:00.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/src/configure.c 2007-09-20 16:59:11.000000000 +0100
@@ -425,7 +425,7 @@
   fd=open(fn,O_RDONLY);
 
   if (fd>=0) {
-    push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,&fd);
+    push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,(void*)&fd);
     fd_md5(fd, hashbuf, -1, _("md5hash"));
     pop_cleanup(ehflag_normaltidy); /* fd= open(cdr.buf) */
     close(fd);
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/src/filesdb.c 
dpkg-1.14.5ubuntu12/src/filesdb.c
--- old/dpkg-1.14.5ubuntu14/src/filesdb.c       2007-08-16 00:44:00.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/src/filesdb.c   2007-09-20 16:59:11.000000000 +0100
@@ -133,7 +133,7 @@
     return;
   }
 
-  push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,&fd);
+  push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,(void*)&fd);
   
    if(fstat(fd, &stat_buf))
      ohshite("unable to stat files list file for package `%.250s'",pkg->name);
diff --exclude='*~' -ru old/dpkg-1.14.5ubuntu14/src/processarc.c 
dpkg-1.14.5ubuntu12/src/processarc.c
--- old/dpkg-1.14.5ubuntu14/src/processarc.c    2007-09-18 11:35:37.000000000 
+0100
+++ dpkg-1.14.5ubuntu12/src/processarc.c        2007-09-20 15:46:48.000000000 
+0100
@@ -562,13 +562,12 @@
     execlp(BACKEND, BACKEND, "--fsys-tarfile", filename, (char*)0);
     ohshite(_("unable to exec dpkg-deb to get filesystem archive"));
   }
-  close(p1[1]);
+  close(p1[1]);  p1[1]= -1;
 
   newfileslist= 0; tc.newfilesp= &newfileslist;
   push_cleanup(cu_fileslist,~0, 0, 0, 0);
   tc.pkg= pkg;
   tc.backendpipe= p1[0];
-  push_cleanup(cu_closefd,~ehflag_bombout, 0,0, 1,&tc.backendpipe);
 
   r= TarExtractor((void*)&tc, &tf);
   if (r) {
@@ -578,8 +577,8 @@
       ohshit(_("corrupted filesystem tarfile - corrupted package archive"));
     }
   }
-  fd_null_copy(tc.backendpipe,-1,_("dpkg-deb: zap possible trailing zeros"));
-  close(tc.backendpipe);
+  fd_null_copy(p1[0],-1,_("dpkg-deb: zap possible trailing zeros"));
+  close(p1[0]);  p1[0]= -1;
   waitsubproc(c1,BACKEND " --fsys-tarfile",PROCPIPE);
 
   if (oldversionstatus == stat_halfinstalled || oldversionstatus == 
stat_unpacked) {

Reply via email to