Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f4261d4 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bpfilter-fixes'



Taehee Yoo says:

====================
net: bpfilter: fix two bugs in bpfilter

This patches fix two bugs in the bpfilter_umh which are related in
iptables command.

The first patch adds an exit code for UMH process.
This provides an opportunity to cleanup members of the umh_info
to modules which use the UMH.
In order to identify UMH processes, a new flag PF_UMH is added.

The second patch makes the bpfilter_umh use UMH cleanup callback.

The third patch adds re-start routine for the bpfilter_umh.
The bpfilter_umh does not re-start after error occurred.
because there is no re-start routine in the module.

The fourth patch ensures that the bpfilter.ko module will not removed while
it's being used.
The bpfilter.ko is not protected by locks or module reference counter.
Therefore that can be removed while module is being used.
In order to protect that, mutex is used.

The first and second patch are preparation patches for the third and
fourth patch.

TEST #1
   while :
   do
	modprobe bpfilter
	kill -9 <pid of the bpfilter_umh>
	iptables -vnL
   done

TEST #2
   while :
   do
	iptables -I FORWARD -m string --string ap --algo kmp &
	iptables -F &
	modprobe -rv bpfilter &
   done

TEST #3
   while :
   do
	modprobe bpfilter &
	modprobe -rv bpfilter &
   done

The TEST1 makes a failure of iptables command.
This is fixed by the third patch.

The TEST2 makes a panic because of a race condition in the bpfilter_umh
module.
This is fixed by the fourth patch.

The TEST3 makes a double-create UMH process.
This is fixed by the third and fourth patch.

v4 :
 - declare the exit_umh() as static inline
 - check stop flag in the load_umh() to avoid a double-create UMH
v3 :
 - Avoid unnecessary list lookup for non-UMH processes
 - Add a new PF_UMH flag
v2 : add the first and second patch
v1 : Initial patch
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2ff33d66 71a85084
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -3,13 +3,22 @@
#define _LINUX_BPFILTER_H

#include <uapi/linux/bpfilter.h>
#include <linux/umh.h>

struct sock;
int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval,
			    unsigned int optlen);
int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
			    int __user *optlen);
extern int (*bpfilter_process_sockopt)(struct sock *sk, int optname,
struct bpfilter_umh_ops {
	struct umh_info info;
	/* since ip_getsockopt() can run in parallel, serialize access to umh */
	struct mutex lock;
	int (*sockopt)(struct sock *sk, int optname,
		       char __user *optval,
		       unsigned int optlen, bool is_set);
	int (*start)(void);
	bool stop;
};
extern struct bpfilter_umh_ops bpfilter_ops;
#endif
+9 −0
Original line number Diff line number Diff line
@@ -1406,6 +1406,7 @@ extern struct pid *cad_pid;
#define PF_RANDOMIZE		0x00400000	/* Randomize virtual address space */
#define PF_SWAPWRITE		0x00800000	/* Allowed to write to swap */
#define PF_MEMSTALL		0x01000000	/* Stalled due to lack of memory */
#define PF_UMH			0x02000000	/* I'm an Usermodehelper process */
#define PF_NO_SETAFFINITY	0x04000000	/* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY		0x08000000      /* Early kill for mce process policy */
#define PF_MUTEX_TESTER		0x20000000	/* Thread belongs to the rt mutex tester */
@@ -1904,6 +1905,14 @@ static inline void rseq_execve(struct task_struct *t)

#endif

void __exit_umh(struct task_struct *tsk);

static inline void exit_umh(struct task_struct *tsk)
{
	if (unlikely(tsk->flags & PF_UMH))
		__exit_umh(tsk);
}

#ifdef CONFIG_DEBUG_RSEQ

void rseq_syscall(struct pt_regs *regs);
+2 −0
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@ struct umh_info {
	const char *cmdline;
	struct file *pipe_to_umh;
	struct file *pipe_from_umh;
	struct list_head list;
	void (*cleanup)(struct umh_info *info);
	pid_t pid;
};
int fork_usermode_blob(void *data, size_t len, struct umh_info *info);
+1 −0
Original line number Diff line number Diff line
@@ -866,6 +866,7 @@ void __noreturn do_exit(long code)
	exit_task_namespaces(tsk);
	exit_task_work(tsk);
	exit_thread(tsk);
	exit_umh(tsk);

	/*
	 * Flush inherited counters to the parent - before the parent
+31 −2
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
static DEFINE_SPINLOCK(umh_sysctl_lock);
static DECLARE_RWSEM(umhelper_sem);
static LIST_HEAD(umh_list);
static DEFINE_MUTEX(umh_list_lock);

static void call_usermodehelper_freeinfo(struct subprocess_info *info)
{
@@ -100,10 +102,12 @@ static int call_usermodehelper_exec_async(void *data)
	commit_creds(new);

	sub_info->pid = task_pid_nr(current);
	if (sub_info->file)
	if (sub_info->file) {
		retval = do_execve_file(sub_info->file,
					sub_info->argv, sub_info->envp);
	else
		if (!retval)
			current->flags |= PF_UMH;
	} else
		retval = do_execve(getname_kernel(sub_info->path),
				   (const char __user *const __user *)sub_info->argv,
				   (const char __user *const __user *)sub_info->envp);
@@ -517,6 +521,11 @@ int fork_usermode_blob(void *data, size_t len, struct umh_info *info)
		goto out;

	err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC);
	if (!err) {
		mutex_lock(&umh_list_lock);
		list_add(&info->list, &umh_list);
		mutex_unlock(&umh_list_lock);
	}
out:
	fput(file);
	return err;
@@ -679,6 +688,26 @@ static int proc_cap_handler(struct ctl_table *table, int write,
	return 0;
}

void __exit_umh(struct task_struct *tsk)
{
	struct umh_info *info;
	pid_t pid = tsk->pid;

	mutex_lock(&umh_list_lock);
	list_for_each_entry(info, &umh_list, list) {
		if (info->pid == pid) {
			list_del(&info->list);
			mutex_unlock(&umh_list_lock);
			goto out;
		}
	}
	mutex_unlock(&umh_list_lock);
	return;
out:
	if (info->cleanup)
		info->cleanup(info);
}

struct ctl_table usermodehelper_table[] = {
	{
		.procname	= "bset",
Loading