ソースを参照

pass-through stdin fd instead of content if not a terminal

Commit 299aea924ccef428219ed6f1a026c122678429e6 fixes the problem of
not logging terminal in case stdin & stdout are not a terminal. The
problem is that we are then trying to pass-through stdin content by
reading from the apt-process stdin and writing it to the stdin of the
child (dpkg), which works great for users who can control themselves,
but pipes and co are a bit less forgiving causing us to pass everything
to the first child process, which if the sending part of the pipe is
e.g. 'yes' we will never see the end of it (as the pipe is full at some
point and further writing blocks).

There is a simple solution for that of course: If stdin isn't a terminal,
we us the apt-process stdin as stdin for the child directly (We don't do
this if it is a terminal to be able to save the typed input in the log).

Closes: 773061
David Kalnischkies 11 年 前
コミット
748a2177dc
共有2 個のファイルを変更した32 個の追加6 個の削除を含む
  1. 12 4
      apt-pkg/deb/dpkgpm.cc
  2. 20 2
      test/integration/test-no-fds-leaked-to-maintainer-scripts

+ 12 - 4
apt-pkg/deb/dpkgpm.cc

@@ -73,7 +73,8 @@ public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
 			term_out(NULL), history_out(NULL),
 			term_out(NULL), history_out(NULL),
 			progress(NULL), tt_is_valid(false), master(-1),
 			progress(NULL), tt_is_valid(false), master(-1),
-			slave(NULL), protect_slave_from_dying(-1)
+			slave(NULL), protect_slave_from_dying(-1),
+			direct_stdin(false)
    {
    {
       dpkgbuf[0] = '\0';
       dpkgbuf[0] = '\0';
    }
    }
@@ -100,6 +101,7 @@ public:
    sigset_t sigmask;
    sigset_t sigmask;
    sigset_t original_sigmask;
    sigset_t original_sigmask;
 
 
+   bool direct_stdin;
 };
 };
 
 
 namespace
 namespace
@@ -1079,6 +1081,9 @@ void pkgDPkgPM::StartPtyMagic()
       return;
       return;
    }
    }
 
 
+   if (isatty(STDIN_FILENO) == 0)
+      d->direct_stdin = true;
+
    _error->PushToStack();
    _error->PushToStack();
 
 
    d->master = posix_openpt(O_RDWR | O_NOCTTY);
    d->master = posix_openpt(O_RDWR | O_NOCTTY);
@@ -1176,7 +1181,10 @@ void pkgDPkgPM::SetupSlavePtyMagic()
       _error->FatalE("ioctl", "Setting TIOCSCTTY for slave fd %d failed!", slaveFd);
       _error->FatalE("ioctl", "Setting TIOCSCTTY for slave fd %d failed!", slaveFd);
    else
    else
    {
    {
-      for (unsigned short i = 0; i < 3; ++i)
+      unsigned short i = 0;
+      if (d->direct_stdin == true)
+	 ++i;
+      for (; i < 3; ++i)
 	 if (dup2(slaveFd, i) == -1)
 	 if (dup2(slaveFd, i) == -1)
 	    _error->FatalE("dup2", "Dupping %d to %d in child failed!", slaveFd, i);
 	    _error->FatalE("dup2", "Dupping %d to %d in child failed!", slaveFd, i);
 
 
@@ -1596,8 +1604,8 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 
 
 	 // wait for input or output here
 	 // wait for input or output here
 	 FD_ZERO(&rfds);
 	 FD_ZERO(&rfds);
-	 if (d->master >= 0 && !d->stdin_is_dev_null)
-	    FD_SET(0, &rfds); 
+	 if (d->master >= 0 && d->direct_stdin == false && d->stdin_is_dev_null == false)
+	    FD_SET(STDIN_FILENO, &rfds);
 	 FD_SET(_dpkgin, &rfds);
 	 FD_SET(_dpkgin, &rfds);
 	 if(d->master >= 0)
 	 if(d->master >= 0)
 	    FD_SET(d->master, &rfds);
 	    FD_SET(d->master, &rfds);

+ 20 - 2
test/integration/test-no-fds-leaked-to-maintainer-scripts

@@ -11,8 +11,14 @@ configdpkgnoopchroot
 setupsimplenativepackage "fdleaks" 'all' '1.0' 'unstable'
 setupsimplenativepackage "fdleaks" 'all' '1.0' 'unstable'
 BUILDDIR="incoming/fdleaks-1.0"
 BUILDDIR="incoming/fdleaks-1.0"
 for script in 'preinst' 'postinst' 'prerm' 'postrm'; do
 for script in 'preinst' 'postinst' 'prerm' 'postrm'; do
-	echo '#!/bin/sh
-ls -l /proc/self/fd/' > ${BUILDDIR}/debian/$script
+	cat > ${BUILDDIR}/debian/$script << EOF
+#!/bin/sh
+if [ -e "$(pwd)/rootdir/tmp/read_stdin" ]; then
+	read line;
+	echo "STDIN: -\$line-"
+fi
+ls -l /proc/self/fd/
+EOF
 done
 done
 buildpackage "$BUILDDIR" 'unstable' 'main' 'native'
 buildpackage "$BUILDDIR" 'unstable' 'main' 'native'
 rm -rf "$BUILDDIR"
 rm -rf "$BUILDDIR"
@@ -99,3 +105,15 @@ checkinstall
 rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
 rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
 testsuccess runapt command setsid -w "${BUILDDIRECTORY}/apt-get" purge -y fdleaks -qq
 testsuccess runapt command setsid -w "${BUILDDIRECTORY}/apt-get" purge -y fdleaks -qq
 checkpurge
 checkpurge
+
+touch rootdir/tmp/read_stdin
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+for i in $(seq 1 10); do echo "$i"; done | testsuccess aptget install -y fdleaks -qq
+checkinstall
+testequal '2' grep -c '^STDIN: ' rootdir/var/log/apt/term.log
+
+rm -f rootdir/var/log/dpkg.log rootdir/var/log/apt/term.log
+yes '' | testsuccess runapt command setsid -w "${BUILDDIRECTORY}/apt-get" purge -y fdleaks -qq
+checkpurge
+testequal '3' grep -c '^STDIN: ' rootdir/var/log/apt/term.log