diff options
author | Steve Magnani <steve.magnani@digidescorp.com> | 2017-10-12 09:48:40 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-10-17 05:56:45 -0400 |
commit | b490bdd630cc43a5725e76c7c23f8a7e55551145 (patch) | |
tree | 9ee95e0af7d247b2a8b282b2b5ed1a783465e9da /fs/udf/udfdecl.h | |
parent | 503c3117d05c184b431e403cd05c463ac41370f0 (diff) |
udf: Fix 64-bit sign extension issues affecting blocks > 0x7FFFFFFF
Large (> 1 TiB) UDF filesystems appear subject to several problems when
mounted on 64-bit systems:
* readdir() can fail on a directory containing File Identifiers residing
above 0x7FFFFFFF. This manifests as a 'ls' command failing with EIO.
* FIBMAP on a file block located above 0x7FFFFFFF can return a negative
value. The low 32 bits are correct, but applications that don't mask the
high 32 bits of the result can perform incorrectly.
Per suggestion by Jan Kara, introduce a udf_pblk_t type for representation
of UDF block addresses. Ultimately, all driver functions that manipulate
UDF block addresses should use this type; for now, deployment is limited
to functions with actual or potential sign extension issues.
Changes to udf_readdir() and udf_block_map() address the issues noted
above; other changes address potential similar issues uncovered during
audit of the driver code.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf/udfdecl.h')
-rw-r--r-- | fs/udf/udfdecl.h | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 63b034984378..8e51704fd75d 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
@@ -73,6 +73,8 @@ static inline size_t udf_ext0_offset(struct inode *inode) | |||
73 | /* computes tag checksum */ | 73 | /* computes tag checksum */ |
74 | u8 udf_tag_checksum(const struct tag *t); | 74 | u8 udf_tag_checksum(const struct tag *t); |
75 | 75 | ||
76 | typedef uint32_t udf_pblk_t; | ||
77 | |||
76 | struct dentry; | 78 | struct dentry; |
77 | struct inode; | 79 | struct inode; |
78 | struct task_struct; | 80 | struct task_struct; |
@@ -144,15 +146,17 @@ static inline struct inode *udf_iget(struct super_block *sb, | |||
144 | return __udf_iget(sb, ino, false); | 146 | return __udf_iget(sb, ino, false); |
145 | } | 147 | } |
146 | extern int udf_expand_file_adinicb(struct inode *); | 148 | extern int udf_expand_file_adinicb(struct inode *); |
147 | extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *); | 149 | extern struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, |
148 | extern struct buffer_head *udf_bread(struct inode *, int, int, int *); | 150 | udf_pblk_t *block, int *err); |
151 | extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block, | ||
152 | int create, int *err); | ||
149 | extern int udf_setsize(struct inode *, loff_t); | 153 | extern int udf_setsize(struct inode *, loff_t); |
150 | extern void udf_evict_inode(struct inode *); | 154 | extern void udf_evict_inode(struct inode *); |
151 | extern int udf_write_inode(struct inode *, struct writeback_control *wbc); | 155 | extern int udf_write_inode(struct inode *, struct writeback_control *wbc); |
152 | extern long udf_block_map(struct inode *, sector_t); | 156 | extern udf_pblk_t udf_block_map(struct inode *inode, sector_t block); |
153 | extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, | 157 | extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, |
154 | struct kernel_lb_addr *, uint32_t *, sector_t *); | 158 | struct kernel_lb_addr *, uint32_t *, sector_t *); |
155 | extern int udf_setup_indirect_aext(struct inode *inode, int block, | 159 | extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, |
156 | struct extent_position *epos); | 160 | struct extent_position *epos); |
157 | extern int __udf_add_aext(struct inode *inode, struct extent_position *epos, | 161 | extern int __udf_add_aext(struct inode *inode, struct extent_position *epos, |
158 | struct kernel_lb_addr *eloc, uint32_t elen, int inc); | 162 | struct kernel_lb_addr *eloc, uint32_t elen, int inc); |
@@ -168,8 +172,9 @@ extern int8_t udf_current_aext(struct inode *, struct extent_position *, | |||
168 | struct kernel_lb_addr *, uint32_t *, int); | 172 | struct kernel_lb_addr *, uint32_t *, int); |
169 | 173 | ||
170 | /* misc.c */ | 174 | /* misc.c */ |
171 | extern struct buffer_head *udf_tgetblk(struct super_block *, int); | 175 | extern struct buffer_head *udf_tgetblk(struct super_block *sb, |
172 | extern struct buffer_head *udf_tread(struct super_block *, int); | 176 | udf_pblk_t block); |
177 | extern struct buffer_head *udf_tread(struct super_block *sb, udf_pblk_t block); | ||
173 | extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, | 178 | extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, |
174 | uint32_t, uint8_t); | 179 | uint32_t, uint8_t); |
175 | extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, | 180 | extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, |
@@ -228,8 +233,8 @@ extern void udf_free_blocks(struct super_block *, struct inode *, | |||
228 | struct kernel_lb_addr *, uint32_t, uint32_t); | 233 | struct kernel_lb_addr *, uint32_t, uint32_t); |
229 | extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, | 234 | extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, |
230 | uint32_t, uint32_t); | 235 | uint32_t, uint32_t); |
231 | extern int udf_new_block(struct super_block *, struct inode *, uint16_t, | 236 | extern udf_pblk_t udf_new_block(struct super_block *sb, struct inode *inode, |
232 | uint32_t, int *); | 237 | uint16_t partition, uint32_t goal, int *err); |
233 | 238 | ||
234 | /* directory.c */ | 239 | /* directory.c */ |
235 | extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *, | 240 | extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *, |