CVE-2017-18216 (C, published 2018-03-05T18:29Z)
Description: value: In fs/ocfs2/cluster/nodemanager.c in the Linux kernel before 4.15, local users can cause a denial of service (NULL pointer dereference and BUG) because a required mutex is not used.
Severity: LOW (CVSS v3 base score: 5.5)
Weakness: CWE-476 \u2014 NULL Pointer Dereference
The product dereferences a pointer that it expects to be valid but is NULL.
Repository: https://github.com/torvalds/linux
Files changed:
fs/ocfs2/cluster/nodemanager.c
Commit message: ocfs2: subsystem.su_mutex is required while accessing the item->ci_parent

The subsystem.su_mutex is required while accessing the item->ci_parent,
otherwise, NULL pointer dereference to the item->ci_parent will be
triggered in the following situation:

add node                     delete node
sys_write
 vfs_write
  configfs_write_file
   o2nm_node_store
    o2nm_node_local_write
                             do_rmdir
                              vfs_rmdir
                               configfs_rmdir
                                mutex_lock(&subsys->su_mutex);
                                unlink_obj
                                 item->ci_group = NULL;
                                 item->ci_parent = NULL;
	 to_o2nm_cluster_from_node
	  node->nd_item.ci_parent->ci_parent
	  BUG since of NULL pointer dereference to nd_item.ci_parent

Moreover, the o2nm_cluster also should be protected by the
subsystem.su_mutex.

[alex.chen@huawei.com: v2]
  Link: http://lkml.kernel.org/r/59EEAA69.9080703@huawei.com
Link: http://lkml.kernel.org/r/59E9B36A.10700@huawei.com
Signed-off-by: Alex Chen <alex.chen@huawei.com>
Reviewed-by: Jun Piao <piaojun@huawei.com>
Reviewed-by: Joseph Qi <jiangqi903@gmail.com>
Cc: Mark Fasheh <mfasheh@versity.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>


Vulnerable code:
	return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
	    cluster->cl_local_node != node->nd_num)
		return -EBUSY;
			return ret;
	return count;

Fixed code:
static inline void o2nm_lock_subsystem(void);
static inline void o2nm_unlock_subsystem(void);

	if (node->nd_item.ci_parent)
		return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
	else
		return NULL;
	struct o2nm_cluster *cluster;
	o2nm_lock_subsystem();
	cluster = to_o2nm_cluster_from_node(node);
	if (!cluster) {
		o2nm_unlock_subsystem();
		return -EINVAL;
	}

	o2nm_unlock_subsystem();

	struct o2nm_cluster *cluster;
	o2nm_lock_subsystem();
	cluster = to_o2nm_cluster_from_node(node);
	if (!cluster) {
		o2nm_unlock_subsystem();
		return -EINVAL;
	}

	o2nm_unlock_subsystem();

	struct o2nm_cluster *cluster;
	o2nm_lock_subsystem();
	cluster = to_o2nm_cluster_from_node(node);
	if (!cluster) {
		ret = -EINVAL;
		goto out;
	}

	    cluster->cl_local_node != node->nd_num) {
		ret = -EBUSY;
		goto out;
	}
			goto out;
	ret = count;

out:
	o2nm_unlock_subsystem();
	return ret;
static inline void o2nm_lock_subsystem(void)
{
	mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex);
}

static inline void o2nm_unlock_subsystem(void)
{
	mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex);
}