Skip to content

Commit

Permalink
udf: Fix conversion of 'dstring' fields to UTF8
Browse files Browse the repository at this point in the history
Commit 9293fcf
("udf: Remove struct ustr as non-needed intermediate storage"),
while getting rid of 'struct ustr', does not take any special care
of 'dstring' fields and effectively use fixed field length instead
of actual string length, encoded in the last byte of the field.

Also, commit 484a10f
("udf: Merge linux specific translation into CS0 conversion function")
introduced checking of the length of the string being converted,
requiring proper alignment to number of bytes constituing each
character.

The UDF volume identifier is represented as a 32-bytes 'dstring',
and needs to be converted from CS0 to UTF8, while mounting UDF
filesystem. The changes in mentioned commits can in some cases
lead to incorrect handling of volume identifier:
- if the actual string in 'dstring' is of maximal length and
does not have zero bytes separating it from dstring encoded
length in last byte, that last byte may be included in conversion,
thus making incorrect resulting string;
- if the identifier is encoded with 2-bytes characters (compression
code is 16), the length of 31 bytes (32 bytes of field length minus
1 byte of compression code), taken as the string length, is reported
as an incorrect (unaligned) length, and the conversion fails, which
in its turn leads to volume mounting failure.

This patch introduces handling of 'dstring' encoded length field
in udf_CS0toUTF8 function, that is used in all and only cases
when 'dstring' fields are converted. Currently these cases are
processing of Volume Identifier and Volume Set Identifier fields.
The function is also renamed to udf_dstrCS0toUTF8 to distinctly
indicate that it handles 'dstring' input.

Signed-off-by: Andrew Gabbasov <[email protected]>
Signed-off-by: Jan Kara <[email protected]>
  • Loading branch information
agabbasov authored and jankara committed Apr 25, 2016
1 parent 95d0c42 commit c26f6c6
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 5 deletions.
4 changes: 2 additions & 2 deletions fs/udf/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -919,14 +919,14 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
#endif
}

ret = udf_CS0toUTF8(outstr, 31, pvoldesc->volIdent, 32);
ret = udf_dstrCS0toUTF8(outstr, 31, pvoldesc->volIdent, 32);
if (ret < 0)
goto out_bh;

strncpy(UDF_SB(sb)->s_volume_ident, outstr, ret);
udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident);

ret = udf_CS0toUTF8(outstr, 127, pvoldesc->volSetIdent, 128);
ret = udf_dstrCS0toUTF8(outstr, 127, pvoldesc->volSetIdent, 128);
if (ret < 0)
goto out_bh;

Expand Down
2 changes: 1 addition & 1 deletion fs/udf/udfdecl.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ extern int udf_get_filename(struct super_block *, const uint8_t *, int,
uint8_t *, int);
extern int udf_put_filename(struct super_block *, const uint8_t *, int,
uint8_t *, int);
extern int udf_CS0toUTF8(uint8_t *, int, const uint8_t *, int);
extern int udf_dstrCS0toUTF8(uint8_t *, int, const uint8_t *, int);

/* ialloc.c */
extern void udf_free_inode(struct inode *);
Expand Down
16 changes: 14 additions & 2 deletions fs/udf/unicode.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,21 @@ static int udf_name_to_CS0(uint8_t *ocu, int ocu_max_len,
return u_len;
}

int udf_CS0toUTF8(uint8_t *utf_o, int o_len, const uint8_t *ocu_i, int i_len)
int udf_dstrCS0toUTF8(uint8_t *utf_o, int o_len,
const uint8_t *ocu_i, int i_len)
{
return udf_name_from_CS0(utf_o, o_len, ocu_i, i_len,
int s_len = 0;

if (i_len > 0) {
s_len = ocu_i[i_len - 1];
if (s_len >= i_len) {
pr_err("incorrect dstring lengths (%d/%d)\n",
s_len, i_len);
return -EINVAL;
}
}

return udf_name_from_CS0(utf_o, o_len, ocu_i, s_len,
udf_uni2char_utf8, 0);
}

Expand Down

0 comments on commit c26f6c6

Please sign in to comment.