首页 -> 安全研究

安全研究

安全漏洞
RUS-CERT安全公告200004-01: GNU Emacs 20

发布日期:2000-04-18
更新日期:2000-04-21

受影响系统:
Linux (包括libc和glibc)
FreeBSD (可能包括其他BSD变种)
HP-UX 10.x, 11.00
AIX 4
不受影响系统:
Solaris (Solaris运行时间库自动调整PTY的权限)
  根据源代码判断,Data General's DG/UX 似乎是不受影响的
描述:

1. slave PTYs 不适当的权限

   对于多用户环境危险性高,否则危险性一般。

   在上面列出的受影响系统中,如果利用内嵌的Lisp函数start-process
   创建一个新的子进程,Emacs并没有对slave PTY设备设置正确的权限。

   非特权的本地用户可以监听到Emacs送往子进程的数据并伪造来自子进
   程的应答。比如Emacs软件包中的Mailcrypt,它会通过这种数据通道
   传送 PGP passphrases。

   在Emacs Lisp语言中,应该使用 call-process 而不是使用 start-process。
   当然,并不是总是可以用call-process 代替 start-process 的,因为
   这两个函数并非完全一样,一个同步创建子进程,一个异步创建子进程。

   真正的解决办法需要修改Emacs的源代码,后面提供了针对 Emacs 20.6
   的补丁,它使得Emacs使用Unix98 PTYs。已知该补丁在下列系统上有效:

   Linux with glibc 2.1
   AIX 4.2
   HP-UX 11.00

   希望这个补丁也能用于 HP-UX 10.x 。在某些版本的 HP-UX 上,grantpt()
   并没有象期待的那样工作,该补丁对此做了修正。

   不幸的是,象 Linux libc5 和 glibc 2.0、FreeBSD 以及 AIX 3 缺乏对
   Unix98 的支持,这些系统需要一个完全不同的补丁,以及一个
   setuid-to-root的工具更改PTY的权限。没有计划对此做出修正,Unix98 PTYs
   已经被广泛采用,绝大多数Unix系统提供对它的支持,值得注意的是,个别
   BSD变种例外。有人提议在FreeBSD中对openpty()增强,使之针对slave TTY
   设置正确的权限,该提议被采纳了。

   将来的Emacs版本将包含类似的修正。

2. 临时文件不安全的创建

   所有的Unix系统上的Emacs在一个公共目录里存放临时文件

   对于多用户环境危险性高,否则危险性一般。

   Emacs Lisp 没有任何功能可以在一个公共可写的目录里安全地创建临时文件。
   许多Emacs软件包使用 make-temp-name Lisp 函数创建临时文件名,这些文件
   名不是非常难猜。因为无法安全地创建临时文件,常用的符号链接攻击手段很
   可能成功。

   Emacs 21 将提供一个新版的 make-temp-file 函数,它将询问是否以安全方
   式创建临时文件。在 Emacs 21 发布前,应该使用私有目录存放临时文件,绝
   大多数软件包提供环境变量设置私有目录,比如 Mailcrypt ,需要设置变量
   mc-temp-directory,对于 Python Mode,需要设置变量 py-temp-directory。

3. 最近一次输入的口令被保存在历史记录中

   所有的平台都存在这个问题,不过危险性不大。

   象 read-passwd 这样的函数并没有清除最近一次输入口令的历史记录,事实
   上无法通过 Emacs Lisp 达到清除目的。

   如果有人能够物理访问一个正在运行Emacs的控制台,口令就可能被他恢复得
   到并搅乱口令期限。通常,如果你能在一个foreign Emacs中输入Ctrl-h l,还
   有很多其他方法获得口令。


<*
漏洞发现者以及相关联结:

   < mailto: cert@uni-stuttgart.de >

   Helmut Waitzmann 重新发现PTY权限问题,并测试了 HP-UX 补丁。
   Emacs开发小组的Gerd Moellmann提供了补丁。
*>



建议:

下面的补丁是针对GNU Emacs 20.6的,注意你必须再次运行
autoconf,重新生成配置脚本,我们没有提供重新生成的配置
脚本的patch,因为它太大了。

diff --unified --recursive emacs-20.6-orig/configure.in emacs-20.6/configure.in
--- emacs-20.6-orig/configure.in Sat Feb 26 13:07:02 2000
+++ emacs-20.6/configure.in Fri Mar 10 19:13:05 2000
@@ -1636,6 +1636,11 @@
strerror fpathconf select mktime euidaccess getpagesize tzset setlocale \
utimes setrlimit setpgid getcwd shutdown strftime)


+# Check for UNIX98 PTYs.
+# getpt is a glibc addition which emulates the master device on
+# systems without kernel support.
+AC_CHECK_FUNCS(grantpt unlockpt getpt ptsname)
+
# Check this now, so that we will NOT find the above functions in ncurses.
# That is because we have not set up to link ncurses in lib-src.
# It's better to believe a function is not available
diff --unified --recursive emacs-20.6-orig/src/config.in emacs-20.6/src/config.in
--- emacs-20.6-orig/src/config.in Mon Apr 26 07:19:44 1999
+++ emacs-20.6/src/config.in Fri Mar 10 19:13:05 2000
@@ -235,6 +235,14 @@
#undef HAVE_SHUTDOWN
#undef HAVE_STRFTIME


+/* UNIX98 PTY support functions
+ getpt is a glibc addition which emulates the master device on
+ systems without kernel support. */
+#undef HAVE_GRANTPT
+#undef HAVE_UNLOCKPT
+#undef HAVE_GETPT
+#undef HAVE_PTSNAME
+
#undef LOCALTIME_CACHE
#undef HAVE_INET_SOCKETS


diff --unified --recursive emacs-20.6-orig/src/keyboard.c emacs-20.6/src/keyboard.c
--- emacs-20.6-orig/src/keyboard.c Thu Nov 18 05:57:32 1999
+++ emacs-20.6/src/keyboard.c Fri Mar 10 19:13:05 2000
@@ -8318,10 +8318,18 @@


DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
   Sclear_this_command_keys, 0, 0, 0,
- "Clear out the vector that `this-command-keys' returns.")
+ "Clear out the vector that `this-command-keys' returns.\n\
+Clear vector containing last 100 events.")
   ()
{
+ int i;
+
   this_command_key_count = 0;
+
+ for (i = 0; i < XVECTOR (recent_keys)->size; ++i)
+ XVECTOR (recent_keys)->contents[i] = Qnil;
+ total_keys = 0;
+ recent_keys_index = 0;
   return Qnil;
}


diff --unified --recursive emacs-20.6-orig/src/s/aix4.h emacs-20.6/src/s/aix4.h
--- emacs-20.6-orig/src/s/aix4.h Sat Jul 25 08:45:27 1998
+++ emacs-20.6/src/s/aix4.h Fri Mar 17 20:44:08 2000
@@ -12,3 +12,33 @@
/* Specify the type that the 3rd arg of `accept' points to.
    It is just a guess which versions of AIX need this definition. */
#define SOCKLEN_TYPE int
+
+#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME)
+/* UNIX98 PTYs are available.
+ Added by Florian Weimer <Florian.Weimer@RUS.Uni-Stuttgart.DE>,
+ RUS-CERT, University of Stuttgart. Based on Emacs code for DGUX. */
+
+/* Most of the #defines are already provided by aix3-1.h. */
+
+/* This sets the name of the slave side of the PTY. grantpt(3) and
+ unlockpt(3) may fork a subprocess, so keep sigchld_handler() from
+ intercepting that death. */
+
+#undef PTY_TTY_NAME_SPRINTF
+#define PTY_TTY_NAME_SPRINTF \
+ { \
+ char *ptsname(), *ptyname; \
+ \
+ sigblock(sigmask(SIGCHLD)); \
+ if (grantpt(fd) == -1) \
+ fatal("could not grant slave pty"); \
+ if (unlockpt(fd) == -1) \
+ fatal("could not unlock slave pty"); \
+ sigunblock(sigmask(SIGCHLD)); \
+ if (!(ptyname = ptsname(fd))) \
+ fatal ("could not enable slave pty"); \
+ strncpy(pty_name, ptyname, sizeof(pty_name)); \
+ pty_name[sizeof(pty_name) - 1] = 0; \
+ }
+
+#endif
diff --unified --recursive emacs-20.6-orig/src/s/gnu-linux.h emacs-20.6/src/s/gnu-linux.h
--- emacs-20.6-orig/src/s/gnu-linux.h Wed Jan 26 14:28:40 2000
+++ emacs-20.6/src/s/gnu-linux.h Fri Mar 17 20:44:31 2000
@@ -307,3 +307,49 @@
#ifdef DOUG_LEA_MALLOC
#undef REL_ALLOC
#endif
+
+#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME)
+/* UNIX98 PTYs are available.
+ Added by Florian Weimer <Florian.Weimer@RUS.Uni-Stuttgart.DE>,
+ RUS-CERT, University of Stuttgart. Based on Emacs code for DGUX. */
+
+#define PTY_ITERATION for (i = 0; i < 1; i++)
+/* no iteration at all */
+
+/* Use getpt() if it's available, because it provides Unix98 PTY
+ emulation for kernels which doesn't support it natively. */
+
+#ifdef HAVE_GETPT
+#define PTY_OPEN \
+ do { \
+ fd = getpt(); \
+ if (fcntl (fd, F_SETFL, O_NDELAY) == -1) \
+ fatal ("could not set master PTY to non-block mode"); \
+ } while (0)
+
+#else
+/* the master PTY device */
+#define PTY_NAME_SPRINTF strcpy (pty_name, "/dev/ptmx");
+#endif
+
+/* This sets the name of the slave side of the PTY. grantpt(3) and
+ unlockpt(3) may fork a subprocess, so keep sigchld_handler() from
+ intercepting that death. */
+
+#define PTY_TTY_NAME_SPRINTF \
+ { \
+ char *ptsname(), *ptyname; \
+ \
+ sigblock(sigmask(SIGCHLD)); \
+ if (grantpt(fd) == -1) \
+ fatal("could not grant slave pty"); \
+ if (unlockpt(fd) == -1) \
+ fatal("could not unlock slave pty"); \
+ if (!(ptyname = ptsname(fd))) \
+ fatal ("could not enable slave pty"); \
+ strncpy(pty_name, ptyname, sizeof(pty_name)); \
+ pty_name[sizeof(pty_name) - 1] = 0; \
+ sigunblock(sigmask(SIGCHLD)); \
+ }
+
+#endif
diff --unified --recursive emacs-20.6-orig/src/s/hpux.h emacs-20.6/src/s/hpux.h
--- emacs-20.6-orig/src/s/hpux.h Mon Jan 15 10:16:40 1996
+++ emacs-20.6/src/s/hpux.h Wed Mar 29 08:40:52 2000
@@ -228,6 +228,59 @@
/* This is needed for HPUX version 6.2; it may not be needed for 6.2.1. */
#define SHORT_CAST_BUG


+#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME)
+/* UNIX98 PTYs are available.
+ Added by Florian Weimer <Florian.Weimer@RUS.Uni-Stuttgart.DE>,
+ RUS-CERT, University of Stuttgart. Based on Emacs code for DGUX. */
+
+#ifdef emacs
+#include <grp.h>
+#include <sys/stropts.h>
+#endif
+
+#define PTY_ITERATION for (i = 0; i < 1; i++)
+/* no iteration at all */
+
+/* the master PTY device */
+#define PTY_NAME_SPRINTF strcpy (pty_name, "/dev/ptmx");
+
+/* This sets the name of the slave side of the PTY. grantpt(3) and
+ unlockpt(3) may fork a subprocess, so keep sigchld_handler() from
+ intercepting that death. grantpt() behavior on HP-UX differs from
+ what's specified in the man page: the group of the slave PTY is set
+ to the user's primary group, and we fix that. */
+
+#define PTY_TTY_NAME_SPRINTF \
+ { \
+ char *ptsname(), *ptyname; \
+ struct group *getgrnam (), *tty_group = getgrnam ("tty"); \
+ if (tty_group == NULL) \
+ fatal ("group tty not found"); \
+ \
+ sigblock(sigmask(SIGCHLD)); \
+ if (grantpt(fd) == -1) \
+ fatal("could not grant slave pty"); \
+ if (!(ptyname = ptsname(fd))) \
+ fatal ("could not enable slave pty"); \
+ strncpy(pty_name, ptyname, sizeof(pty_name)); \
+ pty_name[sizeof(pty_name) - 1] = 0; \
+ if (chown (pty_name, (uid_t) -1, tty_group->gr_gid) == -1) \
+ fatal ("could not chown slave pty"); \
+ if (unlockpt(fd) == -1) \
+ fatal("could not unlock slave pty"); \
+ sigunblock(sigmask(SIGCHLD)); \
+ }
+
+/* Push various streams modules onto a PTY channel. */
+
+#define SETUP_SLAVE_PTY \
+ if (ioctl (xforkin, I_PUSH, "ptem") == -1) \
+ fatal ("ioctl I_PUSH ptem", errno); \
+ if (ioctl (xforkin, I_PUSH, "ldterm") == -1) \
+ fatal ("ioctl I_PUSH ldterm", errno);
+
+#else /* no UNIX98 PTYs */
+
/* This is how to get the device name of the tty end of a pty. */
#define PTY_TTY_NAME_SPRINTF \
             sprintf (pty_name, "/dev/pty/tty%c%x", c, i);
@@ -235,6 +288,8 @@
/* This is how to get the device name of the control end of a pty. */
#define PTY_NAME_SPRINTF \
         sprintf (pty_name, "/dev/ptym/pty%c%x", c, i);
+
+#endif /* UNIX 98 PTYs */


/* This triggers a conditional in xfaces.c. */
#define XOS_NEEDS_TIME_H



浏览次数:7926
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障