涉及程序: linux kernel 详细: 发现 LINUX 内核存在拒绝服务漏洞,本地攻击者建立多个深层次链接,当系统被要求处理这种链接时,将会消耗大量 CPU 资源,从而不能处理其它进程。 下面的 mklink.sh 测试脚本带参数N,会创建5个链接,每个含有 2*N+1 个路径元素,当 N=3 时: $ ls -lG drwxr-xr-x 2 nergal 4096 wrz 21 14:46 l lrwxrwxrwx 1 nergal 53 wrz 21 14:46 l0 -> l1/../l1/../l1/../l/../../../../../../../etc/services lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l1 -> l2/../l2/../l2/../l lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l2 -> l3/../l3/../l3/../l lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l3 -> l4/../l4/../l4/../l lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l4 -> l5/../l5/../l5/../l drwxr-xr-x 2 nergal 4096 wrz 21 14:46 l5 drwxr-xr-x 2 rybagowa 4096 lut 27 1999 still_here 命令 head l0 将消耗: N system time 10: sys 0m0.050s 20: sys 0m1.400s 30: sys 0m10.150s 40: sys 0m41.840s 受影响系统: Linux kernels 2.2.x, x<=19 and 2.4.y, y<=9 解决方案: 1、升级到内核 2.4.12 2、下载安装补丁 --- linux-2.2.19/fs/namei.c.orig Wed Oct 10 09:31:37 2001 +++ linux-2.2.19/fs/namei.c Wed Oct 10 10:30:56 2001 @@ -277,6 +277,15 @@ result->d_op->d_revalidate(result, flags); return result; } +/* + * Yes, this really increments the link_count by 5, and + * decrements it by 4. Together with checking against 25, + * this limits recursive symlink follows to 5, while + * limiting consecutive symlinks to 25. + * + * Without that kind of total limit, nasty chains of consecutive + * symlinks can cause almost arbitrarily long lookups. + */ static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow) { @@ -284,13 +293,17 @@ if ((follow & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { - if (current->link_count < 5) { + if (current->link_count < 25) { struct dentry * result; - current->link_count++; + if (current->need_resched) { + current->state = TASK_RUNNING; + schedule(); + } + current->link_count += 5; /* This eats the base */ - result = inode->i_op->follow_link(dentry, base, follow); - current->link_count--; + result = inode->i_op->follow_link(dentry, base, follow|LOOKUP_INSYMLINK); + current->link_count -= 4; dput(dentry); return result; } @@ -324,6 +337,8 @@ struct dentry * dentry; struct inode *inode; + if (!(lookup_flags & LOOKUP_INSYMLINK)) + current->link_count=0; if (*name == \`/\`) { if (base) dput(base); --- linux-2.2.19/include/linux/fs.h.orig Wed Oct 10 10:06:41 2001 +++ linux-2.2.19/include/linux/fs.h Wed Oct 10 10:07:58 2001 @@ -872,6 +872,7 @@ #define LOOKUP_DIRECTORY (2) #define LOOKUP_SLASHOK (4) #define LOOKUP_CONTINUE (8) +#define LOOKUP_INSYMLINK (16) extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int); extern struct dentry * __namei(const char *, unsigned int);