Skip to content

Commit a11b4fa

Browse files
committed
Pull ntfs3 updates from Konstantin Komarov: "Added: - sanity check for file name - mark live inode as bad and avoid any operations Fixed: - handling of symlinks created in windows - creation of symlinks for relative path Changed: - cancel setting inode as bad after removing name fails - revert 'replace inode_trylock with inode_lock'" * tag 'ntfs3_for_6.17' of https://github.com/Paragon-Software-Group/linux-ntfs3: Revert "fs/ntfs3: Replace inode_trylock with inode_lock" fs/ntfs3: Exclude call make_bad_inode for live nodes. fs/ntfs3: cancle set bad inode after removing name fails fs/ntfs3: Add sanity check for file name fs/ntfs3: correctly create symlink for relative path fs/ntfs3: fix symlinks cannot be handled correctly
2 parents f92b71f + a49f0ab commit a11b4fa

9 files changed

Lines changed: 178 additions & 61 deletions

File tree

fs/ntfs3/dir.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,9 @@ static inline bool ntfs_dir_emit(struct ntfs_sb_info *sbi,
304304
if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
305305
return true;
306306

307+
if (fname->name_len + sizeof(struct NTFS_DE) > le16_to_cpu(e->size))
308+
return true;
309+
307310
name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name,
308311
PATH_MAX);
309312
if (name_len <= 0) {
@@ -329,8 +332,7 @@ static inline bool ntfs_dir_emit(struct ntfs_sb_info *sbi,
329332
* It does additional locks/reads just to get the type of name.
330333
* Should we use additional mount option to enable branch below?
331334
*/
332-
if (((fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT) ||
333-
fname->dup.ea_size) &&
335+
if (fname->dup.extend_data &&
334336
ino != ni->mi.rno) {
335337
struct inode *inode = ntfs_iget5(sbi->sb, &e->ref, NULL);
336338
if (!IS_ERR_OR_NULL(inode)) {

fs/ntfs3/file.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ long ntfs_ioctl(struct file *filp, u32 cmd, unsigned long arg)
5757
struct inode *inode = file_inode(filp);
5858
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
5959

60+
/* Avoid any operation if inode is bad. */
61+
if (unlikely(is_bad_ni(ntfs_i(inode))))
62+
return -EINVAL;
63+
6064
switch (cmd) {
6165
case FITRIM:
6266
return ntfs_ioctl_fitrim(sbi, arg);
@@ -81,6 +85,10 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
8185
struct inode *inode = d_inode(path->dentry);
8286
struct ntfs_inode *ni = ntfs_i(inode);
8387

88+
/* Avoid any operation if inode is bad. */
89+
if (unlikely(is_bad_ni(ni)))
90+
return -EINVAL;
91+
8492
stat->result_mask |= STATX_BTIME;
8593
stat->btime = ni->i_crtime;
8694
stat->blksize = ni->mi.sbi->cluster_size; /* 512, 1K, ..., 2M */
@@ -271,6 +279,10 @@ static int ntfs_file_mmap(struct file *file, struct vm_area_struct *vma)
271279
bool rw = vma->vm_flags & VM_WRITE;
272280
int err;
273281

282+
/* Avoid any operation if inode is bad. */
283+
if (unlikely(is_bad_ni(ni)))
284+
return -EINVAL;
285+
274286
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
275287
return -EIO;
276288

@@ -310,7 +322,10 @@ static int ntfs_file_mmap(struct file *file, struct vm_area_struct *vma)
310322
}
311323

312324
if (ni->i_valid < to) {
313-
inode_lock(inode);
325+
if (!inode_trylock(inode)) {
326+
err = -EAGAIN;
327+
goto out;
328+
}
314329
err = ntfs_extend_initialized_size(file, ni,
315330
ni->i_valid, to);
316331
inode_unlock(inode);
@@ -735,6 +750,10 @@ int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
735750
umode_t mode = inode->i_mode;
736751
int err;
737752

753+
/* Avoid any operation if inode is bad. */
754+
if (unlikely(is_bad_ni(ni)))
755+
return -EINVAL;
756+
738757
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
739758
return -EIO;
740759

@@ -795,6 +814,10 @@ static int check_read_restriction(struct inode *inode)
795814
{
796815
struct ntfs_inode *ni = ntfs_i(inode);
797816

817+
/* Avoid any operation if inode is bad. */
818+
if (unlikely(is_bad_ni(ni)))
819+
return -EINVAL;
820+
798821
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
799822
return -EIO;
800823

@@ -1130,6 +1153,10 @@ static int check_write_restriction(struct inode *inode)
11301153
{
11311154
struct ntfs_inode *ni = ntfs_i(inode);
11321155

1156+
/* Avoid any operation if inode is bad. */
1157+
if (unlikely(is_bad_ni(ni)))
1158+
return -EINVAL;
1159+
11331160
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
11341161
return -EIO;
11351162

@@ -1212,6 +1239,10 @@ int ntfs_file_open(struct inode *inode, struct file *file)
12121239
{
12131240
struct ntfs_inode *ni = ntfs_i(inode);
12141241

1242+
/* Avoid any operation if inode is bad. */
1243+
if (unlikely(is_bad_ni(ni)))
1244+
return -EINVAL;
1245+
12151246
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
12161247
return -EIO;
12171248

@@ -1281,6 +1312,10 @@ int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
12811312
int err;
12821313
struct ntfs_inode *ni = ntfs_i(inode);
12831314

1315+
/* Avoid any operation if inode is bad. */
1316+
if (unlikely(is_bad_ni(ni)))
1317+
return -EINVAL;
1318+
12841319
err = fiemap_prep(inode, fieinfo, start, &len, ~FIEMAP_FLAG_XATTR);
12851320
if (err)
12861321
return err;

fs/ntfs3/frecord.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3003,8 +3003,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
30033003
* ni_rename - Remove one name and insert new name.
30043004
*/
30053005
int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
3006-
struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
3007-
bool *is_bad)
3006+
struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de)
30083007
{
30093008
int err;
30103009
struct NTFS_DE *de2 = NULL;
@@ -3027,8 +3026,8 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
30273026
err = ni_add_name(new_dir_ni, ni, new_de);
30283027
if (!err) {
30293028
err = ni_remove_name(dir_ni, ni, de, &de2, &undo);
3030-
if (err && ni_remove_name(new_dir_ni, ni, new_de, &de2, &undo))
3031-
*is_bad = true;
3029+
WARN_ON(err && ni_remove_name(new_dir_ni, ni, new_de, &de2,
3030+
&undo));
30323031
}
30333032

30343033
/*
@@ -3119,11 +3118,21 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
31193118
}
31203119
}
31213120

3122-
/* TODO: Fill reparse info. */
3123-
dup->reparse = 0;
3124-
dup->ea_size = 0;
3121+
dup->extend_data = 0;
31253122

3126-
if (ni->ni_flags & NI_FLAG_EA) {
3123+
if (dup->fa & FILE_ATTRIBUTE_REPARSE_POINT) {
3124+
attr = ni_find_attr(ni, NULL, NULL, ATTR_REPARSE, NULL, 0, NULL,
3125+
NULL);
3126+
3127+
if (attr) {
3128+
const struct REPARSE_POINT *rp;
3129+
3130+
rp = resident_data_ex(attr, sizeof(struct REPARSE_POINT));
3131+
/* If ATTR_REPARSE exists 'rp' can't be NULL. */
3132+
if (rp)
3133+
dup->extend_data = rp->ReparseTag;
3134+
}
3135+
} else if (ni->ni_flags & NI_FLAG_EA) {
31273136
attr = ni_find_attr(ni, attr, &le, ATTR_EA_INFO, NULL, 0, NULL,
31283137
NULL);
31293138
if (attr) {
@@ -3132,7 +3141,7 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
31323141
info = resident_data_ex(attr, sizeof(struct EA_INFO));
31333142
/* If ATTR_EA_INFO exists 'info' can't be NULL. */
31343143
if (info)
3135-
dup->ea_size = info->size_pack;
3144+
dup->extend_data = info->size;
31363145
}
31373146
}
31383147

@@ -3199,6 +3208,10 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
31993208
if (is_bad_inode(inode) || sb_rdonly(sb))
32003209
return 0;
32013210

3211+
/* Avoid any operation if inode is bad. */
3212+
if (unlikely(is_bad_ni(ni)))
3213+
return -EINVAL;
3214+
32023215
if (unlikely(ntfs3_forced_shutdown(sb)))
32033216
return -EIO;
32043217

fs/ntfs3/fsntfs.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,9 +905,13 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
905905
void ntfs_bad_inode(struct inode *inode, const char *hint)
906906
{
907907
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
908+
struct ntfs_inode *ni = ntfs_i(inode);
908909

909910
ntfs_inode_err(inode, "%s", hint);
910-
make_bad_inode(inode);
911+
912+
/* Do not call make_bad_inode()! */
913+
ni->ni_bad = true;
914+
911915
/* Avoid recursion if bad inode is $Volume. */
912916
if (inode->i_ino != MFT_REC_VOL &&
913917
!(sbi->flags & NTFS_FLAGS_LOG_REPLAYING)) {

fs/ntfs3/inode.c

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,10 @@ static int ntfs_resident_writepage(struct folio *folio,
878878
struct ntfs_inode *ni = ntfs_i(inode);
879879
int ret;
880880

881+
/* Avoid any operation if inode is bad. */
882+
if (unlikely(is_bad_ni(ni)))
883+
return -EINVAL;
884+
881885
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
882886
return -EIO;
883887

@@ -896,6 +900,10 @@ static int ntfs_writepages(struct address_space *mapping,
896900
{
897901
struct inode *inode = mapping->host;
898902

903+
/* Avoid any operation if inode is bad. */
904+
if (unlikely(is_bad_ni(ntfs_i(inode))))
905+
return -EINVAL;
906+
899907
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
900908
return -EIO;
901909

@@ -919,6 +927,10 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping,
919927
struct inode *inode = mapping->host;
920928
struct ntfs_inode *ni = ntfs_i(inode);
921929

930+
/* Avoid any operation if inode is bad. */
931+
if (unlikely(is_bad_ni(ni)))
932+
return -EINVAL;
933+
922934
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
923935
return -EIO;
924936

@@ -1062,10 +1074,10 @@ int inode_read_data(struct inode *inode, void *data, size_t bytes)
10621074
* Number of bytes for REPARSE_DATA_BUFFER(IO_REPARSE_TAG_SYMLINK)
10631075
* for unicode string of @uni_len length.
10641076
*/
1065-
static inline u32 ntfs_reparse_bytes(u32 uni_len)
1077+
static inline u32 ntfs_reparse_bytes(u32 uni_len, bool is_absolute)
10661078
{
10671079
/* Header + unicode string + decorated unicode string. */
1068-
return sizeof(short) * (2 * uni_len + 4) +
1080+
return sizeof(short) * (2 * uni_len + (is_absolute ? 4 : 0)) +
10691081
offsetof(struct REPARSE_DATA_BUFFER,
10701082
SymbolicLinkReparseBuffer.PathBuffer);
10711083
}
@@ -1078,8 +1090,11 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
10781090
struct REPARSE_DATA_BUFFER *rp;
10791091
__le16 *rp_name;
10801092
typeof(rp->SymbolicLinkReparseBuffer) *rs;
1093+
bool is_absolute;
10811094

1082-
rp = kzalloc(ntfs_reparse_bytes(2 * size + 2), GFP_NOFS);
1095+
is_absolute = (strlen(symname) > 1 && symname[1] == ':');
1096+
1097+
rp = kzalloc(ntfs_reparse_bytes(2 * size + 2, is_absolute), GFP_NOFS);
10831098
if (!rp)
10841099
return ERR_PTR(-ENOMEM);
10851100

@@ -1094,7 +1109,7 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
10941109
goto out;
10951110

10961111
/* err = the length of unicode name of symlink. */
1097-
*nsize = ntfs_reparse_bytes(err);
1112+
*nsize = ntfs_reparse_bytes(err, is_absolute);
10981113

10991114
if (*nsize > sbi->reparse.max_size) {
11001115
err = -EFBIG;
@@ -1114,24 +1129,26 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
11141129

11151130
/* PrintName + SubstituteName. */
11161131
rs->SubstituteNameOffset = cpu_to_le16(sizeof(short) * err);
1117-
rs->SubstituteNameLength = cpu_to_le16(sizeof(short) * err + 8);
1132+
rs->SubstituteNameLength = cpu_to_le16(sizeof(short) * err + (is_absolute ? 8 : 0));
11181133
rs->PrintNameLength = rs->SubstituteNameOffset;
11191134

11201135
/*
11211136
* TODO: Use relative path if possible to allow Windows to
11221137
* parse this path.
11231138
* 0-absolute path 1- relative path (SYMLINK_FLAG_RELATIVE).
11241139
*/
1125-
rs->Flags = 0;
1140+
rs->Flags = cpu_to_le32(is_absolute ? 0 : SYMLINK_FLAG_RELATIVE);
11261141

1127-
memmove(rp_name + err + 4, rp_name, sizeof(short) * err);
1142+
memmove(rp_name + err + (is_absolute ? 4 : 0), rp_name, sizeof(short) * err);
11281143

1129-
/* Decorate SubstituteName. */
1130-
rp_name += err;
1131-
rp_name[0] = cpu_to_le16('\\');
1132-
rp_name[1] = cpu_to_le16('?');
1133-
rp_name[2] = cpu_to_le16('?');
1134-
rp_name[3] = cpu_to_le16('\\');
1144+
if (is_absolute) {
1145+
/* Decorate SubstituteName. */
1146+
rp_name += err;
1147+
rp_name[0] = cpu_to_le16('\\');
1148+
rp_name[1] = cpu_to_le16('?');
1149+
rp_name[2] = cpu_to_le16('?');
1150+
rp_name[3] = cpu_to_le16('\\');
1151+
}
11351152

11361153
return rp;
11371154
out:
@@ -1260,6 +1277,12 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
12601277
goto out1;
12611278
}
12621279

1280+
/* Avoid any operation if inode is bad. */
1281+
if (unlikely(is_bad_ni(dir_ni))) {
1282+
err = -EINVAL;
1283+
goto out2;
1284+
}
1285+
12631286
if (unlikely(ntfs3_forced_shutdown(sb))) {
12641287
err = -EIO;
12651288
goto out2;
@@ -1350,7 +1373,7 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
13501373
fname->dup.a_time = std5->cr_time;
13511374
fname->dup.alloc_size = fname->dup.data_size = 0;
13521375
fname->dup.fa = std5->fa;
1353-
fname->dup.ea_size = fname->dup.reparse = 0;
1376+
fname->dup.extend_data = S_ISLNK(mode) ? IO_REPARSE_TAG_SYMLINK : 0;
13541377

13551378
dsize = le16_to_cpu(new_de->key_size);
13561379
asize = ALIGN(SIZEOF_RESIDENT + dsize, 8);
@@ -1590,27 +1613,29 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
15901613
inode->i_flags |= S_NOSEC;
15911614
}
15921615

1593-
/*
1594-
* ntfs_init_acl and ntfs_save_wsl_perm update extended attribute.
1595-
* The packed size of extended attribute is stored in direntry too.
1596-
* 'fname' here points to inside new_de.
1597-
*/
1598-
err = ntfs_save_wsl_perm(inode, &fname->dup.ea_size);
1599-
if (err)
1600-
goto out6;
1616+
if (!S_ISLNK(mode)) {
1617+
/*
1618+
* ntfs_init_acl and ntfs_save_wsl_perm update extended attribute.
1619+
* The packed size of extended attribute is stored in direntry too.
1620+
* 'fname' here points to inside new_de.
1621+
*/
1622+
err = ntfs_save_wsl_perm(inode, &fname->dup.extend_data);
1623+
if (err)
1624+
goto out6;
16011625

1602-
/*
1603-
* update ea_size in file_name attribute too.
1604-
* Use ni_find_attr cause layout of MFT record may be changed
1605-
* in ntfs_init_acl and ntfs_save_wsl_perm.
1606-
*/
1607-
attr = ni_find_attr(ni, NULL, NULL, ATTR_NAME, NULL, 0, NULL, NULL);
1608-
if (attr) {
1609-
struct ATTR_FILE_NAME *fn;
1626+
/*
1627+
* update ea_size in file_name attribute too.
1628+
* Use ni_find_attr cause layout of MFT record may be changed
1629+
* in ntfs_init_acl and ntfs_save_wsl_perm.
1630+
*/
1631+
attr = ni_find_attr(ni, NULL, NULL, ATTR_NAME, NULL, 0, NULL, NULL);
1632+
if (attr) {
1633+
struct ATTR_FILE_NAME *fn;
16101634

1611-
fn = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
1612-
if (fn)
1613-
fn->dup.ea_size = fname->dup.ea_size;
1635+
fn = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
1636+
if (fn)
1637+
fn->dup.extend_data = fname->dup.extend_data;
1638+
}
16141639
}
16151640

16161641
/* We do not need to update parent directory later */

0 commit comments

Comments
 (0)