Skip to content

Commit

Permalink
compat: Restrict __ro_after_init usage
Browse files Browse the repository at this point in the history
The attribute __ro_after_init was introduced in Linux kernel 4.5.  If
a data structure is given this attribute then after the driver module
loads the memory page where the data resides will be marked read only.

The compat code in cache.h always defines __ro_after_init if it is not
already defined so that it can be used as an attribute for the datapath
genl_family structure definitions.  If __ro_after_init is defined then
it is used "as-is" where it will apply the read only attribute after
driver initialization.

This is incorrect usage for the Generic Netlink genl_family structure
definitions prior to Linux kernel 4.10.  The genl_family structure
in those kernels includes a list header member that will be written
to when the generic netlink family is unregistered.  This will cause
a subsequent page fault and kernel panic because at this time the
genl_family structure data has been marked read only in the page
descriptor.

A new compat macro is introduced in acinclude.m4 to detect when the
genl_family structure has the family_list list header as a member.
In this case HAVE_GENL_FAMILY_LIST is defined and if __ro_after_init
is also defined then it is undefined and redefined as empty.  This
will prevent the genl_family data structure from being marked read
only in kernels 4.5 through 4.9 and thus prevent the page fault when
the generic netlink families in datapath.c are unregistered.

[Committer notes]
* Rolled a short explanation comment into the code.

Fixes: ba63fe2 ("datapath: Allow compile against current net-next.")
CC: Jarno Rajahalme <[email protected]>
Signed-off-by: Greg Rose <[email protected]>
Signed-off-by: Joe Stringer <[email protected]>
  • Loading branch information
gvrose8192 authored and joestringer committed Jun 19, 2017
1 parent 58bfaba commit bef862b
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 1 deletion.
2 changes: 2 additions & 0 deletions acinclude.m4
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
OVS_FIND_PARAM_IFELSE([$KSRC/include/net/netfilter/ipv6/nf_defrag_ipv6.h],
[nf_defrag_ipv6_enable], [net],
[OVS_DEFINE([HAVE_DEFRAG_ENABLE_TAKES_NET])])
OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [family_list],
[OVS_DEFINE([HAVE_GENL_FAMILY_LIST])])
if cmp -s datapath/linux/kcompat.h.new \
datapath/linux/kcompat.h >/dev/null 2>&1; then
Expand Down
15 changes: 14 additions & 1 deletion datapath/linux/compat/include/linux/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,21 @@

#include_next <linux/cache.h>

/* Upstream commit c74ba8b3480d ("arch: Introduce post-init read-only memory")
* introduced the __ro_after_init attribute, however it wasn't applied to
* generic netlink sockets until commit 34158151d2aa ("netfilter: cttimeout:
* use nf_ct_iterate_cleanup_net to unlink timeout objs"). Using it on
* genetlink before the latter commit leads to crash on module unload.
* For kernels < 4.10, define it as empty. */
#ifdef HAVE_GENL_FAMILY_LIST
#ifdef __ro_after_init
#undef __ro_after_init
#endif /* #ifdef __ro_after_init */
#define __ro_after_init
#else
#ifndef __ro_after_init
#define __ro_after_init
#endif
#endif /* #ifndef __ro_after_init */
#endif /* #ifdef HAVE_GENL_FAMILY_LIST */

#endif

0 comments on commit bef862b

Please sign in to comment.