创建具有有限文件大小的文件

创建具有有限文件大小的文件

我写过服务器(Ubuntu 14.04 LTS 服务器)- 客户端 - Java 程序。

通过这个程序,我可以从我的 Android 智能手机发送文本到我的服务器并将其保存到文件中receivedData

该程序在默认情况下未分配 shell 且无权访问敏感数据或程序的用户下运行。

我能想到的唯一安全问题是由于大量 GB 的receivedData文件没有大小检查而导致内存不足。或者,当然是 DoS 攻击,但我认为我的服务器没那么重要...

该程序仅用于学习目的,不得由任何客户/黑客使用(当然;))但您现在永远不会知道......

那么,有人能告诉我是否可以直接创建一个receivedData具有文件大小限制的文件吗?当文件大小达到限制时,它应该拒绝receivedData阻止它导致 OOM。

如果没有的话,我将需要将其实现到 Java 程序中......

答案1

有两种方法可以实现此目的:

  • 使用ulimitshell 实用程序,或者使用setrlimit系统调用(依次ulimit调用)。
  • 使用文件系统配额,以及服务器进程的特殊用户,将限制全部的该用户的使用情况

ulimit/setrlimit

man 2 setrlimit

RLIMIT_FSIZE
      The maximum size of files that the process may create.  Attempts
      to extend a file beyond this  limit  result  in  delivery  of  a
      SIGXFSZ  signal.   By default, this signal terminates a process,
      but a process can catch this signal instead, in which  case  the
      relevant  system  call  (e.g., write(2), truncate(2)) fails with
      the error EFBIG.

我不确定如何setrlimit从 Java 调用该函数,但是这个 U&L 问题可能会有帮助。或者,将 Java 服务器包装在脚本中:

#! /bin/bash
ulimit -f 1073741824   # 1GB
java ....

文件系统配额:

我假设是 ext4 文件系统,其他的我不确定。首先,我们需要在文件系统上启用配额。编辑/etc/fstab,并添加usrquota到相应分区的挂载选项中。/例如,如果我们对 执行此操作,则最终条目将如下所示:

UUID=... /               ext4    errors=remount-ro,usrquota 0       1

然后重启后启用它:

sudo quotaon /

我假设您的服务器以其他用户身份运行(例如restricted_user)。如果不是,请创建一个,如果您不希望正常流程受到影响。

然后做:

sudo edquota restricted_user

这将打开一个编辑器。

Disk quotas for user restricted_user (uid 1001):
  Filesystem                   blocks       soft       hard     inodes     soft     hard
  /dev/sdd1                   1087940    943718   1048576       9956        0        0

将软限制和硬限制设置为适当的值(它们是 1024 字节块,因此将限制除以 1024)。保存并退出。

那么用户将不能超过全部的该文件系统上使用的 1G 空间,计算其拥有的所有文件。


当然,您仍然应该在服务器程序中检查大小。

答案2

更新:

muru 的回答对于文件大小来说是完美的,我在这里给出如何调整目录本身的大小,而不仅仅是文件的大小的解决方案。


不存在直接这样的事情,因为文件系统将文件夹视为文件的文件,并且其限制是整个文件系统本身。

因此,为了解决您的问题,您可以采取一些技巧,创建一个虚拟文件系统并将其挂载到特定的(空)目录中。

创建要挂载的虚拟文件系统的挂载点(对我来说是〜/ test)

mkdir ~/test

创建一个充满 /dev/zero 的文件,足够大到您想要为虚拟文件系统保留的最大大小(我在这里将其设置为 1MB)

dd if=/dev/zero of=test.img bs=1024 count=0 seek=1024

使用 ext4 文件系统格式化此文件

 mke2fs test.img

将新格式化的磁盘空间挂载到您创建的目录中作为挂载点

mount -o loop test.img ~/test

然后使用该目录

答案3

我认为检查 java 程序内部的文件大小是最安全的。

只要分区中有足够的空间,您就可以向任何您有写权限的文件附加内容,所以您不能直接限制文件的大小。

我唯一能想到的办法就是只为这个文件创建一个分区,这样文件大小就会被限制在分区大小之内。另外,如果你将分区格式化为 FAT32,文件的最大大小可以达到 4 GiB。

答案4

如果看不到你的代码,就很难判断你的应用程序是否会 OOM。

通常,您会从套接字读取一个可管理的数据块(例如 1MB),然后将该数据块直接写入文件。这样,您每次在内存中存储的数据都不会超过临时数据块。

通常这看起来像:

FileOutputStream fos = new FileOutputStream("receivedData");

InputStream is = clientSocket.getInputStream();
byte[] buffer = new byte[1024];
int read;
while((read = is.read(buffer)) != -1) {
    fos.write(buffer);
};

然后,您可以向 while 循环添加一个计数器,以计算已写入文件的字节数,并在超过预定数量或接近消耗所有可用磁盘空间时终止套接字。

相关内容