读者来信
2001 年 8 月刊 LJ 的 At the Forge 专栏是关于 Enhydra 的一个功能。Enhydra 是商业软件,基于 Java,而 Java 也是商业软件。据我所见,文章中没有提到 Linux 或任何特定于 Linux 的内容。这篇文章放在名为 Web Automation 的杂志上也不会显得格格不入,但我不知道为什么它会出现在一本致力于 Linux,更广泛地说,致力于自由软件的杂志中。
—Carl Fink
Reuven 回复: 虽然 Java 不是自由软件,但许多 Web 开发人员想要或需要在其工作中使用 Java。我无法更改 Java 许可证,但我可以鼓励 Java 开发人员使用开源操作系统 (Linux) 和开源应用服务器 (Enhydra)。据我所知,有两种不同的方法可以获得 Enhydra。第一种是获取核心 Enhydra 应用服务器,它是可以免费下载和分发的。这包括 XMLC、DODS、超级 Servlet 以及所有其他内容。尽管您可能在 Enhydra 网站上的其他地方读到过不同的说法,但其许可协议确实是开源的。以下是关于许可方案的三个 URL:www.enhydra.org/aboutEnhydra/index.html,enhydra.enhydra.org/software/license/rationale.htm 和 enhydra.enhydra.org/software/license/opl.html。第二种方法是获取 Lutris EAS(Enhydra 应用服务器),它是开源软件的商业打包和测试版本。我相信您需要为 EAS 支付每个 CPU 995 美元(或更多),但您支付的是支持费用,而不是服务器本身,这是开源模式的一种变体。您也可以争辩说,我关于 PostgreSQL 的文章并非专门关于 Linux,但事实是,有很多人有兴趣在 Linux 上使用该数据库。无论好坏,都有许多 Linux 爱好者也希望能够使用 Java。事实上,作为每天(和许多夜晚)在 Linux 上进行 Web 开发的人,我很高兴知道我现在可以与客户谈论超越 Jakarta-Tomcat 的严肃的 Java 和 EJB 解决方案。
我非常喜欢 William Benton 在 2001 年 9 月刊 Linux Journal 上发表的“可加载内核模块利用”一文。我知道这类文章并非旨在详尽无遗,但在第 26 页的“检查和日志功能列表”中,我发现一个我认为至关重要的错误。代码通过保存 SYS_write 的当前地址并替换它来钩入 sys_call_table。它通过放回保存的地址来取消钩入。错误在于是否存在多个这样的钩子。如果另一个模块在本模块之后钩住 SYS_write 条目,则对此模块执行 rmmod,另一个模块将被取消钩入。
甚至可能出现更糟糕的情况:1) 模块 A 被 insmod-ed 并钩住 SYS_write。SYS_write 指向模块 A 中的 wrapped_write,orgwrite 指向前一个内容(假设它是正常条目)。2) 现在模块 B 执行相同的操作。SYS_write 指向,例如,模块 B 中的 modified_write,orgwrite 指向模块 A 中的 wrapped_write。3) 模块 A 被 rmmod-ed。SYS_write 现在包含原始 SYS_write 值。但这表示模块 B 中的 modified_write 现在被绕过。4) 现在模块 B 被 rmmod-ed。模块 B 中的 cleanup_module 将恢复 SYS_write 表条目,使其指向模块 A 曾经驻留的位置。5) Linux 很可能会崩溃。
不幸的是,我并不是真正的内核黑客,所以我不知道如何告诉 rmmod 函数我不希望被删除。为了安全起见,您需要以与 insmod-ed 相反的顺序执行 rmmod。我对 Linux 的了解不足以说明如何实现这一点。
—John McKown
Benton 回复: 您是对的;如果您系统管理员不够小心,您描述的情况可能会成为生产代码的问题。我没有假设这在示例代码(或有警惕的系统管理员的生产代码)中会成为严重问题,但很高兴能够识别内核编程中可能存在的陷阱。一个(简单的)解决方案是小心加载和卸载的内容以及顺序。正如老笑话所说:“医生,我这样做时会疼!”“好吧,那就别那样做了!”。有很多方法可以使您的系统崩溃,一旦您识别出所有这些方法,最好避免所有这些方法。认真地说,只要 Linux 不提供注册系统调用表更改的机制,这些问题就会存在。我不认为它们非常严重,因为用户的一定程度的谨慎可以防止崩溃。但是,有一种解决方法可以为您提供一些基本的稳定性:在 cleanup_module() 中,请务必检查您即将恢复的系统调用表条目是否是您认为应该的条目。如果不是,则发出警告并在修改系统调用表之前调用 sync() 系统调用。这将最大限度地减少崩溃事件中的损害。作为一种替代方案(也是更困难的解决方案),您可以在加载的第一个模块中替换 create_module 系统调用,将其包装在一个为静态堆栈或双端队列中的系统调用表提供某种版本控制系统的调用中。我将把实现它作为留给读者的练习。
Robin,我在 LinuxWorld 上拿到了一本 Linux Journal,并阅读了您关于梦工厂的文章——那次访问一定很棒!
鉴于您在那里看到的以及可能已经知道的,我想问您是否可以提供一些建议。我有一个十几岁的儿子,他对动画非常感兴趣,但是用于制作动画的应用程序非常昂贵。您能否推荐一些更经济实惠的基于 Linux 的渲染应用程序?
—Jack C.
Robin 回复: Jack,我们在梦工厂玩得很开心。但梦工厂只是第一个。所有工作室都在进行 Linux 迁移项目。
您可能想从 Blender 开始,Blender 是一款流行的、免费分发的 3D 建模软件包,用于动画、渲染、交互式 3D 和游戏创建。与大多数免费动画工具不同,Blender 有印刷书籍可供参考。其他可能感兴趣的工具包括 K-3D、Ayam、AC3D、Flow、Radiance 和 BMRT。您可以通过在 Freshmeat.net 上搜索找到它们的网页
在 2001 年 9 月刊 LJ 的文章“可加载内核模块利用”中,我对劫持 sys_call_table 指针并在您自己的函数中包装它的技术很感兴趣。在美好的旧时代,我过去在 DOS 中做过非常相似的事情,编写 TSR(Terminate and Stay Resident)和其他“借用” bios 或 dos 中断向量的程序。
对于程序来说,恢复原始中断向量(指针)很简单,但是对于 TSR 来说,在恢复原始指针之前必须小心。问题是,如果安装了多个 TSR 实用程序,则两个实用程序可能会劫持同一个中断(通常是键盘)。一个正确编写的 TSR 在卸载之前会检查当前指针是否确实指向自身,如果不是,则它无法卸载,因为这样做会破坏另一个稍后安装的 TSR。
文章中的 cleanup_module(void) 例程在恢复 sys_call_table[SYS_write] 指针之前没有执行此类检查,乍一看,这在多任务环境中对我来说似乎很危险,尤其是在内核可以自动加载和卸载模块的环境中。
—John Jacq