diff options
| -rw-r--r-- | kernel/livepatch/core.c | 36 | ||||
| -rw-r--r-- | kernel/livepatch/core.h | 6 | ||||
| -rw-r--r-- | kernel/livepatch/transition.c | 2 | ||||
| -rw-r--r-- | lib/livepatch/test_klp_shadow_vars.c | 24 | ||||
| -rw-r--r-- | tools/testing/selftests/livepatch/functions.sh | 19 | 
5 files changed, 48 insertions, 39 deletions
| diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index fe1993399823..eb0ee10a1981 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -522,7 +522,7 @@ static int klp_add_nops(struct klp_patch *patch)  	struct klp_patch *old_patch;  	struct klp_object *old_obj; -	list_for_each_entry(old_patch, &klp_patches, list) { +	klp_for_each_patch(old_patch) {  		klp_for_each_object(old_patch, old_obj) {  			int err; @@ -1004,7 +1004,7 @@ int klp_enable_patch(struct klp_patch *patch)  	if (!klp_have_reliable_stack()) {  		pr_err("This architecture doesn't have support for the livepatch consistency model.\n"); -		return -ENOSYS; +		return -EOPNOTSUPP;  	} @@ -1057,7 +1057,7 @@ void klp_discard_replaced_patches(struct klp_patch *new_patch)  {  	struct klp_patch *old_patch, *tmp_patch; -	list_for_each_entry_safe(old_patch, tmp_patch, &klp_patches, list) { +	klp_for_each_patch_safe(old_patch, tmp_patch) {  		if (old_patch == new_patch)  			return; @@ -1101,7 +1101,7 @@ static void klp_cleanup_module_patches_limited(struct module *mod,  	struct klp_patch *patch;  	struct klp_object *obj; -	list_for_each_entry(patch, &klp_patches, list) { +	klp_for_each_patch(patch) {  		if (patch == limit)  			break; @@ -1109,21 +1109,14 @@ static void klp_cleanup_module_patches_limited(struct module *mod,  			if (!klp_is_module(obj) || strcmp(obj->name, mod->name))  				continue; -			/* -			 * Only unpatch the module if the patch is enabled or -			 * is in transition. -			 */ -			if (patch->enabled || patch == klp_transition_patch) { - -				if (patch != klp_transition_patch) -					klp_pre_unpatch_callback(obj); +			if (patch != klp_transition_patch) +				klp_pre_unpatch_callback(obj); -				pr_notice("reverting patch '%s' on unloading module '%s'\n", -					  patch->mod->name, obj->mod->name); -				klp_unpatch_object(obj); +			pr_notice("reverting patch '%s' on unloading module '%s'\n", +				  patch->mod->name, obj->mod->name); +			klp_unpatch_object(obj); -				klp_post_unpatch_callback(obj); -			} +			klp_post_unpatch_callback(obj);  			klp_free_object_loaded(obj);  			break; @@ -1148,7 +1141,7 @@ int klp_module_coming(struct module *mod)  	 */  	mod->klp_alive = true; -	list_for_each_entry(patch, &klp_patches, list) { +	klp_for_each_patch(patch) {  		klp_for_each_object(patch, obj) {  			if (!klp_is_module(obj) || strcmp(obj->name, mod->name))  				continue; @@ -1162,13 +1155,6 @@ int klp_module_coming(struct module *mod)  				goto err;  			} -			/* -			 * Only patch the module if the patch is enabled or is -			 * in transition. -			 */ -			if (!patch->enabled && patch != klp_transition_patch) -				break; -  			pr_notice("applying patch '%s' to loading module '%s'\n",  				  patch->mod->name, obj->mod->name); diff --git a/kernel/livepatch/core.h b/kernel/livepatch/core.h index e6200f38701f..ec43a40b853f 100644 --- a/kernel/livepatch/core.h +++ b/kernel/livepatch/core.h @@ -7,6 +7,12 @@  extern struct mutex klp_mutex;  extern struct list_head klp_patches; +#define klp_for_each_patch_safe(patch, tmp_patch)		\ +	list_for_each_entry_safe(patch, tmp_patch, &klp_patches, list) + +#define klp_for_each_patch(patch)	\ +	list_for_each_entry(patch, &klp_patches, list) +  void klp_free_patch_start(struct klp_patch *patch);  void klp_discard_replaced_patches(struct klp_patch *new_patch);  void klp_discard_nops(struct klp_patch *new_patch); diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c index 183b2086ba03..9c89ae8b337a 100644 --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c @@ -652,6 +652,6 @@ void klp_force_transition(void)  	for_each_possible_cpu(cpu)  		klp_update_patch_state(idle_task(cpu)); -	list_for_each_entry(patch, &klp_patches, list) +	klp_for_each_patch(patch)  		patch->forced = true;  } diff --git a/lib/livepatch/test_klp_shadow_vars.c b/lib/livepatch/test_klp_shadow_vars.c index 02f892f941dc..fe5c413efe96 100644 --- a/lib/livepatch/test_klp_shadow_vars.c +++ b/lib/livepatch/test_klp_shadow_vars.c @@ -44,7 +44,7 @@ static int ptr_id(void *ptr)  	sp = kmalloc(sizeof(*sp), GFP_ATOMIC);  	if (!sp) -		return -1; +		return -ENOMEM;  	sp->ptr = ptr;  	sp->id = count++; @@ -154,22 +154,37 @@ static int test_klp_shadow_vars_init(void)  	 * Allocate a few shadow variables with different <obj> and <id>.  	 */  	sv1 = shadow_alloc(obj, id, size, gfp_flags, shadow_ctor, &var1); +	if (!sv1) +		return -ENOMEM; +  	sv2 = shadow_alloc(obj + 1, id, size, gfp_flags, shadow_ctor, &var2); +	if (!sv2) +		return -ENOMEM; +  	sv3 = shadow_alloc(obj, id + 1, size, gfp_flags, shadow_ctor, &var3); +	if (!sv3) +		return -ENOMEM;  	/*  	 * Verify we can find our new shadow variables and that they point  	 * to expected data.  	 */  	ret = shadow_get(obj, id); +	if (!ret) +		return -EINVAL;  	if (ret == sv1 && *sv1 == &var1)  		pr_info("  got expected PTR%d -> PTR%d result\n",  			ptr_id(sv1), ptr_id(*sv1)); +  	ret = shadow_get(obj + 1, id); +	if (!ret) +		return -EINVAL;  	if (ret == sv2 && *sv2 == &var2)  		pr_info("  got expected PTR%d -> PTR%d result\n",  			ptr_id(sv2), ptr_id(*sv2));  	ret = shadow_get(obj, id + 1); +	if (!ret) +		return -EINVAL;  	if (ret == sv3 && *sv3 == &var3)  		pr_info("  got expected PTR%d -> PTR%d result\n",  			ptr_id(sv3), ptr_id(*sv3)); @@ -179,7 +194,12 @@ static int test_klp_shadow_vars_init(void)  	 * The second invocation should return the same shadow var.  	 */  	sv4 = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); +	if (!sv4) +		return -ENOMEM; +  	ret = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); +	if (!ret) +		return -EINVAL;  	if (ret == sv4 && *sv4 == &var4)  		pr_info("  got expected PTR%d -> PTR%d result\n",  			ptr_id(sv4), ptr_id(*sv4)); @@ -207,6 +227,8 @@ static int test_klp_shadow_vars_init(void)  	 * We should still find an <id+1> variable.  	 */  	ret = shadow_get(obj, id + 1); +	if (!ret) +		return -EINVAL;  	if (ret == sv3 && *sv3 == &var3)  		pr_info("  got expected PTR%d -> PTR%d result\n",  			ptr_id(sv3), ptr_id(*sv3)); diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh index c7b9fb45d7c9..30195449c63c 100644 --- a/tools/testing/selftests/livepatch/functions.sh +++ b/tools/testing/selftests/livepatch/functions.sh @@ -55,11 +55,10 @@ function is_livepatch_mod() {  function __load_mod() {  	local mod="$1"; shift -	local args="$*" -	local msg="% modprobe $mod $args" +	local msg="% modprobe $mod $*"  	log "${msg%% }" -	ret=$(modprobe "$mod" "$args" 2>&1) +	ret=$(modprobe "$mod" "$@" 2>&1)  	if [[ "$ret" != "" ]]; then  		die "$ret"  	fi @@ -75,12 +74,11 @@ function __load_mod() {  #	params  - module parameters to pass to modprobe  function load_mod() {  	local mod="$1"; shift -	local args="$*"  	is_livepatch_mod "$mod" &&  		die "use load_lp() to load the livepatch module $mod" -	__load_mod "$mod" "$args" +	__load_mod "$mod" "$@"  }  # load_lp_nowait(modname, params) - load a kernel module with a livepatch @@ -89,12 +87,11 @@ function load_mod() {  #	params  - module parameters to pass to modprobe  function load_lp_nowait() {  	local mod="$1"; shift -	local args="$*"  	is_livepatch_mod "$mod" ||  		die "module $mod is not a livepatch" -	__load_mod "$mod" "$args" +	__load_mod "$mod" "$@"  	# Wait for livepatch in sysfs ...  	loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' || @@ -106,9 +103,8 @@ function load_lp_nowait() {  #	params  - module parameters to pass to modprobe  function load_lp() {  	local mod="$1"; shift -	local args="$*" -	load_lp_nowait "$mod" "$args" +	load_lp_nowait "$mod" "$@"  	# Wait until the transition finishes ...  	loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' || @@ -120,11 +116,10 @@ function load_lp() {  #	params  - module parameters to pass to modprobe  function load_failing_mod() {  	local mod="$1"; shift -	local args="$*" -	local msg="% modprobe $mod $args" +	local msg="% modprobe $mod $*"  	log "${msg%% }" -	ret=$(modprobe "$mod" "$args" 2>&1) +	ret=$(modprobe "$mod" "$@" 2>&1)  	if [[ "$ret" == "" ]]; then  		die "$mod unexpectedly loaded"  	fi | 
