diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2018-10-29 19:40:46 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2018-10-29 19:40:46 -0400 |
commit | 9fd91a90cb9837372af24a804853e15c11aed93e (patch) | |
tree | 28bf526bcccd9d6250a7451e5c2d734a419c70f4 | |
parent | 2c5773f102c9bb07d5328467f61f0a88f2f2892d (diff) |
vfs: strengthen checking of file range inputs to generic_remap_checks
File range remapping, if allowed to run past the destination file's EOF,
is an optimization on a regular file write. Regular file writes that
extend the file length are subject to various constraints which are not
checked by range cloning.
This is a correctness problem because we're never allowed to touch
ranges that the page cache can't support (s_maxbytes); we're not
supposed to deal with large offsets (MAX_NON_LFS) if O_LARGEFILE isn't
set; and we must obey resource limits (RLIMIT_FSIZE).
Therefore, add these checks to the new generic_remap_checks function so
that we curtail unexpected behavior.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | mm/filemap.c | 84 |
1 files changed, 52 insertions, 32 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 47e6bfd45a91..84b7301e41a0 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2916,6 +2916,42 @@ struct page *read_cache_page_gfp(struct address_space *mapping, | |||
2916 | EXPORT_SYMBOL(read_cache_page_gfp); | 2916 | EXPORT_SYMBOL(read_cache_page_gfp); |
2917 | 2917 | ||
2918 | /* | 2918 | /* |
2919 | * Don't operate on ranges the page cache doesn't support, and don't exceed the | ||
2920 | * LFS limits. If pos is under the limit it becomes a short access. If it | ||
2921 | * exceeds the limit we return -EFBIG. | ||
2922 | */ | ||
2923 | static int generic_access_check_limits(struct file *file, loff_t pos, | ||
2924 | loff_t *count) | ||
2925 | { | ||
2926 | struct inode *inode = file->f_mapping->host; | ||
2927 | loff_t max_size = inode->i_sb->s_maxbytes; | ||
2928 | |||
2929 | if (!(file->f_flags & O_LARGEFILE)) | ||
2930 | max_size = MAX_NON_LFS; | ||
2931 | |||
2932 | if (unlikely(pos >= max_size)) | ||
2933 | return -EFBIG; | ||
2934 | *count = min(*count, max_size - pos); | ||
2935 | return 0; | ||
2936 | } | ||
2937 | |||
2938 | static int generic_write_check_limits(struct file *file, loff_t pos, | ||
2939 | loff_t *count) | ||
2940 | { | ||
2941 | loff_t limit = rlimit(RLIMIT_FSIZE); | ||
2942 | |||
2943 | if (limit != RLIM_INFINITY) { | ||
2944 | if (pos >= limit) { | ||
2945 | send_sig(SIGXFSZ, current, 0); | ||
2946 | return -EFBIG; | ||
2947 | } | ||
2948 | *count = min(*count, limit - pos); | ||
2949 | } | ||
2950 | |||
2951 | return generic_access_check_limits(file, pos, count); | ||
2952 | } | ||
2953 | |||
2954 | /* | ||
2919 | * Performs necessary checks before doing a write | 2955 | * Performs necessary checks before doing a write |
2920 | * | 2956 | * |
2921 | * Can adjust writing position or amount of bytes to write. | 2957 | * Can adjust writing position or amount of bytes to write. |
@@ -2926,8 +2962,8 @@ inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) | |||
2926 | { | 2962 | { |
2927 | struct file *file = iocb->ki_filp; | 2963 | struct file *file = iocb->ki_filp; |
2928 | struct inode *inode = file->f_mapping->host; | 2964 | struct inode *inode = file->f_mapping->host; |
2929 | unsigned long limit = rlimit(RLIMIT_FSIZE); | 2965 | loff_t count; |
2930 | loff_t pos; | 2966 | int ret; |
2931 | 2967 | ||
2932 | if (!iov_iter_count(from)) | 2968 | if (!iov_iter_count(from)) |
2933 | return 0; | 2969 | return 0; |
@@ -2936,40 +2972,15 @@ inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) | |||
2936 | if (iocb->ki_flags & IOCB_APPEND) | 2972 | if (iocb->ki_flags & IOCB_APPEND) |
2937 | iocb->ki_pos = i_size_read(inode); | 2973 | iocb->ki_pos = i_size_read(inode); |
2938 | 2974 | ||
2939 | pos = iocb->ki_pos; | ||
2940 | |||
2941 | if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) | 2975 | if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) |
2942 | return -EINVAL; | 2976 | return -EINVAL; |
2943 | 2977 | ||
2944 | if (limit != RLIM_INFINITY) { | 2978 | count = iov_iter_count(from); |
2945 | if (iocb->ki_pos >= limit) { | 2979 | ret = generic_write_check_limits(file, iocb->ki_pos, &count); |
2946 | send_sig(SIGXFSZ, current, 0); | 2980 | if (ret) |
2947 | return -EFBIG; | 2981 | return ret; |
2948 | } | ||
2949 | iov_iter_truncate(from, limit - (unsigned long)pos); | ||
2950 | } | ||
2951 | |||
2952 | /* | ||
2953 | * LFS rule | ||
2954 | */ | ||
2955 | if (unlikely(pos + iov_iter_count(from) > MAX_NON_LFS && | ||
2956 | !(file->f_flags & O_LARGEFILE))) { | ||
2957 | if (pos >= MAX_NON_LFS) | ||
2958 | return -EFBIG; | ||
2959 | iov_iter_truncate(from, MAX_NON_LFS - (unsigned long)pos); | ||
2960 | } | ||
2961 | |||
2962 | /* | ||
2963 | * Are we about to exceed the fs block limit ? | ||
2964 | * | ||
2965 | * If we have written data it becomes a short write. If we have | ||
2966 | * exceeded without writing data we send a signal and return EFBIG. | ||
2967 | * Linus frestrict idea will clean these up nicely.. | ||
2968 | */ | ||
2969 | if (unlikely(pos >= inode->i_sb->s_maxbytes)) | ||
2970 | return -EFBIG; | ||
2971 | 2982 | ||
2972 | iov_iter_truncate(from, inode->i_sb->s_maxbytes - pos); | 2983 | iov_iter_truncate(from, count); |
2973 | return iov_iter_count(from); | 2984 | return iov_iter_count(from); |
2974 | } | 2985 | } |
2975 | EXPORT_SYMBOL(generic_write_checks); | 2986 | EXPORT_SYMBOL(generic_write_checks); |
@@ -2991,6 +3002,7 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in, | |||
2991 | uint64_t bcount; | 3002 | uint64_t bcount; |
2992 | loff_t size_in, size_out; | 3003 | loff_t size_in, size_out; |
2993 | loff_t bs = inode_out->i_sb->s_blocksize; | 3004 | loff_t bs = inode_out->i_sb->s_blocksize; |
3005 | int ret; | ||
2994 | 3006 | ||
2995 | /* The start of both ranges must be aligned to an fs block. */ | 3007 | /* The start of both ranges must be aligned to an fs block. */ |
2996 | if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_out, bs)) | 3008 | if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_out, bs)) |
@@ -3014,6 +3026,14 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in, | |||
3014 | return -EINVAL; | 3026 | return -EINVAL; |
3015 | count = min(count, size_in - (uint64_t)pos_in); | 3027 | count = min(count, size_in - (uint64_t)pos_in); |
3016 | 3028 | ||
3029 | ret = generic_access_check_limits(file_in, pos_in, &count); | ||
3030 | if (ret) | ||
3031 | return ret; | ||
3032 | |||
3033 | ret = generic_write_check_limits(file_out, pos_out, &count); | ||
3034 | if (ret) | ||
3035 | return ret; | ||
3036 | |||
3017 | /* | 3037 | /* |
3018 | * If the user wanted us to link to the infile's EOF, round up to the | 3038 | * If the user wanted us to link to the infile's EOF, round up to the |
3019 | * next block boundary for this check. | 3039 | * next block boundary for this check. |