diff options
| -rw-r--r-- | arch/alpha/include/asm/uaccess.h | 9 | ||||
| -rw-r--r-- | arch/alpha/lib/copy_user.S | 16 | ||||
| -rw-r--r-- | arch/alpha/lib/ev6-copy_user.S | 23 | ||||
| -rw-r--r-- | arch/arc/kernel/signal.c | 8 | ||||
| -rw-r--r-- | arch/arm/include/asm/uaccess.h | 11 | ||||
| -rw-r--r-- | arch/arm/lib/copy_from_user.S | 9 | ||||
| -rw-r--r-- | arch/arm64/include/asm/uaccess.h | 10 | ||||
| -rw-r--r-- | arch/arm64/lib/copy_from_user.S | 7 | ||||
| -rw-r--r-- | arch/blackfin/include/asm/uaccess.h | 32 | ||||
| -rw-r--r-- | arch/score/kernel/traps.c | 1 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 11 | ||||
| -rw-r--r-- | fs/read_write.c | 29 | ||||
| -rw-r--r-- | fs/super.c | 43 | ||||
| -rw-r--r-- | lib/iov_iter.c | 22 |
14 files changed, 133 insertions, 98 deletions
diff --git a/arch/alpha/include/asm/uaccess.h b/arch/alpha/include/asm/uaccess.h index 466e42e96bfa..94f587535dee 100644 --- a/arch/alpha/include/asm/uaccess.h +++ b/arch/alpha/include/asm/uaccess.h | |||
| @@ -396,11 +396,12 @@ copy_to_user(void __user *to, const void *from, long n) | |||
| 396 | extern inline long | 396 | extern inline long |
| 397 | copy_from_user(void *to, const void __user *from, long n) | 397 | copy_from_user(void *to, const void __user *from, long n) |
| 398 | { | 398 | { |
| 399 | long res = n; | ||
| 399 | if (likely(__access_ok((unsigned long)from, n, get_fs()))) | 400 | if (likely(__access_ok((unsigned long)from, n, get_fs()))) |
| 400 | n = __copy_tofrom_user_nocheck(to, (__force void *)from, n); | 401 | res = __copy_from_user_inatomic(to, from, n); |
| 401 | else | 402 | if (unlikely(res)) |
| 402 | memset(to, 0, n); | 403 | memset(to + (n - res), 0, res); |
| 403 | return n; | 404 | return res; |
| 404 | } | 405 | } |
| 405 | 406 | ||
| 406 | extern void __do_clear_user(void); | 407 | extern void __do_clear_user(void); |
diff --git a/arch/alpha/lib/copy_user.S b/arch/alpha/lib/copy_user.S index 2238068b1b40..509f62b65311 100644 --- a/arch/alpha/lib/copy_user.S +++ b/arch/alpha/lib/copy_user.S | |||
| @@ -126,22 +126,8 @@ $65: | |||
| 126 | bis $31,$31,$0 | 126 | bis $31,$31,$0 |
| 127 | $41: | 127 | $41: |
| 128 | $35: | 128 | $35: |
| 129 | $exitout: | ||
| 130 | ret $31,($28),1 | ||
| 131 | |||
| 132 | $exitin: | 129 | $exitin: |
| 133 | /* A stupid byte-by-byte zeroing of the rest of the output | 130 | $exitout: |
| 134 | buffer. This cures security holes by never leaving | ||
| 135 | random kernel data around to be copied elsewhere. */ | ||
| 136 | |||
| 137 | mov $0,$1 | ||
| 138 | $101: | ||
| 139 | EXO ( ldq_u $2,0($6) ) | ||
| 140 | subq $1,1,$1 | ||
| 141 | mskbl $2,$6,$2 | ||
| 142 | EXO ( stq_u $2,0($6) ) | ||
| 143 | addq $6,1,$6 | ||
| 144 | bgt $1,$101 | ||
| 145 | ret $31,($28),1 | 131 | ret $31,($28),1 |
| 146 | 132 | ||
| 147 | .end __copy_user | 133 | .end __copy_user |
diff --git a/arch/alpha/lib/ev6-copy_user.S b/arch/alpha/lib/ev6-copy_user.S index debcc3b6b704..be720b518af9 100644 --- a/arch/alpha/lib/ev6-copy_user.S +++ b/arch/alpha/lib/ev6-copy_user.S | |||
| @@ -228,33 +228,12 @@ $dirtyentry: | |||
| 228 | bgt $0,$onebyteloop # U .. .. .. : U L U L | 228 | bgt $0,$onebyteloop # U .. .. .. : U L U L |
| 229 | 229 | ||
| 230 | $zerolength: | 230 | $zerolength: |
| 231 | $exitin: | ||
| 231 | $exitout: # Destination for exception recovery(?) | 232 | $exitout: # Destination for exception recovery(?) |
| 232 | nop # .. .. .. E | 233 | nop # .. .. .. E |
| 233 | nop # .. .. E .. | 234 | nop # .. .. E .. |
| 234 | nop # .. E .. .. | 235 | nop # .. E .. .. |
| 235 | ret $31,($28),1 # L0 .. .. .. : L U L U | 236 | ret $31,($28),1 # L0 .. .. .. : L U L U |
| 236 | 237 | ||
| 237 | $exitin: | ||
| 238 | |||
| 239 | /* A stupid byte-by-byte zeroing of the rest of the output | ||
| 240 | buffer. This cures security holes by never leaving | ||
| 241 | random kernel data around to be copied elsewhere. */ | ||
| 242 | |||
| 243 | nop | ||
| 244 | nop | ||
| 245 | nop | ||
| 246 | mov $0,$1 | ||
| 247 | |||
| 248 | $101: | ||
| 249 | EXO ( stb $31,0($6) ) # L | ||
| 250 | subq $1,1,$1 # E | ||
| 251 | addq $6,1,$6 # E | ||
| 252 | bgt $1,$101 # U | ||
| 253 | |||
| 254 | nop | ||
| 255 | nop | ||
| 256 | nop | ||
| 257 | ret $31,($28),1 # L0 | ||
| 258 | |||
| 259 | .end __copy_user | 238 | .end __copy_user |
| 260 | EXPORT_SYMBOL(__copy_user) | 239 | EXPORT_SYMBOL(__copy_user) |
diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index 6cb3736b6b83..d347bbc086fe 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c | |||
| @@ -107,13 +107,13 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf) | |||
| 107 | struct user_regs_struct uregs; | 107 | struct user_regs_struct uregs; |
| 108 | 108 | ||
| 109 | err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); | 109 | err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); |
| 110 | if (!err) | ||
| 111 | set_current_blocked(&set); | ||
| 112 | |||
| 113 | err |= __copy_from_user(&uregs.scratch, | 110 | err |= __copy_from_user(&uregs.scratch, |
| 114 | &(sf->uc.uc_mcontext.regs.scratch), | 111 | &(sf->uc.uc_mcontext.regs.scratch), |
| 115 | sizeof(sf->uc.uc_mcontext.regs.scratch)); | 112 | sizeof(sf->uc.uc_mcontext.regs.scratch)); |
| 113 | if (err) | ||
| 114 | return err; | ||
| 116 | 115 | ||
| 116 | set_current_blocked(&set); | ||
| 117 | regs->bta = uregs.scratch.bta; | 117 | regs->bta = uregs.scratch.bta; |
| 118 | regs->lp_start = uregs.scratch.lp_start; | 118 | regs->lp_start = uregs.scratch.lp_start; |
| 119 | regs->lp_end = uregs.scratch.lp_end; | 119 | regs->lp_end = uregs.scratch.lp_end; |
| @@ -138,7 +138,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf) | |||
| 138 | regs->r0 = uregs.scratch.r0; | 138 | regs->r0 = uregs.scratch.r0; |
| 139 | regs->sp = uregs.scratch.sp; | 139 | regs->sp = uregs.scratch.sp; |
| 140 | 140 | ||
| 141 | return err; | 141 | return 0; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static inline int is_do_ss_needed(unsigned int magic) | 144 | static inline int is_do_ss_needed(unsigned int magic) |
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index a93c0f99acf7..1f59ea051bab 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h | |||
| @@ -533,11 +533,12 @@ __clear_user(void __user *addr, unsigned long n) | |||
| 533 | 533 | ||
| 534 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) | 534 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) |
| 535 | { | 535 | { |
| 536 | if (access_ok(VERIFY_READ, from, n)) | 536 | unsigned long res = n; |
| 537 | n = __copy_from_user(to, from, n); | 537 | if (likely(access_ok(VERIFY_READ, from, n))) |
| 538 | else /* security hole - plug it */ | 538 | res = __copy_from_user(to, from, n); |
| 539 | memset(to, 0, n); | 539 | if (unlikely(res)) |
| 540 | return n; | 540 | memset(to + (n - res), 0, res); |
| 541 | return res; | ||
| 541 | } | 542 | } |
| 542 | 543 | ||
| 543 | static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) | 544 | static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) |
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index f549c57ea435..63e4c1ed0225 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S | |||
| @@ -100,12 +100,9 @@ EXPORT_SYMBOL(arm_copy_from_user) | |||
| 100 | .pushsection .fixup,"ax" | 100 | .pushsection .fixup,"ax" |
| 101 | .align 0 | 101 | .align 0 |
| 102 | copy_abort_preamble | 102 | copy_abort_preamble |
| 103 | ldmfd sp!, {r1, r2} | 103 | ldmfd sp!, {r1, r2, r3} |
| 104 | sub r3, r0, r1 | 104 | sub r0, r0, r1 |
| 105 | rsb r1, r3, r2 | 105 | rsb r0, r0, r2 |
| 106 | str r1, [sp] | ||
| 107 | bl __memzero | ||
| 108 | ldr r0, [sp], #4 | ||
| 109 | copy_abort_end | 106 | copy_abort_end |
| 110 | .popsection | 107 | .popsection |
| 111 | 108 | ||
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index c47257c91b77..bcaf6fba1b65 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h | |||
| @@ -278,14 +278,16 @@ static inline unsigned long __must_check __copy_to_user(void __user *to, const v | |||
| 278 | 278 | ||
| 279 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) | 279 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) |
| 280 | { | 280 | { |
| 281 | unsigned long res = n; | ||
| 281 | kasan_check_write(to, n); | 282 | kasan_check_write(to, n); |
| 282 | 283 | ||
| 283 | if (access_ok(VERIFY_READ, from, n)) { | 284 | if (access_ok(VERIFY_READ, from, n)) { |
| 284 | check_object_size(to, n, false); | 285 | check_object_size(to, n, false); |
| 285 | n = __arch_copy_from_user(to, from, n); | 286 | res = __arch_copy_from_user(to, from, n); |
| 286 | } else /* security hole - plug it */ | 287 | } |
| 287 | memset(to, 0, n); | 288 | if (unlikely(res)) |
| 288 | return n; | 289 | memset(to + (n - res), 0, res); |
| 290 | return res; | ||
| 289 | } | 291 | } |
| 290 | 292 | ||
| 291 | static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) | 293 | static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) |
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 0b90497d4424..4fd67ea03bb0 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S | |||
| @@ -79,11 +79,6 @@ ENDPROC(__arch_copy_from_user) | |||
| 79 | 79 | ||
| 80 | .section .fixup,"ax" | 80 | .section .fixup,"ax" |
| 81 | .align 2 | 81 | .align 2 |
| 82 | 9998: | 82 | 9998: sub x0, end, dst // bytes not copied |
| 83 | sub x0, end, dst | ||
| 84 | 9999: | ||
| 85 | strb wzr, [dst], #1 // zero remaining buffer space | ||
| 86 | cmp dst, end | ||
| 87 | b.lo 9999b | ||
| 88 | ret | 83 | ret |
| 89 | .previous | 84 | .previous |
diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index 0a2a70096d8b..0eff88aa6d6a 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h | |||
| @@ -163,18 +163,29 @@ static inline int bad_user_access_length(void) | |||
| 163 | : "a" (__ptr(ptr))); \ | 163 | : "a" (__ptr(ptr))); \ |
| 164 | }) | 164 | }) |
| 165 | 165 | ||
| 166 | #define __copy_from_user(to, from, n) copy_from_user(to, from, n) | ||
| 167 | #define __copy_to_user(to, from, n) copy_to_user(to, from, n) | ||
| 168 | #define __copy_to_user_inatomic __copy_to_user | 166 | #define __copy_to_user_inatomic __copy_to_user |
| 169 | #define __copy_from_user_inatomic __copy_from_user | 167 | #define __copy_from_user_inatomic __copy_from_user |
| 170 | 168 | ||
| 171 | static inline unsigned long __must_check | 169 | static inline unsigned long __must_check |
| 170 | __copy_from_user(void *to, const void __user *from, unsigned long n) | ||
| 171 | { | ||
| 172 | memcpy(to, (const void __force *)from, n); | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | static inline unsigned long __must_check | ||
| 177 | __copy_to_user(void __user *to, const void *from, unsigned long n) | ||
| 178 | { | ||
| 179 | memcpy((void __force *)to, from, n); | ||
| 180 | SSYNC(); | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static inline unsigned long __must_check | ||
| 172 | copy_from_user(void *to, const void __user *from, unsigned long n) | 185 | copy_from_user(void *to, const void __user *from, unsigned long n) |
| 173 | { | 186 | { |
| 174 | if (likely(access_ok(VERIFY_READ, from, n))) { | 187 | if (likely(access_ok(VERIFY_READ, from, n))) |
| 175 | memcpy(to, (const void __force *)from, n); | 188 | return __copy_from_user(to, from, n); |
| 176 | return 0; | ||
| 177 | } | ||
| 178 | memset(to, 0, n); | 189 | memset(to, 0, n); |
| 179 | return n; | 190 | return n; |
| 180 | } | 191 | } |
| @@ -182,12 +193,9 @@ copy_from_user(void *to, const void __user *from, unsigned long n) | |||
| 182 | static inline unsigned long __must_check | 193 | static inline unsigned long __must_check |
| 183 | copy_to_user(void __user *to, const void *from, unsigned long n) | 194 | copy_to_user(void __user *to, const void *from, unsigned long n) |
| 184 | { | 195 | { |
| 185 | if (access_ok(VERIFY_WRITE, to, n)) | 196 | if (likely(access_ok(VERIFY_WRITE, to, n))) |
| 186 | memcpy((void __force *)to, from, n); | 197 | return __copy_to_user(to, from, n); |
| 187 | else | 198 | return n; |
| 188 | return n; | ||
| 189 | SSYNC(); | ||
| 190 | return 0; | ||
| 191 | } | 199 | } |
| 192 | 200 | ||
| 193 | /* | 201 | /* |
diff --git a/arch/score/kernel/traps.c b/arch/score/kernel/traps.c index 1517a7dcd6d9..5cea1e750cec 100644 --- a/arch/score/kernel/traps.c +++ b/arch/score/kernel/traps.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
| 30 | #include <asm/irq.h> | 30 | #include <asm/irq.h> |
| 31 | #include <asm/irq_regs.h> | 31 | #include <asm/irq_regs.h> |
| 32 | #include <asm/uaccess.h> | ||
| 32 | 33 | ||
| 33 | unsigned long exception_handlers[32]; | 34 | unsigned long exception_handlers[32]; |
| 34 | 35 | ||
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 89182c4e2e30..bcf3965be819 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
| @@ -1303,6 +1303,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1303 | if (!oe) | 1303 | if (!oe) |
| 1304 | goto out_put_cred; | 1304 | goto out_put_cred; |
| 1305 | 1305 | ||
| 1306 | sb->s_magic = OVERLAYFS_SUPER_MAGIC; | ||
| 1307 | sb->s_op = &ovl_super_operations; | ||
| 1308 | sb->s_xattr = ovl_xattr_handlers; | ||
| 1309 | sb->s_fs_info = ufs; | ||
| 1310 | sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK; | ||
| 1311 | |||
| 1306 | root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR)); | 1312 | root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR)); |
| 1307 | if (!root_dentry) | 1313 | if (!root_dentry) |
| 1308 | goto out_free_oe; | 1314 | goto out_free_oe; |
| @@ -1326,12 +1332,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1326 | ovl_inode_init(d_inode(root_dentry), realinode, !!upperpath.dentry); | 1332 | ovl_inode_init(d_inode(root_dentry), realinode, !!upperpath.dentry); |
| 1327 | ovl_copyattr(realinode, d_inode(root_dentry)); | 1333 | ovl_copyattr(realinode, d_inode(root_dentry)); |
| 1328 | 1334 | ||
| 1329 | sb->s_magic = OVERLAYFS_SUPER_MAGIC; | ||
| 1330 | sb->s_op = &ovl_super_operations; | ||
| 1331 | sb->s_xattr = ovl_xattr_handlers; | ||
| 1332 | sb->s_root = root_dentry; | 1335 | sb->s_root = root_dentry; |
| 1333 | sb->s_fs_info = ufs; | ||
| 1334 | sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK; | ||
| 1335 | 1336 | ||
| 1336 | return 0; | 1337 | return 0; |
| 1337 | 1338 | ||
diff --git a/fs/read_write.c b/fs/read_write.c index 66215a7b17cf..190e0d362581 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -730,6 +730,35 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, | |||
| 730 | /* A write operation does a read from user space and vice versa */ | 730 | /* A write operation does a read from user space and vice versa */ |
| 731 | #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) | 731 | #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) |
| 732 | 732 | ||
| 733 | /** | ||
| 734 | * rw_copy_check_uvector() - Copy an array of &struct iovec from userspace | ||
| 735 | * into the kernel and check that it is valid. | ||
| 736 | * | ||
| 737 | * @type: One of %CHECK_IOVEC_ONLY, %READ, or %WRITE. | ||
| 738 | * @uvector: Pointer to the userspace array. | ||
| 739 | * @nr_segs: Number of elements in userspace array. | ||
| 740 | * @fast_segs: Number of elements in @fast_pointer. | ||
| 741 | * @fast_pointer: Pointer to (usually small on-stack) kernel array. | ||
| 742 | * @ret_pointer: (output parameter) Pointer to a variable that will point to | ||
| 743 | * either @fast_pointer, a newly allocated kernel array, or NULL, | ||
| 744 | * depending on which array was used. | ||
| 745 | * | ||
| 746 | * This function copies an array of &struct iovec of @nr_segs from | ||
| 747 | * userspace into the kernel and checks that each element is valid (e.g. | ||
| 748 | * it does not point to a kernel address or cause overflow by being too | ||
| 749 | * large, etc.). | ||
| 750 | * | ||
| 751 | * As an optimization, the caller may provide a pointer to a small | ||
| 752 | * on-stack array in @fast_pointer, typically %UIO_FASTIOV elements long | ||
| 753 | * (the size of this array, or 0 if unused, should be given in @fast_segs). | ||
| 754 | * | ||
| 755 | * @ret_pointer will always point to the array that was used, so the | ||
| 756 | * caller must take care not to call kfree() on it e.g. in case the | ||
| 757 | * @fast_pointer array was used and it was allocated on the stack. | ||
| 758 | * | ||
| 759 | * Return: The total number of bytes covered by the iovec array on success | ||
| 760 | * or a negative error code on error. | ||
| 761 | */ | ||
| 733 | ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, | 762 | ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, |
| 734 | unsigned long nr_segs, unsigned long fast_segs, | 763 | unsigned long nr_segs, unsigned long fast_segs, |
| 735 | struct iovec *fast_pointer, | 764 | struct iovec *fast_pointer, |
diff --git a/fs/super.c b/fs/super.c index c2ff475c1711..c183835566c1 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -1269,25 +1269,34 @@ EXPORT_SYMBOL(__sb_start_write); | |||
| 1269 | static void sb_wait_write(struct super_block *sb, int level) | 1269 | static void sb_wait_write(struct super_block *sb, int level) |
| 1270 | { | 1270 | { |
| 1271 | percpu_down_write(sb->s_writers.rw_sem + level-1); | 1271 | percpu_down_write(sb->s_writers.rw_sem + level-1); |
| 1272 | /* | ||
| 1273 | * We are going to return to userspace and forget about this lock, the | ||
| 1274 | * ownership goes to the caller of thaw_super() which does unlock. | ||
| 1275 | * | ||
| 1276 | * FIXME: we should do this before return from freeze_super() after we | ||
| 1277 | * called sync_filesystem(sb) and s_op->freeze_fs(sb), and thaw_super() | ||
| 1278 | * should re-acquire these locks before s_op->unfreeze_fs(sb). However | ||
| 1279 | * this leads to lockdep false-positives, so currently we do the early | ||
| 1280 | * release right after acquire. | ||
| 1281 | */ | ||
| 1282 | percpu_rwsem_release(sb->s_writers.rw_sem + level-1, 0, _THIS_IP_); | ||
| 1283 | } | 1272 | } |
| 1284 | 1273 | ||
| 1285 | static void sb_freeze_unlock(struct super_block *sb) | 1274 | /* |
| 1275 | * We are going to return to userspace and forget about these locks, the | ||
| 1276 | * ownership goes to the caller of thaw_super() which does unlock(). | ||
| 1277 | */ | ||
| 1278 | static void lockdep_sb_freeze_release(struct super_block *sb) | ||
| 1279 | { | ||
| 1280 | int level; | ||
| 1281 | |||
| 1282 | for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--) | ||
| 1283 | percpu_rwsem_release(sb->s_writers.rw_sem + level, 0, _THIS_IP_); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | /* | ||
| 1287 | * Tell lockdep we are holding these locks before we call ->unfreeze_fs(sb). | ||
| 1288 | */ | ||
| 1289 | static void lockdep_sb_freeze_acquire(struct super_block *sb) | ||
| 1286 | { | 1290 | { |
| 1287 | int level; | 1291 | int level; |
| 1288 | 1292 | ||
| 1289 | for (level = 0; level < SB_FREEZE_LEVELS; ++level) | 1293 | for (level = 0; level < SB_FREEZE_LEVELS; ++level) |
| 1290 | percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_); | 1294 | percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_); |
| 1295 | } | ||
| 1296 | |||
| 1297 | static void sb_freeze_unlock(struct super_block *sb) | ||
| 1298 | { | ||
| 1299 | int level; | ||
| 1291 | 1300 | ||
| 1292 | for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--) | 1301 | for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--) |
| 1293 | percpu_up_write(sb->s_writers.rw_sem + level); | 1302 | percpu_up_write(sb->s_writers.rw_sem + level); |
| @@ -1379,10 +1388,11 @@ int freeze_super(struct super_block *sb) | |||
| 1379 | } | 1388 | } |
| 1380 | } | 1389 | } |
| 1381 | /* | 1390 | /* |
| 1382 | * This is just for debugging purposes so that fs can warn if it | 1391 | * For debugging purposes so that fs can warn if it sees write activity |
| 1383 | * sees write activity when frozen is set to SB_FREEZE_COMPLETE. | 1392 | * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super(). |
| 1384 | */ | 1393 | */ |
| 1385 | sb->s_writers.frozen = SB_FREEZE_COMPLETE; | 1394 | sb->s_writers.frozen = SB_FREEZE_COMPLETE; |
| 1395 | lockdep_sb_freeze_release(sb); | ||
| 1386 | up_write(&sb->s_umount); | 1396 | up_write(&sb->s_umount); |
| 1387 | return 0; | 1397 | return 0; |
| 1388 | } | 1398 | } |
| @@ -1399,7 +1409,7 @@ int thaw_super(struct super_block *sb) | |||
| 1399 | int error; | 1409 | int error; |
| 1400 | 1410 | ||
| 1401 | down_write(&sb->s_umount); | 1411 | down_write(&sb->s_umount); |
| 1402 | if (sb->s_writers.frozen == SB_UNFROZEN) { | 1412 | if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) { |
| 1403 | up_write(&sb->s_umount); | 1413 | up_write(&sb->s_umount); |
| 1404 | return -EINVAL; | 1414 | return -EINVAL; |
| 1405 | } | 1415 | } |
| @@ -1409,11 +1419,14 @@ int thaw_super(struct super_block *sb) | |||
| 1409 | goto out; | 1419 | goto out; |
| 1410 | } | 1420 | } |
| 1411 | 1421 | ||
| 1422 | lockdep_sb_freeze_acquire(sb); | ||
| 1423 | |||
| 1412 | if (sb->s_op->unfreeze_fs) { | 1424 | if (sb->s_op->unfreeze_fs) { |
| 1413 | error = sb->s_op->unfreeze_fs(sb); | 1425 | error = sb->s_op->unfreeze_fs(sb); |
| 1414 | if (error) { | 1426 | if (error) { |
| 1415 | printk(KERN_ERR | 1427 | printk(KERN_ERR |
| 1416 | "VFS:Filesystem thaw failed\n"); | 1428 | "VFS:Filesystem thaw failed\n"); |
| 1429 | lockdep_sb_freeze_release(sb); | ||
| 1417 | up_write(&sb->s_umount); | 1430 | up_write(&sb->s_umount); |
| 1418 | return error; | 1431 | return error; |
| 1419 | } | 1432 | } |
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 7312e7784611..f0c7f1481bae 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
| @@ -1139,6 +1139,28 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) | |||
| 1139 | } | 1139 | } |
| 1140 | EXPORT_SYMBOL(dup_iter); | 1140 | EXPORT_SYMBOL(dup_iter); |
| 1141 | 1141 | ||
| 1142 | /** | ||
| 1143 | * import_iovec() - Copy an array of &struct iovec from userspace | ||
| 1144 | * into the kernel, check that it is valid, and initialize a new | ||
| 1145 | * &struct iov_iter iterator to access it. | ||
| 1146 | * | ||
| 1147 | * @type: One of %READ or %WRITE. | ||
| 1148 | * @uvector: Pointer to the userspace array. | ||
| 1149 | * @nr_segs: Number of elements in userspace array. | ||
| 1150 | * @fast_segs: Number of elements in @iov. | ||
| 1151 | * @iov: (input and output parameter) Pointer to pointer to (usually small | ||
| 1152 | * on-stack) kernel array. | ||
| 1153 | * @i: Pointer to iterator that will be initialized on success. | ||
| 1154 | * | ||
| 1155 | * If the array pointed to by *@iov is large enough to hold all @nr_segs, | ||
| 1156 | * then this function places %NULL in *@iov on return. Otherwise, a new | ||
| 1157 | * array will be allocated and the result placed in *@iov. This means that | ||
| 1158 | * the caller may call kfree() on *@iov regardless of whether the small | ||
| 1159 | * on-stack array was used or not (and regardless of whether this function | ||
| 1160 | * returns an error or not). | ||
| 1161 | * | ||
| 1162 | * Return: 0 on success or negative error code on error. | ||
| 1163 | */ | ||
| 1142 | int import_iovec(int type, const struct iovec __user * uvector, | 1164 | int import_iovec(int type, const struct iovec __user * uvector, |
| 1143 | unsigned nr_segs, unsigned fast_segs, | 1165 | unsigned nr_segs, unsigned fast_segs, |
| 1144 | struct iovec **iov, struct iov_iter *i) | 1166 | struct iovec **iov, struct iov_iter *i) |
