[LU-7315] In osd_dirent_check_repair(), Pointer 'hlock' can be NULL and can be dereferenced Created: 19/Oct/15  Updated: 04/Dec/15  Resolved: 04/Dec/15

Status: Resolved
Project: Lustre
Component/s: None
Affects Version/s: None
Fix Version/s: Lustre 2.8.0

Type: Bug Priority: Major
Reporter: Dmitry Eremin (Inactive) Assignee: nasf (Inactive)
Resolution: Fixed Votes: 0
Labels: kw

Issue Links:
Related
is related to LU-6895 sanity-lfsck test 4 hung: bad entry i... Resolved
Severity: 3
Rank (Obsolete): 9223372036854775807

 Description   
  1. Pointer may be passed to function that can dereference it after it was positively checked for NULL
    • lustre/osd-ldiskfs/osd_handler.c: in osd_dirent_check_repair, Pointer 'hlock' checked for NULL at line 5478 may be passed to function and may be dereferenced there by passing argument 4 to function '__ldiskfs_find_entry' at line 5353. Also there are 2 similar errors on lines 5353.
  2. Null pointer may be passed to function that may dereference it
    • lustre/osd-ldiskfs/osd_handler.c: in osd_dirent_check_repair, Null pointer 'hlock' that comes from line 5257 may be passed to function and can be dereferenced there by passing argument 4 to function '__ldiskfs_find_entry' at line 5353.

The list of commits since the previous build 2.7.61-9-g4438262:

723065f LU-6868 mdd: add changelog for migration
3c86f72 LU-7295 osp: do not warn on uncommitted changes
9ea40a3 LU-6746 ptlrpc: Move IT_* definitions to lustre_idl.h
4691290 LU-6556 obdclass: re-allow catalog to wrap around
ef63c03 LU-4341 test: skip failing sanity test 170
e94d375 LU-7153 build: Update SPL/ZFS to 0.6.5.2
10ebe81 LU-6155 osd-zfs: dbuf_hold_impl() called without the lock
bee9c18 LU-6852 ldlm: Do not evict MDS-MDS connection
cc0733f LU-6215 lnet: make o2iblnd buildable for 4.2.1 kernels
31b7404 LU-2049 grant: delay grant releasing until commit
dd16884 LU-6204 misc: Add missing MODULE_VERSION for lustre
2907eb6 LU-7244 llite: Fix XATTR_NAME_EVM redefinition
173b332 LU-7122 utils: changelog_ {de}

register cleanup

bc17c8d LU-6899 test: rename sanity test_162 to test_162a
1443374 LU-5733 lnet: Use lnet_is_route_alive for router aliveness
d2d725d LU-7184 lod: cleanup unused OSP devices on error
d8612e3 LU-6895 scrub: not trigger scrub if inode removed by race
eebc3da LU-6895 lfsck: not destroy directory when fix FID-in-dirent
5fa93f6 LU-6386 tgt: don't update client data with smaller transno
85c6c09 LU-7045 osd: enough credits for single indirect block write
888a314 LU-6842 clio: add cl_page LRU shrinker
7b56957 LU-7005 tests: wait client imports fully recovered
e72c150 LU-7196 kernel: kernel update RHEL 6.7 [2.6.32-573.7.1.el6]
cbb42d0 LU-6886 mdd: declare changelog store for POSIX ACLs
4d4771b LU-7074 mdd: validate the linkea before packing
adce06a LU-7228 build: make lustre rpm also provide lustre-client
9937eb5 LU-7082 test: fix synchronization of conf_sanity test_90
a2844eb LU-6215 ldlm: handle percpu_counter_init change in 3.18+ kernels
55afbf5 LU-6527 ext4: journal_commit_callback optimization
7f5c975 LU-3322 ko2iblnd: Support different configs between systems
efe3842 LU-6584 osd: prevent int type overflow in osd_read_prep()
881b288 LU-7222 tests: add Mulitple MDTs to test_84
790ca7b LU-3281 obdclass: remove structure holes to reduce memory
846efa4 LU-7162 kernel: kernel update RHEL 7.1 [3.10.0-229.14.1.el7]
c250f40 Revert "LU-5951 ptlrpc: track unreplied requests"


 Comments   
Comment by Andreas Dilger [ 19/Oct/15 ]

It looks like this was added by http://review.whamcloud.com/16440 "LU-6895 lfsck: not destroy directory when fix FID-in-dirent" when it landed.

Fan Yong, could you please take a look.

Comment by nasf (Inactive) [ 23/Oct/15 ]

Inside the function osd_dirent_check_repair(), anytime before it "goto again", it will call as following:

                if (jh == NULL) {
                        brelse(bh);
                        if (hlock != NULL)
                                ldiskfs_htree_unlock(hlock);
                        else
                                up_read(&obj->oo_ext_idx_sem);
                        dev->od_dirent_journal = 1;

                        goto again;
                }

Means the "hlock" or "oo_ext_idx_sem" will be unlock/up before "goto again". Then the logic goes to the label "again":

        if (dev->od_dirent_journal != 0) {

again:
                jh = osd_journal_start_sb(sb, LDISKFS_HT_MISC, credits);
                if (IS_ERR(jh)) {
                        rc = PTR_ERR(jh);
                        CDEBUG(D_LFSCK, "%.16s: fail to start trans for dirent "
                               "check_repair, dir = %lu/%u, credits = %d, "
                               "name = %.*s: rc = %d\n",
                               devname, dir->i_ino, dir->i_generation, credits,
                               ent->oied_namelen, ent->oied_name, rc);

                        GOTO(out_inode, rc);
                }

                if (obj->oo_hl_head != NULL) {
                        hlock = osd_oti_get(env)->oti_hlock;
                        /* "0" means exclusive lock for the whole directory.
                         * We need to prevent others access such name entry
                         * during the delete + insert. Neither HLOCK_ADD nor
                         * HLOCK_DEL cannot guarantee the atomicity. */
                        ldiskfs_htree_lock(hlock, obj->oo_hl_head, dir, 0);
                } else {
                        down_write(&obj->oo_ext_idx_sem);
                }
        } else {
...
out_inode:
        iput(inode);
        if (rc >= 0 && !dirty)
                dev->od_dirent_journal = 0;

        return rc;

As you can see, it will try to start journal firstly, if it failed, then "GOTO(out_inode, rc);", at the label "out_inode", it will not handle "hlock" or "oo_ext_idx_sem", because either "hlock" or "oo_ext_idx_sem" has been unlocked/up, or it has not been lock/down (for the first time).

If journal has been started successfully, then it will try to lock/down the "hlock" or "oo_ext_idx_sem". After that, all elements become valid. The "obj->oo_hl_head" cannot be changed once it has been set, so if "hlock" is not NULL before the "goto again", then it will still be non-NULL after the "goto again". So the whole logic is safe.

Anyway, I know what you worry about, I will make patch to reset the "hlock" explicitly to the logic to be easy for the readers.

Comment by Gerrit Updater [ 23/Oct/15 ]

Fan Yong (fan.yong@intel.com) uploaded a new patch: http://review.whamcloud.com/16924
Subject: LU-7315 osd-ldiskfs: reset lock variable after unlock
Project: fs/lustre-release
Branch: master
Current Patch Set: 1
Commit: acbdb3581ee53b385838c3f69c0441553e9fad36

Comment by Dmitry Eremin (Inactive) [ 17/Nov/15 ]

The tool reports the different path of this issue.
TRACEBACK:

osd_handler.c:5404: 'hlock' is checked for NULL.
osd_handler.c:5404: hlock!= ( (void* )0) is false
osd_handler.c:5333: obj->oo_hl_head!= ( (void* )0) is false
osd_handler.c:5353: 'hlock' is dereferenced by passing argument 4 to function '__ldiskfs_find_entry'.
	namei.c:1215: 'lck' is passed to function '__ldiskfs_find_entry'.
	namei.c:1236: 'lck' is dereferenced by passing argument 4 to function 'ldiskfs_dx_find_entry'.
		namei.c:1327: 'lck' is passed to function 'ldiskfs_dx_find_entry'.
		namei.c:1343: 'lck' is dereferenced by passing argument 5 to function 'dx_probe'.
			namei.c:594: 'lck' is passed to function 'dx_probe'.
			namei.c:618: hinfo->hash_version<=2 is true
			namei.c:690: 0 is false
			namei.c:727: ldiskfs_htree_node_locked(lck, LDISKFS_LB_DX) is false
			namei.c:736: 'lck' is dereferenced by passing argument 1 to function 'dx_probe_hash_collision'.
				namei.c:566: 'lck' is passed to function 'dx_probe_hash_collision'.
				namei.c:570: 'lck' is explicitly dereferenced.
Comment by nasf (Inactive) [ 18/Nov/15 ]

Hm... That is a different story in the original PDO patch, not related with the recent landed patch http://review.whamcloud.com/16440. I have updated the patch to fix that.

Please help to analysis the new code with tools. Thanks!

Comment by Dmitry Eremin (Inactive) [ 18/Nov/15 ]

Now tool don't detect issue with lck.

Comment by Gerrit Updater [ 04/Dec/15 ]

Oleg Drokin (oleg.drokin@intel.com) merged in patch http://review.whamcloud.com/16924/
Subject: LU-7315 osd-ldiskfs: handle pdo lock properly
Project: fs/lustre-release
Branch: master
Current Patch Set:
Commit: 343364d0f06c34f403eb009de498455b5ebe14be

Comment by Joseph Gmitter (Inactive) [ 04/Dec/15 ]

Landed for 2.8

Generated at Sat Feb 10 02:07:50 UTC 2024 using Jira 9.4.14#940014-sha1:734e6822bbf0d45eff9af51f82432957f73aa32c.