2012-02-14 25 views
4

我在Linux上有一个很大的C++应用程序,有许多第一方和第三方库被构建和链接。如何以编程方式在大型Linux应用程序中“拔出网线”?

该应用程序的某些部分应该在不访问文件系统或网络的情况下执行(特别是加载联网文件)。我们定期发现这个操作确实通常是由于程序员错误而加载文件。

如何在代码中执行此操作?例如,如下所示:

try { 
    lockFileSystem(); 
    Application->DoImportantOperation(); 
    unlockFileSystem(); 
} catch (InvalidFileSystemAccess) 
{ 
// bad programmer, no pizza 
} 

或者还有某种低级别的回调,应用程序可以在文件打开时挂钩?

注意我知道strace的可怕性,但它已经到了需要作为应用程序执行的一部分执行的地步,而不是作为事后手动测试。

+0

*它是如何加载文件?你能不能'#including '? – Beta 2012-02-14 23:46:13

+0

加载在编译时不可执行。应用程序本质上运行一个脚本,并且一些部分不应该访问文件系统。 – Justicle 2012-02-14 23:48:46

+1

在chroot中启动应用程序?设置一些iptables规则来拒绝应用程序访问您的文件服务器?设置一个SELinux策略?不允许应用程序运行的用户访问装载点?在自己的网络名称空间/ VRF域中运行应用程序? ... – ninjalj 2012-02-15 00:01:33

回答

5

这取决于代码合法地尝试做什么,但您可以使用setrlimit()RLIMIT_NOFILE做到这一点。

像这样的东西应该工作:

#include <sys/resource.h> 

struct scoped_fd_blocker { 
    rlim_t prev; 
    scoped_fd_blocker() { 
     rlimit lim; 
     getrlimit(RLIMIT_NOFILE, &lim); // get the current limit 
     prev = lim.rlim_cur; // save old limit 
     lim.rlim_cur = 0; // set the soft limit to 0 
     setrlimit(RLIMIT_NOFILE, &lim); // do the set 
    } 

    ~scoped_fd_blocker() { 
     rlimit lim; 
     getrlimit(RLIMIT_NOFILE, &lim); // get the current limit 
     lim.rlim_cur = prev; // reset the soft limit to the previous value 
     setrlimit(RLIMIT_NOFILE, &lim); // do the set 
    } 
}; 


// Example Usage: 
void do_stuff() { 
    scoped_fd_blocker blocker; 
    Application->DoImportantOperation(); 
} 

基本上这告诉OS不要让你的程序打开任何文件描述符,即使现有的闭合,通过清空软开文件描述符限制的过程。请注意,这不仅仅是文件,还可能会产生一些意想不到的后果。这将包括文件,套接字,事件对象,目录,共享资源,管道,并且还会阻止C库打开文件。 (有些C库确实使用文件锁和内容来管理并发性。)想想所有打开文件的东西(例如dlopen)。

任何尝试打开文件描述符都将失败(返回-1),而errno将被设置为EMFILE,这将转换为“错误24:打开的文件过多”。

我把整个事情放在一个结构体中,以便它非常强大的异常安全。

+0

这看起来很有前途。读这个,http://linux.die.net/man/2/setrlimit我不知道调用'setr​​limit'是否需要超级用户权限。我想象不到,因为它在同一个过程中被调用。 – Justicle 2012-02-15 01:16:27

+1

为RAII包装+1! – 2012-02-15 07:11:59

+0

@Jittericle提高rlim_max高于getrlimit返回的值将需要root权限。与rlim_cur混淆不会(但它不能超过rlim_max)。这也意味着如果你降低rlim_max你不能再提高它。 – SoapBox 2012-02-15 09:40:55

2

不是很优雅,但你可以挂钩例如open()并通过你自己的具有状态的proxy_open()类型的调用进行路由。如果状态是“不允许文件系统!”那么你只需返回适当的错误和/或处理它,但不管你喜欢。

相关问题