[Patch-ac] Re: DoS with tmpfs #3

From: Christoph Rohland (cr@sap.com)
Date: Mon Aug 06 2001 - 11:29:00 EST


Hi Alan,

On 06 Aug 2001, Christoph Rohland wrote:
> Since there are enough persons having trouble with the current
> behaviour I append a patch (against 2.4.8-pre4) to implement the
> default to be ram/2.

The appended patch is the same against 2.4.7-ac7 plus some further
fixes/cleanups:

- Use PAGE_CACHE_SIZE consistently
- use info->sem instead of inode->i_sem where appropriate
- fix a race in shmem_lock

Greetings
                Christoph

diff -uNr 7-ac7/mm/shmem.c 7-ac7-fix/mm/shmem.c
--- 7-ac7/mm/shmem.c Mon Aug 6 17:37:28 2001
+++ 7-ac7-fix/mm/shmem.c Mon Aug 6 18:06:13 2001
@@ -33,7 +33,7 @@
 /* This magic number is used in glibc for posix shared memory */
 #define TMPFS_MAGIC 0x01021994
 
-#define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))
+#define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
 
 #define SHMEM_SB(sb) (&sb->u.shmem_sb)
 
@@ -49,7 +49,7 @@
 static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED;
 atomic_t shmem_nrpages = ATOMIC_INIT(0);
 
-#define BLOCKS_PER_PAGE (PAGE_SIZE/512)
+#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512)
 
 static void shmem_removepage(struct page *page)
 {
@@ -626,7 +626,7 @@
         unsigned int idx;
         struct inode * inode = vma->vm_file->f_dentry->d_inode;
 
- idx = (address - vma->vm_start) >> PAGE_SHIFT;
+ idx = (address - vma->vm_start) >> PAGE_CACHE_SHIFT;
         idx += vma->vm_pgoff;
 
         if (shmem_getpage(inode, idx, &page))
@@ -655,9 +655,9 @@
         struct page * page;
         unsigned long idx, size;
 
- if (info->locked == lock)
- return;
- down(&inode->i_sem);
+ down(&info->sem);
+ if (info->locked == lock)
+ goto out;
         info->locked = lock;
         size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
         for (idx = 0; idx < size; idx++) {
@@ -671,7 +671,8 @@
                 }
                 UnlockPage(page);
         }
- up(&inode->i_sem);
+out:
+ up(&info->sem);
 }
 
 static int shmem_mmap(struct file * file, struct vm_area_struct * vma)
@@ -962,18 +963,8 @@
         buf->f_type = TMPFS_MAGIC;
         buf->f_bsize = PAGE_CACHE_SIZE;
         spin_lock (&sbinfo->stat_lock);
- if (sbinfo->max_blocks == ULONG_MAX) {
- /*
- * This is only a guestimate and not honoured.
- * We need it to make some programs happy which like to
- * test the free space of a file system.
- */
- buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages);
- buf->f_blocks = buf->f_bfree + ULONG_MAX - sbinfo->free_blocks;
- } else {
- buf->f_blocks = sbinfo->max_blocks;
- buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
- }
+ buf->f_blocks = sbinfo->max_blocks;
+ buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
         buf->f_files = sbinfo->max_inodes;
         buf->f_ffree = sbinfo->free_inodes;
         spin_unlock (&sbinfo->stat_lock);
@@ -1129,7 +1120,7 @@
                 return error;
 
         len = strlen(symname) + 1;
- if (len > PAGE_SIZE)
+ if (len > PAGE_CACHE_SIZE)
                 return -ENAMETOOLONG;
                 
         inode = dentry->d_inode;
@@ -1143,10 +1134,10 @@
                 spin_lock (&shmem_ilock);
                 list_add (&info->list, &shmem_inodes);
                 spin_unlock (&shmem_ilock);
- down(&inode->i_sem);
+ down(&info->sem);
                 page = shmem_getpage_locked(info, inode, 0);
                 if (IS_ERR(page)) {
- up(&inode->i_sem);
+ up(&info->sem);
                         return PTR_ERR(page);
                 }
                 kaddr = kmap(page);
@@ -1155,7 +1146,7 @@
                 SetPageDirty(page);
                 UnlockPage(page);
                 page_cache_release(page);
- up(&inode->i_sem);
+ up(&info->sem);
                 inode->i_op = &shmem_symlink_inode_operations;
         }
         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1253,17 +1244,11 @@
         return 0;
 }
 
-static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
+static int shmem_set_size(struct shmem_sb_info *sbinfo,
+ unsigned long max_blocks, unsigned long max_inodes)
 {
         int error;
- unsigned long max_blocks, blocks;
- unsigned long max_inodes, inodes;
- struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
-
- max_blocks = sbinfo->max_blocks;
- max_inodes = sbinfo->max_inodes;
- if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
- return -EINVAL;
+ unsigned long blocks, inodes;
 
         spin_lock(&sbinfo->stat_lock);
         blocks = sbinfo->max_blocks - sbinfo->free_blocks;
@@ -1283,6 +1268,17 @@
         return error;
 }
 
+static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
+{
+ struct shmem_sb_info *sbinfo = &sb->u.shmem_sb;
+ unsigned long max_blocks = sbinfo->max_blocks;
+ unsigned long max_inodes = sbinfo->max_inodes;
+
+ if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
+ return -EINVAL;
+ return shmem_set_size(sbinfo, max_blocks, max_inodes);
+}
+
 int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
         return 0;
@@ -1293,10 +1289,17 @@
 {
         struct inode * inode;
         struct dentry * root;
- unsigned long blocks = ULONG_MAX; /* unlimited */
- unsigned long inodes = ULONG_MAX; /* unlimited */
+ unsigned long blocks, inodes;
         int mode = S_IRWXUGO | S_ISVTX;
         struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+ struct sysinfo si;
+
+ /*
+ * Per default we only allow half of the physical ram per
+ * tmpfs instance
+ */
+ si_meminfo(&si);
+ blocks = inodes = si.totalram / 2;
 
 #ifdef CONFIG_TMPFS
         if (shmem_parse_options (data, &mode, &blocks, &inodes)) {
@@ -1416,6 +1419,10 @@
         }
         shm_mnt = res;
 
+ /* The internal instance should not do size checking */
+ if ((error = shmem_set_size(SHMEM_SB(res->mnt_sb), ULONG_MAX, ULONG_MAX)))
+ printk (KERN_ERR "could not set limits on internal tmpfs\n");
+
         return 0;
 }
 
@@ -1450,7 +1457,7 @@
         if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT)
                 return ERR_PTR(-EINVAL);
 
- if (!vm_enough_memory((size) >> PAGE_SHIFT))
+ if (!vm_enough_memory((size) >> PAGE_CACHE_SHIFT))
                 return ERR_PTR(-ENOMEM);
 
         this.name = name;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Aug 07 2001 - 21:00:39 EST