讲解高级 Linux 挂载特性的实际应用
如果能够让用户自由地创建他们的文件系统,而不受系统管理员指定的结构的限制,那么会怎么样?用户可以导出自己的文件系统树的一部分,并将其他用户导出的文件系统树导入自己的树中。本文向 Linux® 系统管理员介绍用挂载传播实现这种设置的详细步骤。<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
有时候,Linux® 中的文件系统是一个相当简单的树。进程可以对本身执行 chroot()
,使其文件系统树的根成为系统文件系统根的一个子目录。在树中的任何节点上,可以用来自新设备的树覆盖文件系统。
在 2000 年,Al Viro 为 Linux 引入了绑定挂载和文件系统名称空间:
- 绑定挂载(bind mount)允许从任何其他位置访问任何文件或目录。
- 文件系统名称空间(filesystem namespace)是与不同进程相关联的完全独立的文件系统树。
clone(2) Linux 手册页指出: clone(2) 系统调用创建一个新的子进程,它让子进程可以与执行调用的进程共享它的执行上下文的某些部分,比如内存空间、文件描述符表和信号处理函数表。细节参见 参考资料。 |
在执行 clone(2)
时,进程请求它当前的文件系统树的拷贝(更多信息见 参考资料);在此之后,新进程就拥有与原进程的文件系统树相同的拷贝。在建立拷贝之后,在这两个树中的任何挂载操作都不会影响另一个拷贝。
尽管每个进程使用单独的文件系统名称空间在理论上非常有意义,但是在实践中,完全隔离它们会造成较大的限制性。进程克隆了系统的文件系统名称空间之后,已经运行的系统守护进程无法为这个用户自动挂载 CD-ROM,因为在原文件系统名称空间中执行的挂载无法影响用户的拷贝。
2006 年引入的挂载传播(mount propagation)解决了这个问题,挂载传播定义了挂载对象之间的关系。系统用这些关系决定任何挂载对象中的挂载事件如何传播到其他挂载对象:
- 如果两个挂载对象具有共享关系,那么一个挂载对象中的挂载事件会传播到另一个挂载对象,反之亦然。
- 如果两个挂载对象形成从属(slave)关系,那么一个挂载对象中的挂载事件会传播到另一个挂载对象,但是反过来不行;在这种关系中,从属对象是事件的接收者。
传播事件的挂载对象称为共享挂载(shared mount);接收挂载事件的挂载对象称为从属挂载(slave mount)。既不传播也不接收挂载事件的挂载对象称为私有挂载(private mount)。另一种特殊的挂载对象称为不可绑定的挂载(unbindable mount),它们与私有挂载相似,但是不允许执行绑定挂载。不可绑定的挂载对于快速增长挂载对象尤其有意义(后面会进一步讨论这个概念)。
在默认情况下,所有挂载都是私有的。可以用以下命令将挂载对象显式地标为共享挂载:
mount --make-shared <mount-object> |
例如,如果 /
上的挂载必须是共享的,那么执行以下命令:
mount --make-shared / |
从共享挂载克隆的挂载对象也是共享的挂载;它们相互传播挂载事件。
通过执行以下命令,可以显式地将一个共享挂载转换为从属挂载:
mount --make-slave <shared-mount-object> |
从从属挂载克隆的挂载对象也是从属的挂载,它也从属于原来的从属挂载的主挂载对象。
通过执行以下命令,可以将挂载对象标为私有的:
mount --make-private <mount-object> |
通过执行以下命令,可以将挂载对象标为不可绑定的:
mount --make-unbindable <mount-object> |
最后,这些设置都可以递归地应用,这意味着它们将应用于目标挂载之下的所有挂载。
例如:
mount --make-rshared / |
将 /
之下的所有挂载转换为共享挂载。
每个登录专用的名称空间
清单 1 给出一个 PAM(pluggable authentication module,可插入身份验证模块)的部分代码,它将除根用户之外的每个用户放在一个私有名称空间中。如果 /tmp/priv/USER 目录存在,那么这个目录将被绑定挂载在用户的私有名称空间中的 /tmp 上。
清单 1. 实现每个登录专用的名称空间的 PAM 代码片段
#define DIRNAMSZ 200 int handle_login(const char *user) { int ret = 0; struct stat statbuf; char dirnam[DIRNAMSZ]; if (strcmp(user, "root") == 0) return PAM_SUCCESS; ret = unshare(CLONE_NEWNS); if (ret) { mysyslog(LOG_ERR, "failed to unshare mounts for %s\n", user); return PAM_SESSION_ERR; } snprintf(dirnam, DIRNAMSZ, "/tmp/priv/%s", user); ret = stat(dirnam, &statbuf); if (ret == 0 && S_ISDIR(statbuf.st_mode)) { ret = mount(dirnam, "/tmp", "none", MS_BIND, NULL); if (ret) { mysyslog(LOG_ERR, "failed to mount tmp for %s\n", user); return PAM_SESSION_ERR; } } else mysyslog(LOG_INFO, "No private /tmp for user %s\n", user); return PAM_SUCCESS; } int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *PAM_user = NULL; char *fnam; int ret; ret = pam_get_user(pamh, &PAM_user, NULL); if (ret != PAM_SUCCESS) { mysyslog(LOG_ERR, "PAM-NS: couldn't get user\n"); return PAM_SESSION_ERR; } return handle_login(PAM_user); } |
要想使用这个 PAM 模块,可以从后面的 下载 一节下载完整的 pam_ns.c 文件和对应的 makefile。编译它并将生成的 pam_ns.so 文件复制到 /lib/security/ 中。然后在 /etc/pam.d/login 和 /etc/pam.d/sshd 中添加以下条目:
session required pam_ns.so |
最后,为用户 USER
创建一个私有的 tmp 目录。
mkdir /tmp/priv chmod 000 /tmp/priv mkdir /tmp/priv/USER chown -R USER /tmp/priv/USER |
现在,以根用户身份在一个终端上登录,以 USER
用户身份在另一个终端上登录。作为 USER
执行以下命令:
touch /tmp/ab ls /tmp |
注意,USER
的 /tmp 只包含新创建的文件。
接下来,在根用户的终端上列出 /tmp 的内容清单;注意,这里有其他文件,但是没有 /tmp/ab。这些 /tmp 目录实际上是单独的目录。要想在根用户的终端上访问 USER
的 /tmp 目录,应该执行:
ls /tmp/priv/USER |
这时会看到文件 ab。接下来,在根用户的终端上,在 /mnt 上挂载某些东西:
mount --bind /dev /mnt |
mount(8) 和 unshare(2) Linux 手册页指出: mount(8) 命令将某一设备上的文件系统附着到一个大文件树上。unshare(2) 系统调用允许进行调用的进程用原名称空间的拷贝替代所选资源的名称空间。参见 参考资料。 |
注意,在根用户的终端上,/dev 的内容出现在 /mnt 下面,但是在 USER
的终端上没有出现。这两个终端的挂载树是完全独立的。可以使用 mount(8)
命令获得与挂载传播相关的指令。在默认情况下,所有挂载都是私有的。所以,在作为 USER
登录之前,可以执行以下命令:
mount --make-rshared / |
在此之后,挂载事件就会在后面的非共享名称空间之间传播。但是,在 USER
登录之后,将 /tmp/priv/USER 挂载到 /tmp 的事件不应该传播到父名称空间。为了解决这个问题,pam_ns.so 可以将它的文件系统标为从属对象,见清单 2。
清单 2. 将用户的名称空间标为从属对象的 PAM 模块
#define DIRNAMSZ 200 #ifndef MS_SLAVE #define MS_SLAVE 1<<19 #endif #ifndef MS_REC #define MS_REC 0x4000 #endif int handle_login(const char *user) { int ret = 0; struct stat statbuf; char dirnam[DIRNAMSZ]; if (strcmp(user, "root") == 0) return PAM_SUCCESS; ret = unshare(CLONE_NEWNS); if (ret) { mysyslog(LOG_ERR, "failed to unshare mounts for %s\n", user); return PAM_SESSION_ERR; } ret = mount("", "/", "dontcare", MS_REC|MS_SLAVE, "")); if (ret) { mysyslog(LOG_ERR, "failed to mark / rslave for %s\n", user); return PAM_SESSION_ERR; } snprintf(dirnam, DIRNAMSZ, "/tmp/priv/%s", user); ret = stat(dirnam, &statbuf); if (ret == 0 && S_ISDIR(statbuf.st_mode)) { ret = mount(dirnam, "/tmp", "none", MS_BIND, NULL); if (ret) { mysyslog(LOG_ERR, "failed to mount tmp for %s\n", user); return PAM_SESSION_ERR; } } else mysyslog(LOG_INFO, "No private /tmp for user %s\n", user); return PAM_SUCCESS; } |
每个用户专用的根
LSPP 共同准则 Labeled Security Protection Profile 为 IT 产品指定了一组安全功能和保障需求。它支持两类访问控制机制,这些机制允许用户指定如何共享他们控制的资源(通过安全标志或 “标签” 来实施),还可以对用户之间的共享实施限制。LSPP 提供的保护级别适合于 “非敌对性的管理良好的用户社区,可以防止意外操作破坏系统安全”。参见 参考资料。 |
在 每个登录专用的名称空间 一节中,我们看到了一个通过挂载名称空间为用户提供私有名称空间的简单示例。通过使用挂载传播,这个解决方案非常适合为用户提供私有的 /tmp 目录;如果再添加一个由 pam_ns.c 解析的配置文件,就可以根据用户对其他目录进行重定向。LSPP 就是以这种方式提供多个实例化的主目录,它会根据登录过程的许可在 /home/USER 上挂载不同的目录。
但是,同一用户的每次登录都会获得一个私有的从属文件系统。所以这个用户在一个登录会话中执行的挂载不影响另一个登录会话。
非管理员用户可以以几种方式挂载文件系统。例如,用户可以使用 FUSE 挂载 sshfs(安全 shell)文件系统或 loopback 文件系统(见 参考资料)。如果不考虑本文后面讨论的用户之间的挂载共享问题,就不容易理解这些挂载如何只出现在用户的一个登录终端中,而不出现在其他终端中。但是,通过使用 “每个登录专用的名称空间” 一节中的方法,确实可以实现这种效果。
清单 3 给出 pam_chroot.so PAM 模块的部分代码。pam_ns.so 在登录时克隆挂载名称空间,但是 pam_chroot.so 模块需要在 /share/USER/root 下设置一个用户专用的文件系统,并使用 chroot()
将用户限制在他的私有文件系统中。
清单 3. 使用 chroot() 的 PAM 模块
int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *PAM_user = NULL; char fnam[400]; int ret, err, count, i; struct mount_entries *entries; struct stat statbuf; ret = pam_get_user(pamh, &PAM_user, NULL); if (ret != PAM_SUCCESS) { mysyslog(LOG_ERR, "PAM-MOUNT: couldn't get user\n"); return PAM_SESSION_ERR; } /* check whether /share/$pam_user/root exists. If so, chroot to it */ sprintf(fnam, "/share/%s/root", PAM_user); ret = stat(fnam, &statbuf); if (ret == 0 && S_ISDIR(statbuf.st_mode)) { ret = chroot(fnam); if (ret) { mysyslog(LOG_ERR, "PAM-MOUNT: unable to chroot to %s\n", fnam); return PAM_SESSION_ERR; } } return PAM_SUCCESS; } |
在这个示例中,在系统启动时提前执行所有挂载。例如,在启动之后,执行:
mkdir -p /share/USER/root mount --make-rshared / mount --rbind / /share/USER/root mount --make-rslave /share/USER/root mount --bind /share/USER/root/tmp/priv/USER /share/USER/root/tmp |
这里没有使用私有名称空间。相反,USER
的每次登录都通过 chroot()
限制在同一个目录(/share/USER/root)中。因此,在 USER
的所有登录中,会看到他的任何登录所执行的任何挂载。而 OTHERUSER
通过 chroot()
限制在 /share/OTHERUSER/root 中,因此不会看到 USER
的挂载活动。
这种方法的一个缺点是,可以回避普通的 chroot()
机制(虽然这需要某些特权)。例如,在具有某些特权(包括 CAP_SYS_CHROOT)的情况下,程序可以回避 chroot()
(参见 参考资料),这会导致程序能够访问真正的文件系统根。根据使用用户专用文件系统树的实际意图的不同,这可能会成为一个问题。
pivot_root(2) 和 chroot(2) Linux 手册页指出: pivot_root(2) 命令将当前进程的根文件系统转移到目录 put_old,并使 new_root 成为新的当前进程根文件系统。chroot(2) 命令将根目录改为路径中指定的目录;当前进程的所有子进程都继承这个根目录。只有具有特权的进程可以调用这个命令。参见 参考资料。 |
解决这个问题的方法是,在私有名称空间中使用 pivot_root(2)
(而不是 chroot(2)
)将登录的根目录改为 /share/USER/root。chroot()
仅仅将进程的文件系统根指向一个指定的新目录,而 pivot_root()
会使指定的 new_root 目录(它必须是一个挂载)脱离它的挂载点,然后将它附着到进程的根目录。因为在挂载树中新的根目录没有父目录,所以无法像使用 chroot()
时那样欺骗系统,从而访问真正的文件系统根。我们将使用 pivot_root()
方式。
用户专用根目录的系统设置
您已经看到了用户专用私有挂载树的实现细节,包括在登录时必须执行的操作。在本节中,将看到在创建用户帐户和系统引导时使用的完整脚本。
清单 4 给出在创建用户时运行的脚本。
清单 4. 用于创建用户的脚本
create_user_tree { user = $1 mkdir /user/$user mount --rbind / /user/$user mount --make-rslave /user/$user mount --make-rshared /user/$user #create a private mount. This is to facilitate pivot_root #to temporarily place the old root here before detaching the #entire old root tree. NOTE: pivot_root will not allow old root #to be placed under a shared mount. pushd /user/$user/ mkdir -p __my_private_mnt__ mount --bind __my_private_mnt__ __my_private_mnt__ mount --make-private __my_private_mnt__ popd } |
这个脚本假设已经运行了 init_per_user_namespace 脚本(后面会讨论这个脚本)。它在 /user/ 下面为用户帐户创建一个目录。然后将根目录递归地绑定挂载在 /user/$user/ 下面。这个递归复制的根文件系统树成为这个用户专用的文件系统,可以持久地保留这个用户执行的挂载活动(对多次登录有效,但是在重新启动之后就会失效)。
这个复制的树是根树的从属挂载,所以根树中的挂载活动会传播到这个拷贝,但是不会反向传播。这个树被标为共享的,所以后续的拷贝(也就是通过名称空间克隆建立的拷贝)是相互共享的挂载;任何拷贝中的挂载活动都会传播到所有其他拷贝。
最后,创建一个私有的挂载 __my_private_mnt__。这是为了帮助 pivot_root()
(见清单 6)在删除树之前临时准备根挂载。目前不需要太关注它。了解了 pivot_root()
的语义之后,这个步骤的意义就会明确了。目前只需记住,如果准备的挂载是共享的,那么 pivot 挂载就不会成功。
清单 5 给出在系统引导时运行的脚本。
清单 5. 在引导时执行系统初始化的脚本
init_per_user_namespace { #start with a clean state by marking #all mounts as private. mount --make-rprivate / #create a unbindable mount called 'user' #and have all the users to bind the entire #system tree '/' under them. mkdir /user mount --bind /user /user mount --make-rshared / mount --make-unbindable /user foreach user in existing_user { create_user_tree $user } } |
它创建 /user 目录,用户专用的挂载树将放在这个目录中。然后,它将 /user 绑定挂载到本身。--rshared
等挂载传播指令只能针对挂载点指定。这个步骤确保在 /user 上存在挂载点。
接下来,将文件系统根标为 --rshared
,这样的话以后的拷贝(包括通过绑定挂载或克隆挂载名称空间创建的拷贝)都与这个挂载相互共享,任何树中的挂载操作都会传播到所有共享挂载。
接下来,将 /user 上的挂载标为不可绑定的。对于每个用户,都会递归地复制整个挂载树,所以在 /user/$user_1 下面创建第一个用户的拷贝之后,在 /user/$user_2 下面创建的拷贝会包含 /user/$user_1 的递归拷贝(/user/$user_2/user/$user_1)。可以想像到,这会快速地消耗大量内存。将 /user 标为不可绑定的,就可以防止在递归地绑定挂载 / 时复制 /user。
最后,为每个用户执行一次 清单 4 中的脚本。如果 /user/$user 目录不存在,就创建这个目录,并按照前面的描述设置适当的挂载传播。
清单 6 给出在用户登录时执行的 PAM 模块的片段。
清单 6. 用户登录所用的 PAM 代码片段
#ifndef MNT_DETACH #define MNT_DETACH 0x0000002 #endif #ifndef MS_REC #define MS_REC 0x4000 #endif #ifndef MS_PRIVATE #define MS_PRIVATE 1<<18 /* Private */ #endif #define DIRNAMSZ 200 int handle_login(const char *user) { int ret = 0; struct stat statbuf; char dirnam[DIRNAMSZ], oldroot[DIRNAMSZ]; snprintf(dirnam, DIRNAMSZ, "/user/%s", user); ret = stat(dirnam, &statbuf); if (ret != 0 || !S_ISDIR(statbuf.st_mode)) return PAM_SUCCESS; ret = unshare(CLONE_NEWNS); if (ret) { mysyslog(LOG_ERR, "failed to unshare mounts for %s, error %d\n", user, errno); return PAM_SESSION_ERR; } ret = chdir(dirnam); if (ret) { mysyslog(LOG_ERR, "failed to unshare mounts for %s, error %d\n", user, errno); return PAM_SESSION_ERR; } snprintf(oldroot, DIRNAMSZ, "%s/__my_private_mnt__", dirnam); ret = pivot_root(dirnam, oldroot); if (ret) { mysyslog(LOG_ERR, "failed to pivot_root for %s, error %d\n", user, errno); mysyslog(LOG_ERR, "pivot_root was (%s,%s)\n", dirnam, oldroot); return PAM_SESSION_ERR; } ret = mount("", "/__my_private_mnt__", "dontcare", MS_REC|MS_PRIVATE, ""); if (ret) { mysyslog(LOG_ERR, "failed to mark /tmp private for %s, error %d\n", user, errno); return PAM_SESSION_ERR; } ret = umount2("/__my_private_mnt__", MNT_DETACH); if (ret) { mysyslog(LOG_ERR, "failed to umount old_root %s, error %d\n", user, ret); return PAM_SESSION_ERR; } return PAM_SUCCESS; } |
这个模块首先检查正在登录的用户的 /user/USER 树是否存在。如果这个树不存在,那么这个模块仅仅允许这个用户登录,而不执行任何其他操作。
如果 /user/USER 树存在,那么第一步是为这个登录进程下的任务克隆一个私有的名称空间。因此,这些进程会有自己的系统初始挂载树拷贝。但是,这些拷贝互不相连;复制的树中的每个挂载节点共享初始节点中对应的挂载节点。
接下来,登录进程使用 pivot_root()
将它的文件系统根改为 /user/$user。原来的根被挂载在新的 __my_private_mnt__ 下面。
下一步是将 __my_private_mnt__ 标为私有的,使后面的卸载操作不会传播到根挂载树的其他拷贝,包括原来的树。
最后,从 __my_private_mnt__ 卸载原来的根。
在用户创建脚本(见 清单 4 )中,将 __my_private_mnt__ 目录设置为私有的挂载,并指出这是为了辅助 pivot_root()
的操作。这么做实际上是由于 pivot_root()
有一个文档中没有记载的限制,这个限制与旧根和新根的挂载传播状态有关。要想让 pivot_root()
成功执行,以下挂载不能是共享对象:
- 旧根的目标位置
- 新根的当前父位置(在调用
pivot_root()
的时候) - 新根的目标父位置
在 清单 4 中接近末尾的地方将 __my_private_mnt__ 标为私有的,就可以满足第一个条件。第二个条件已经满足了,因为新根的当前父位置是 /user,/user 上的挂载是一个不可绑定的挂载。第三个条件也已经满足了,因为新根的目标父位置就是当前根的父位置。这个挂载是一个不可见的 rootfs 挂载,它已经是私有的。
在本节中,讨论了如何实现每个用户专用的挂载树,让挂载事件在一个用户的所有登录会话之间共享,但是对其他用户隐藏。在下一节中,讨论如何允许用户相互共享挂载树。
可以选择性共享每个用户专用的挂载树
我们已经讨论了每个用户专用的挂载树;现在讨论如何允许用户选择一部分挂载树在用户之间共享。下面是一个用于系统引导的脚本。
清单 7. 用于系统引导的脚本
init_per_user_namespace { mkdir -p /user/slave_tree mkdir -p /user/share_tree #start with a clean state. Set all mounts to private. mount --make-rprivate / mount --bind /user /user mount --bind /user/share_tree /user/share_tree mount --bind /user/slave_tree /user/slave_tree mount --make-rshared / mount --make-unbindable /user for user in `cat /etc/user_list`; do sh /bin/create_user_tree $user done } |
首先创建一个 /user 挂载,它包含每个用户的根目录。然后,在 /user 下面创建另一个称为 /user/share_tree 的目录,其中包含每个用户可以与其他用户共享的挂载。还创建一个 /user/slave_tree 目录,其中的挂载由每个用户共享,但是不接受来自其他用户的任何修改。当然,为了包含非绑定挂载,我们将 /user 下面的挂载标为不可绑定的。最后,调用 create_user_tree 为每个用户创建挂载树。
清单 8 给出了创建挂载树并允许其他用户共享挂载涉及的步骤。
清单 8. 用于创建用户的脚本
create_user_tree { user = $1 mkdir -p /user/$user #copy over the entire mount tree under /user/$user mount --rbind / /user/$user make --make-rslave /user/$user make --make-rshared /user/$user cd /user/$user/home/$user #export my shared exports mkdir -p my_shared_exports chown $user my_shared_exports mount --bind my_shared_exports my_shared_exports mount --make-private my_shared_exports mount --make-shared my_shared_exports mkdir -p /user/share_tree/$user mount --bind my_shared_exports /user/share_tree/$user #export my slave exports mkdir -p my_slave_exports chown $user my_slave_exports mount --bind my_slave_exports my_slave_exports mount --make-private my_slave_exports mount --make-shared my_slave_exports mkdir -p /user/slave_tree/$user mount --bind my_slave_exports /user/slave_tree/$user cd /user/$user #import everybody's shared exports mkdir -p others_shared_exports mount --rbind /user/share_tree others_shared_exports #import everybody's slave exports mkdir -p others_slave_exports mount --rbind /user/slave_tree others_slave_exports mount --make-rslave others_slave_exports #setup a private mount in the user's tree, This is to facilitate # pivot_mount executed later, during new user-logins. mkdir -p __my_private_mnt__ mount --bind __my_private_mnt__ __my_private_mnt__ mount --make-private __my_private_mnt__ } |
首先,在 /user/$user 下复制整个挂载树。在用户的树中,创建一个共享的挂载 my_shared_exports,在 /user/share_tree/$user 下复制它,从而导出给所有用户。同样,在用户的树中创建 my_slave_exports,在 /user/slave_tree/$user 下复制它,从而导出给所有用户。这里的关键思想是,用户可以选择在 my_shared_tree 下挂载的内容,所有其他用户会自动地共享这些挂载。
接下来,复制 /user/share_tree 下的挂载树并将它挂载在正在登录的用户的 others_shared_exports 下,这样就导入了所有其他用户的共享挂载。同样,复制 /user/slave_tree 下的挂载树并将它挂载在 others_slave_exports 下,这样就导入了所有其他用户的从属挂载。当然,因为这些挂载由导出者以从属挂载的形式导出,所以我们将它们转换为从属挂载。
完成了实现共享所需的设置步骤之后,用户登录算法就与 清单 6 中一样了。在每次登录时,用户会获得一个完全相同的挂载树;同时,用户会在 /others_shared_export 和 /others_slave_exports 下分别看到其他所有用户导出的所有共享挂载和从属挂载。
如果用户希望向其他用户导出某些内容,那么只需将这些内容挂载在 my_shared_exports 下,所有用户就能够自动地看到它们。
描述 | 名字 | 大小 | 下载方法 |
---|---|---|---|
本文的挂载传播代码示例 | dw.mountscode.tgz | 3KB | HTTP |
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
- “Create uniform namespace using autofs with NFS Version 3 clients and servers”(developerWorks,2007 年 1 月)讨论如何使用 autofs 和 LDAP 的开放源码实现,在同一个挂载点下访问从多个文件服务器导出的数据。
- “系统管理员工具包: 迁移和移动 UNIX 文件系统”(developerWorks,2006 年 7 月)解释如何在正在运行的系统上转移整个文件系统,包括如何创建、复制和重新启用文件系统。
- “在 Linux 中使用 ReiserFS 文件系统”(developerWorks,2006 年 4 月)描述 “一种有挑战性的高级文件系统”。
- “Differentiating UNIX and Linux”(developerWorks,2006 年 3 月)介绍 Linux 和 UNIX 的文件系统支持之间的差异。
- 在 Linux 主页上,了解关于
clone(2)
、unshare(2)
、mount(8)
、pivot_root(2)
和chroot(2)
的更多信息。 - 共同准则 Labeled Security Protection Profile(LSPP) 为 IT 产品指定了一组安全功能和保障需求 —— 两类访问控制机制。
- FUSE(Filesystem in Userspace)支持用简单的 API 在用户空间程序中实现功能完整的文件系统,它不需要对内核应用补丁或者进行重新编译。它是一种安全可靠的实现,可以供非特权用户使用。它在 2.4.x 和 2.6.x 内核上运行。
- sshfs 是一种基于 SSH File Transfer Protocol 的文件系统客户机;大多数 SSH 服务器已经支持这个协议,所以在安装它时,不需要在服务器端做任何工作,只需在客户端用 ssh 登录服务器。
- loopback 文件系统 允许创建新的虚拟文件系统,这种文件系统可以使用替代的路径名访问现有的文件;创建它之后,可以在其中挂载其他文件系统,而不会影响原来的文件系统。
- 查看
chroot()
jail 卡。 - Linux PAM 是一种灵活的用户身份验证机制,它使开发人员可以建立独立于身份验证方案的程序(这样的话,“新设备” 就不必考虑所有身份验证支持程序)。
- Linux Documentation Project 提供许多有用的文档,尤其是它的 HOWTO。
- 在 developerWorks Linux 专区 中可以找到为 Linux 开发人员准备的更多参考资料。
- 查阅 developerWorks 上的所有 Linux 技巧 和 Linux 教程。
- 随时关注 developerWorks 技术活动和网络广播。
获得产品和技术
- 索取 SEK for Linux,共有两张 DVD,包含最新的 IBM Linux 试用软件,涉及 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。
- 使用 IBM 试用软件 构建您的下一个 Linux 开发项目,这些软件可以从 developerWorks 直接下载。
讨论
- 通过 新的 developerWorks spaces 中的 blog、论坛、podcast 和社区主题,加入 developerWorks 社区。
Serge Hallyn 是 IBM Linux Technology Center 安全团队的一名专职程序员。他从 College of William and Mary 获得了计算机科学博士学位。他实现了几个安全模型 (dte、bsdjail),并对其他的安全模型 (seclvl) 和 SELinux 贡献了自己的力量。他实现了 DTE 及相应的配置文件和分析工具,并在 Type Enforcement(SELinux 中的主要技术)方面具有丰富的经验。