章节大纲

  • 在本任务中,我们研究 Set-UID 程序如何处理一些环境变量。包括 LD_PRELOAD、LD_LIBRARY_PATH 以及其他 LD_* 在内的多个环境变量会影响动态加载器/链接器的行为。 动态加载器/链接器是操作系统的一部分,它负责将共享库加载到内存并进行链接。

    在 Linux 系统中,ld.so 或 ld-linux.so 是动态加载器/链接器(每个针对不同类型的二进制文件)。在影响其行为的环境变量中,LD_LIBRARY_PATH 和 LD_PRELOAD 是本实验关注的两个变量。加载器/链接器首先需要找到程序需要的共享库,在查找标准目录之前会首先搜索 LD_LIBRARY_PATH 环境变量里指定的目录。如果 LD_PRELOAD 环境变量存在,它里面指定了用户定义的一组共享库,这些库会在所有其他库之前被加载。本任务仅研究 LD_PRELOAD。

      • 首先,我们观察这些环境变量在运行普通程序时如何影响动态加载器/链接器的行为。请按照以下步骤操作:

        • 构建一个动态链接库。创建以下程序,命名为 mylib.c。该程序覆盖了 libc 中的 sleep() 函数:
        #include <stdio.h>
        void sleep (int s)
        {
          /* 如果这是由特权程序调用的,
             你可以在这里造成破坏! */
          printf("我不会睡觉!\n");
        }
        • 使用以下命令编译上述程序:
        $ gcc -fPIC -g -c mylib.c
        $ gcc -shared -o libmylib.so.1.0.1 mylib.o -lc
        • 设置 LD_PRELOAD 环境变量:
        $ export LD_PRELOAD=./libmylib.so.1.0.1
        • 最后,编译以下程序 myprog,并放置在与上述动态链接库 libmylib.so.1.0.1 相同的目录中:
        /* myprog.c */
        #include <unistd.h>
        int main()
        {
          sleep(1);
          return 0;
        }
      • 完成上述操作后,在以下条件下运行 myprog, 观察发生的情况。

        • 将 myprog 设置为普通程序,并以普通用户运行。

        • 将 myprog 设置为 Set-UID root 程序,并以普通用户运行。

        • 将 myprog 设置为 Set-UID root 程序,在 root 账户中设置 LD_PRELOAD 环境变量后运行该程序。

        • 将 myprog 设置为 Set-UID user1 程序(即拥有者为 user1,这是另一个用户账户),在 user2 账户 (非 root 用户)中设置 LD_PRELOAD 环境变量后运行该程序。

      • 在上述场景中,即使运行的是相同的程序,你应该会观察到不同的行为。你需要弄清楚导致差异的原因。环境变量在这里起到了作用。请设计实验以确定主要原因,并解释为何步骤 2 中的行为会有所不同。(提示:子进程可能不会继承 LD_* 环境变量)。