我该如何诱使某个进程认为文件不存在?


31

我有一个程序将其设置存储在 ~/.config/myprogram我既可以交互使用,也可以与批处理排队系统一起使用。交互式运行时,我希望该程序使用我的配置文件(确实如此)。但是,在批处理模式下运行时,不需要配置文件,因为我指定了覆盖所有相关设置的命令行选项。此外,通过网络访问配置文件会使程序的启动时间增加几秒钟。如果文件不存在,程序将启动得更快(由于每个作业仅需一分钟左右,因此对批处理作业的吞吐量有重大影响)。但是因为我也以交互方式使用该程序,所以我不想一直移动/删除配置文件。根据我在群集上安排批处理作业的时间(基于其他用户的使用情况),

(此外:网络文件性能如此之慢可能是一个错误,但是我只是集群的用户,所以我只能解决它,而不能解决它。)

我可以构建不读取配置文件(或不具有命令行选项)以供批处理使用的程序版本,但是该程序的构建环境设计欠佳,难以设置。我非常喜欢使用通过系统的软件包管理器安装的二进制文件。

如何欺骗该程序的特定实例以假装我的配置文件不存在(无需修改程序)?我希望表单有包装pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options...,但是我对其他解决方案持 开放态度。


2
您可以以没有权限读取文件的用户身份运行它。
psimon 2014年

1
@psimon作为群集的“仅用户”,我无法创建新用户来运行我的批处理作业。不过,这是一个聪明的主意,如果没有更好的建议,我将为群集管理员提供调试服务。
Jeffrey Bosboom 2014年

或设置一个脚本,该脚本首先重命名配置文件,运行程序,然后再次重命名配置文件。
psimon 2014年

@psimon我想我可能会更加清楚:我可能同时在批处理模式下以交互方式使用该程序,具体取决于我的批处理作业在群集中的调度时间。
Jeffrey Bosboom 2014年

1
是的,如果它是动态链接的,则可以使用LD_PRELOAD钩子。这比替代方法()容易(如果知道C,则可以在一两个小时内实现)ptrace。您也可以使用fakechroot来执行此操作(我相信这是LD_PRELOAD)。
derobert 2014年

Answers:


33

该程序可能会从解析该文件的路径$HOME/.config/myprogram。因此,您可以告诉它您的主目录在其他位置,例如:

HOME=/nowhere your-program

现在,也许您的程序在主目录中需要其他资源。如果您知道它们是哪一个,则可以为您的程序准备一个伪造的家,其中包含指向该家所需资源的链接。

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram

5
这个答案解决了我的问题,所以即使它不是该问题标题中对该问题的完全笼统的答案,我也接受了它。如另一个答案中所述,预紧钩是一种更通用的解决方案(但也是更省力的解决方案)。
Jeffrey Bosboom 2014年

28

如果其他所有方法均失败,则编写一个包装库,您将使用该包装库注入该包装库,LD_PRELOADopen("/home/you/my-program/config.interactive")拦截对的调用,但其他任何传递都会通过。这适用于任何类型的程序,甚至包括shell脚本,因为它将过滤系统调用。

extern int errno;

int open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    return get_real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1;
  }
}

注意:我尚未测试此代码,因此我不能100%确定 errno部分是否有效。

看看如何fakeroot处理像getuid(2)stat(2)

基本上,链接器会将该应用程序链接到您的库,该库将覆盖该open符号。由于您不能使用open您自己的库中命名的两个不同函数,因此您必须将其分隔为第二部分(例如get_real_open),该第二部分又将链接到原始库。open调用。

原版的: ./Application

Application -----> libc.so
            open()

拦截: LD_PRELOAD=yourlib_wrap.so ./Application

Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
            open()                 get_real_open()                 open()

编辑:显然有一个ld可以启用(--wrap <symbol>)的标志,它允许您编写包装器而不必诉诸双链接:

/* yourlib.c */
#include <stdio.h>

int __real_open(const char *pathname, int flags)

int __wrap_open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    /* the undefined reference here will resolve to "open" at linking time */
    return __real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1; 
  }
}

2

移开配置文件,并为交互式用例编写一个shell脚本包装,将文件复制到其正常目标位置,运行该程序,并在退出时将其删除。


请参阅我最近的编辑:我无法控制批处理计划,因此我可能会交互式地使用该程序,并将其作为批处理作业的一部分同时使用。
Jeffrey Bosboom 2014年

1

unionfs / aufs应该可以做到这一点。您chroot为流程创建环境。您将真实目录用作只读层,并在其上放置一个空目录。然后,将unionfs卷安装到chroot环境中的相应目录,并在那里删除文件。该过程将看不到,但其他所有过程都会看到。


0

将配置文件重命名为例如config.interactive。创建另一个名为eg的空文件config.script

现在,创建一个名为config(或应用程序期望作为配置文件的文件)指向您所需的任何实际配置的软链接,然后运行您的应用程序。

ln -s config.interactive config

切记之后要整理链接。


请参阅我最近的编辑:我无法控制批处理计划,因此我可能会交互式地使用该程序,并将其作为批处理作业的一部分同时使用。这个答案本质上与手动或使用脚本移动文件相同。
Jeffrey Bosboom 2014年

1
h!我需要思考和打字更快。它是一个大型应用程序吗?可以将它转移到chroot并以交互方式从那里运行吗?我想,这完全取决于程序与之交互的方式。将所需的所有内容也放入chroot也可能是一项非常繁琐的任务。(我认为我已经退出该选项了!)
garethTheRed

0

如果您已经精确地描述程序如何使用配置文件,那么我将忽略它。许多程序(例如bashvi)在启动时会立即检查配置文件;如果文件存在,请读取并关闭它。这些程序永远不会再访问这些初始化文件。如果您的程序是这样,请继续阅读。

我知道您已经拒绝了使配置文件确实不存在的答案(通过重命名),但是我有一个皱纹,这是我从未见过的。当您以批处理方式调用程序时,请执行以下操作:

DELAY_TIME=1
REALPATH="~/.config/myprogram"
HOLDPATH="${REALPATH}.hold"

mv "$REALPATH" "$HOLDPATH"
(sleep "$DELAY_TIME"; mv "$HOLDPATH" "$REALPATH")&
myprogram

这会将配置文件移开,但即使myprogram它仍在运行,也要在一秒钟后将其移回。这会创建一个非常短暂的时间窗口,在此时间段内文件将不可用–在此时间段内以交互方式运行程序的可能性是多少?(即使这样做,也可以退出并重新启动,并且配置文件可能会恢复原位。)

这确实会产生竞争条件。如果程序花费太长时间无法打开文件,则它可能会获取真实文件。如果这种情况经常发生而又成为问题,则只需增加DELAY_TIME的值即可。


1
可能会出错的最糟糕的事情是什么?我从字面上已经看到这种情况的发生。在生产中。
Henk Langeveld 2014年

-1

我喜欢Stephane的答案,但这会欺骗任何程序,让其相信任何文件都是空的 - (因为其dentry暂时指向实际上是空的文件)

cat <./test.txt
###OUTPUT###
notempty

mount --bind /dev/null ./test.txt
cat <./test.txt
###NO OUTPUT###

umount ./test.txt
cat <./test.txt
###OUTPUT###
notempty

您还可以:

mount --bind ./someotherconfig.conf ./unwanted.conf

如果你想要的话。


从本质上讲,这等效于几个先前的答案(我相信,这个答案要求用户具有特权)。OP拒绝了其他答案,因为他不想欺骗任何进程–他想欺骗程序的批处理调用,同时让交互式调用正常看到配置文件。
斯科特(Scott)

@Scott-我不同意-在此问题之前的所有其他答案都建议mv对文件进行一些更改-这可能会影响文件的牙科效果,例如实际截断文件或其他文件等,而产生其他后果-而此操作仅能进行。不过,我应该unsharemount我猜...
mikeserv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.