首页 -> 安全研究
安全研究
安全漏洞
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
浏览次数:7945
严重程度:0(网友投票)
绿盟科技给您安全的保障