4

I have written a server(Ubuntu 14.04 LTS Server) - client - java program.

With this program I can send a text from my android-smartphone to my server saving it to the receivedData file.

The program is running under a user which has no shell assigned and no access to sensitive data or programs by default.

The only security issue I can think of is running out of memory due to a tons of gigabyte receivedData file which has no size check. Or, of course a DoS attack but I do not think my server is that important...

The program is just for learning purposes and shall not be used by any clients/hackers(of course ;)) but you never now..

So, can anyone tell me if it is possible to directly create a file receivedData with a limited file size. At the moment it reaches the file size it should deny receivedData preventing it from causing an OOM.

If not I will need to implement that into the java program...

2
  • 1
    Altough "The program is just for learning purposes and shall not be used by any clients/hackers", if I were you I'd still implement this in the program for portability
    – kos
    May 26, 2015 at 12:14
  • Note that an OOM is a different thing - it's Out of Memory in the RAM sense. Size of files created by the processes need not necessarily affect the memory being used by it.
    – muru
    May 26, 2015 at 12:27

4 Answers 4

16

There are two ways this can be done:

  • using the ulimit shell utility, or using the setrlimit system call (which is what ulimit calls in turn).
  • using filesystem quotas, and a special user for the server process, will restrict the total usage of that user

ulimit/setrlimit

From 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.

I'm not sure how one could invoke the setrlimit function from Java, but this U&L question might help. Alternatively, wrap the Java server in a script:

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

Filesystem Quotas:

I'm assuming an ext4 filesystem, I'm unsure about others. First, we need to enable quota on the filesystem. Edit /etc/fstab, and add usrquota to the mount options of the appropriate partition. If we're doing this for /, for example, the final entry would look something like:

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

Then enable it after restarting:

sudo quotaon /

I'll assume your server is run as a different user (say restricted_user). If not, create one if you don't want your normal processes to be affected.

Then do:

sudo edquota restricted_user

Which will open an editor.

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

Set the soft and hard limits to the appropriate values (they're 1024-byte blocks, so divide your limit by 1024). Save and quit.

Then the user will not be able to exceed a total of 1G usage on that filesystem, counting all files owned by them.


Naturally, you should still check the size in your server program.

10
  • 1
    +1: Extremely good answer (said without flattery). I've edited the titles as them seemed so big. Feel free to revert.
    – 0x2b3bfa0
    May 26, 2015 at 12:14
  • @Helio no, that's fine. But I still prefer proper header tags, so I edit them to use h3 tags (### in markdown).
    – muru
    May 26, 2015 at 12:20
  • Ok, now it's better.
    – 0x2b3bfa0
    May 26, 2015 at 12:24
  • Why don't i have to run sudo quotacheck in your solution as recommended in this tutorial? Is it automatically started when i reboot? How can i do a quotacheck on the root system when it is mounted?
    – Mike
    May 27, 2015 at 12:33
  • @Mike the quotacheck command is a reporting tool. It doesn't enforce anything. Whether you run it or not is entirely up to you
    – muru
    May 27, 2015 at 12:48
5

UPDATE:

The answer by muru is perfect for file size, I'm here giving a solution how to size a directory itself, not just a file.


There is no such thing direct since filesystem deal with a folder as file of files and its limit is the whole filesystem itself.

So as a workaround for your problem you can do a trick creating a virtual filesystem and mount it on a specific (empty) directory.

create the mount point of the virtual file system to mount on (~/test for me)

mkdir ~/test

create a file full of /dev/zero, large enough to the maximum size you want to reserve for the virtual filesystem (i'm doing here for 1MB)

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

format this file with an ext4 filesystem

 mke2fs test.img

mount the newly formatted disk space in the directory you've created as mount point

mount -o loop test.img ~/test

Then use this directory

4
  • It certainly is possible (see the answers by @muru and @the_Seppi). If it's only one file, however, it would be easier to track total file-size in Java and give a friendly error-message if the limit is reached.
    – david
    May 26, 2015 at 21:22
  • @david I answered him for sizing a folder not just a file, read my answer again. The original post was about that, not just limiting a file itself
    – Maythux
    May 27, 2015 at 5:35
  • I like your solution. I tried it and it works. Also, any owner or permission changes made to the mounting directory e.g. /mnt/ are affecting the file ( in your case test.img) and not the directory. Now I will spend some time on murus solution! ;)
    – Mike
    May 27, 2015 at 9:17
  • @Mike nice to hear that
    – Maythux
    May 27, 2015 at 9:21
2

I'd say it's safest to check the file size inside the java program.

You can append to any file you have write access to, as long as there is enough space in the partition, so you cannot limit a file's size directly.

The only thing I can think of is to create a partition only for this file, so the file size will be limited to the partition's size. Also, if you'd format the partition as FAT32, the file could have a maximum size of 4 GiB.

0

Without seeing your code, it's hard to tell if your application would OOM or not.

Usually, you would read a manageable chunk of data (say 1MB) from the socket and write that chunk of data directly to a file. That way, you'd never store more than the temporary chunk in memory at any one time.

Typically this looks like:

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);
};

You could then add a counter to the while loop to count how many bytes have been written to the file and terminate the socket should it go over a predetermined amount or is getting close to consuming all available disk space.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .