aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fcntl.c5
-rw-r--r--include/linux/shmem_fs.h17
-rw-r--r--include/uapi/linux/fcntl.h15
-rw-r--r--mm/shmem.c143
4 files changed, 180 insertions, 0 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 72c82f69b01b..22d1c3df61ac 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -21,6 +21,7 @@
21#include <linux/rcupdate.h> 21#include <linux/rcupdate.h>
22#include <linux/pid_namespace.h> 22#include <linux/pid_namespace.h>
23#include <linux/user_namespace.h> 23#include <linux/user_namespace.h>
24#include <linux/shmem_fs.h>
24 25
25#include <asm/poll.h> 26#include <asm/poll.h>
26#include <asm/siginfo.h> 27#include <asm/siginfo.h>
@@ -336,6 +337,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
336 case F_GETPIPE_SZ: 337 case F_GETPIPE_SZ:
337 err = pipe_fcntl(filp, cmd, arg); 338 err = pipe_fcntl(filp, cmd, arg);
338 break; 339 break;
340 case F_ADD_SEALS:
341 case F_GET_SEALS:
342 err = shmem_fcntl(filp, cmd, arg);
343 break;
339 default: 344 default:
340 break; 345 break;
341 } 346 }
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 4d1771c2d29f..50777b5b1e4c 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -1,6 +1,7 @@
1#ifndef __SHMEM_FS_H 1#ifndef __SHMEM_FS_H
2#define __SHMEM_FS_H 2#define __SHMEM_FS_H
3 3
4#include <linux/file.h>
4#include <linux/swap.h> 5#include <linux/swap.h>
5#include <linux/mempolicy.h> 6#include <linux/mempolicy.h>
6#include <linux/pagemap.h> 7#include <linux/pagemap.h>
@@ -11,6 +12,7 @@
11 12
12struct shmem_inode_info { 13struct shmem_inode_info {
13 spinlock_t lock; 14 spinlock_t lock;
15 unsigned int seals; /* shmem seals */
14 unsigned long flags; 16 unsigned long flags;
15 unsigned long alloced; /* data pages alloced to file */ 17 unsigned long alloced; /* data pages alloced to file */
16 union { 18 union {
@@ -65,4 +67,19 @@ static inline struct page *shmem_read_mapping_page(
65 mapping_gfp_mask(mapping)); 67 mapping_gfp_mask(mapping));
66} 68}
67 69
70#ifdef CONFIG_TMPFS
71
72extern int shmem_add_seals(struct file *file, unsigned int seals);
73extern int shmem_get_seals(struct file *file);
74extern long shmem_fcntl(struct file *file, unsigned int cmd, unsigned long arg);
75
76#else
77
78static inline long shmem_fcntl(struct file *f, unsigned int c, unsigned long a)
79{
80 return -EINVAL;
81}
82
83#endif
84
68#endif 85#endif
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index 074b886c6be0..beed138bd359 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -28,6 +28,21 @@
28#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) 28#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
29 29
30/* 30/*
31 * Set/Get seals
32 */
33#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
34#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
35
36/*
37 * Types of seals
38 */
39#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
40#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
41#define F_SEAL_GROW 0x0004 /* prevent file from growing */
42#define F_SEAL_WRITE 0x0008 /* prevent writes */
43/* (1U << 31) is reserved for signed error codes */
44
45/*
31 * Types of directory notifications that may be requested. 46 * Types of directory notifications that may be requested.
32 */ 47 */
33#define DN_ACCESS 0x00000001 /* File accessed */ 48#define DN_ACCESS 0x00000001 /* File accessed */
diff --git a/mm/shmem.c b/mm/shmem.c
index 6dc80d298f9d..8b43bb7a4efe 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -66,6 +66,7 @@ static struct vfsmount *shm_mnt;
66#include <linux/highmem.h> 66#include <linux/highmem.h>
67#include <linux/seq_file.h> 67#include <linux/seq_file.h>
68#include <linux/magic.h> 68#include <linux/magic.h>
69#include <linux/fcntl.h>
69 70
70#include <asm/uaccess.h> 71#include <asm/uaccess.h>
71#include <asm/pgtable.h> 72#include <asm/pgtable.h>
@@ -547,6 +548,7 @@ EXPORT_SYMBOL_GPL(shmem_truncate_range);
547static int shmem_setattr(struct dentry *dentry, struct iattr *attr) 548static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
548{ 549{
549 struct inode *inode = dentry->d_inode; 550 struct inode *inode = dentry->d_inode;
551 struct shmem_inode_info *info = SHMEM_I(inode);
550 int error; 552 int error;
551 553
552 error = inode_change_ok(inode, attr); 554 error = inode_change_ok(inode, attr);
@@ -557,6 +559,11 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
557 loff_t oldsize = inode->i_size; 559 loff_t oldsize = inode->i_size;
558 loff_t newsize = attr->ia_size; 560 loff_t newsize = attr->ia_size;
559 561
562 /* protected by i_mutex */
563 if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
564 (newsize > oldsize && (info->seals & F_SEAL_GROW)))
565 return -EPERM;
566
560 if (newsize != oldsize) { 567 if (newsize != oldsize) {
561 error = shmem_reacct_size(SHMEM_I(inode)->flags, 568 error = shmem_reacct_size(SHMEM_I(inode)->flags,
562 oldsize, newsize); 569 oldsize, newsize);
@@ -1412,6 +1419,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
1412 info = SHMEM_I(inode); 1419 info = SHMEM_I(inode);
1413 memset(info, 0, (char *)inode - (char *)info); 1420 memset(info, 0, (char *)inode - (char *)info);
1414 spin_lock_init(&info->lock); 1421 spin_lock_init(&info->lock);
1422 info->seals = F_SEAL_SEAL;
1415 info->flags = flags & VM_NORESERVE; 1423 info->flags = flags & VM_NORESERVE;
1416 INIT_LIST_HEAD(&info->swaplist); 1424 INIT_LIST_HEAD(&info->swaplist);
1417 simple_xattrs_init(&info->xattrs); 1425 simple_xattrs_init(&info->xattrs);
@@ -1470,7 +1478,17 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
1470 struct page **pagep, void **fsdata) 1478 struct page **pagep, void **fsdata)
1471{ 1479{
1472 struct inode *inode = mapping->host; 1480 struct inode *inode = mapping->host;
1481 struct shmem_inode_info *info = SHMEM_I(inode);
1473 pgoff_t index = pos >> PAGE_CACHE_SHIFT; 1482 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
1483
1484 /* i_mutex is held by caller */
1485 if (unlikely(info->seals)) {
1486 if (info->seals & F_SEAL_WRITE)
1487 return -EPERM;
1488 if ((info->seals & F_SEAL_GROW) && pos + len > inode->i_size)
1489 return -EPERM;
1490 }
1491
1474 return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL); 1492 return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL);
1475} 1493}
1476 1494
@@ -1808,11 +1826,125 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
1808 return offset; 1826 return offset;
1809} 1827}
1810 1828
1829static int shmem_wait_for_pins(struct address_space *mapping)
1830{
1831 return 0;
1832}
1833
1834#define F_ALL_SEALS (F_SEAL_SEAL | \
1835 F_SEAL_SHRINK | \
1836 F_SEAL_GROW | \
1837 F_SEAL_WRITE)
1838
1839int shmem_add_seals(struct file *file, unsigned int seals)
1840{
1841 struct inode *inode = file_inode(file);
1842 struct shmem_inode_info *info = SHMEM_I(inode);
1843 int error;
1844
1845 /*
1846 * SEALING
1847 * Sealing allows multiple parties to share a shmem-file but restrict
1848 * access to a specific subset of file operations. Seals can only be
1849 * added, but never removed. This way, mutually untrusted parties can
1850 * share common memory regions with a well-defined policy. A malicious
1851 * peer can thus never perform unwanted operations on a shared object.
1852 *
1853 * Seals are only supported on special shmem-files and always affect
1854 * the whole underlying inode. Once a seal is set, it may prevent some
1855 * kinds of access to the file. Currently, the following seals are
1856 * defined:
1857 * SEAL_SEAL: Prevent further seals from being set on this file
1858 * SEAL_SHRINK: Prevent the file from shrinking
1859 * SEAL_GROW: Prevent the file from growing
1860 * SEAL_WRITE: Prevent write access to the file
1861 *
1862 * As we don't require any trust relationship between two parties, we
1863 * must prevent seals from being removed. Therefore, sealing a file
1864 * only adds a given set of seals to the file, it never touches
1865 * existing seals. Furthermore, the "setting seals"-operation can be
1866 * sealed itself, which basically prevents any further seal from being
1867 * added.
1868 *
1869 * Semantics of sealing are only defined on volatile files. Only
1870 * anonymous shmem files support sealing. More importantly, seals are
1871 * never written to disk. Therefore, there's no plan to support it on
1872 * other file types.
1873 */
1874
1875 if (file->f_op != &shmem_file_operations)
1876 return -EINVAL;
1877 if (!(file->f_mode & FMODE_WRITE))
1878 return -EPERM;
1879 if (seals & ~(unsigned int)F_ALL_SEALS)
1880 return -EINVAL;
1881
1882 mutex_lock(&inode->i_mutex);
1883
1884 if (info->seals & F_SEAL_SEAL) {
1885 error = -EPERM;
1886 goto unlock;
1887 }
1888
1889 if ((seals & F_SEAL_WRITE) && !(info->seals & F_SEAL_WRITE)) {
1890 error = mapping_deny_writable(file->f_mapping);
1891 if (error)
1892 goto unlock;
1893
1894 error = shmem_wait_for_pins(file->f_mapping);
1895 if (error) {
1896 mapping_allow_writable(file->f_mapping);
1897 goto unlock;
1898 }
1899 }
1900
1901 info->seals |= seals;
1902 error = 0;
1903
1904unlock:
1905 mutex_unlock(&inode->i_mutex);
1906 return error;
1907}
1908EXPORT_SYMBOL_GPL(shmem_add_seals);
1909
1910int shmem_get_seals(struct file *file)
1911{
1912 if (file->f_op != &shmem_file_operations)
1913 return -EINVAL;
1914
1915 return SHMEM_I(file_inode(file))->seals;
1916}
1917EXPORT_SYMBOL_GPL(shmem_get_seals);
1918
1919long shmem_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
1920{
1921 long error;
1922
1923 switch (cmd) {
1924 case F_ADD_SEALS:
1925 /* disallow upper 32bit */
1926 if (arg > UINT_MAX)
1927 return -EINVAL;
1928
1929 error = shmem_add_seals(file, arg);
1930 break;
1931 case F_GET_SEALS:
1932 error = shmem_get_seals(file);
1933 break;
1934 default:
1935 error = -EINVAL;
1936 break;
1937 }
1938
1939 return error;
1940}
1941
1811static long shmem_fallocate(struct file *file, int mode, loff_t offset, 1942static long shmem_fallocate(struct file *file, int mode, loff_t offset,
1812 loff_t len) 1943 loff_t len)
1813{ 1944{
1814 struct inode *inode = file_inode(file); 1945 struct inode *inode = file_inode(file);
1815 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); 1946 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
1947 struct shmem_inode_info *info = SHMEM_I(inode);
1816 struct shmem_falloc shmem_falloc; 1948 struct shmem_falloc shmem_falloc;
1817 pgoff_t start, index, end; 1949 pgoff_t start, index, end;
1818 int error; 1950 int error;
@@ -1828,6 +1960,12 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
1828 loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1; 1960 loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1;
1829 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq); 1961 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq);
1830 1962
1963 /* protected by i_mutex */
1964 if (info->seals & F_SEAL_WRITE) {
1965 error = -EPERM;
1966 goto out;
1967 }
1968
1831 shmem_falloc.waitq = &shmem_falloc_waitq; 1969 shmem_falloc.waitq = &shmem_falloc_waitq;
1832 shmem_falloc.start = unmap_start >> PAGE_SHIFT; 1970 shmem_falloc.start = unmap_start >> PAGE_SHIFT;
1833 shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT; 1971 shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT;
@@ -1854,6 +1992,11 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
1854 if (error) 1992 if (error)
1855 goto out; 1993 goto out;
1856 1994
1995 if ((info->seals & F_SEAL_GROW) && offset + len > inode->i_size) {
1996 error = -EPERM;
1997 goto out;
1998 }
1999
1857 start = offset >> PAGE_CACHE_SHIFT; 2000 start = offset >> PAGE_CACHE_SHIFT;
1858 end = (offset + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 2001 end = (offset + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
1859 /* Try to avoid a swapstorm if len is impossible to satisfy */ 2002 /* Try to avoid a swapstorm if len is impossible to satisfy */