Skip to content

Commit 8869016

Browse files
mirabJiri Kosina
authored andcommitted
livepatch: add locking to force and signal functions
klp_send_signals() and klp_force_transition() do not acquire klp_mutex, because it seemed to be superfluous. A potential race in klp_send_signals() was harmless and there was nothing in klp_force_transition() which needed to be synchronized. That changed with the addition of klp_forced variable during the review process. There is a small window now, when klp_complete_transition() does not see klp_forced set to true while all tasks have been already transitioned to the target state. module_put() is called and the module can be removed. Acquire klp_mutex in sysfs callback to prevent it. Do the same for the signal sending just to be sure. There is no real downside to that. Fixes: c99a2be ("livepatch: force transition to finish") Fixes: 43347d5 ("livepatch: send a fake signal to all blocking tasks") Reported-by: Jason Baron <[email protected]> Signed-off-by: Miroslav Benes <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent c99a2be commit 8869016

File tree

1 file changed

+28
-24
lines changed

1 file changed

+28
-24
lines changed

kernel/livepatch/core.c

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -537,22 +537,24 @@ static ssize_t signal_store(struct kobject *kobj, struct kobj_attribute *attr,
537537
int ret;
538538
bool val;
539539

540-
patch = container_of(kobj, struct klp_patch, kobj);
541-
542-
/*
543-
* klp_mutex lock is not grabbed here intentionally. It is not really
544-
* needed. The race window is harmless and grabbing the lock would only
545-
* hold the action back.
546-
*/
547-
if (patch != klp_transition_patch)
548-
return -EINVAL;
549-
550540
ret = kstrtobool(buf, &val);
551541
if (ret)
552542
return ret;
553543

554-
if (val)
555-
klp_send_signals();
544+
if (!val)
545+
return count;
546+
547+
mutex_lock(&klp_mutex);
548+
549+
patch = container_of(kobj, struct klp_patch, kobj);
550+
if (patch != klp_transition_patch) {
551+
mutex_unlock(&klp_mutex);
552+
return -EINVAL;
553+
}
554+
555+
klp_send_signals();
556+
557+
mutex_unlock(&klp_mutex);
556558

557559
return count;
558560
}
@@ -564,22 +566,24 @@ static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
564566
int ret;
565567
bool val;
566568

567-
patch = container_of(kobj, struct klp_patch, kobj);
568-
569-
/*
570-
* klp_mutex lock is not grabbed here intentionally. It is not really
571-
* needed. The race window is harmless and grabbing the lock would only
572-
* hold the action back.
573-
*/
574-
if (patch != klp_transition_patch)
575-
return -EINVAL;
576-
577569
ret = kstrtobool(buf, &val);
578570
if (ret)
579571
return ret;
580572

581-
if (val)
582-
klp_force_transition();
573+
if (!val)
574+
return count;
575+
576+
mutex_lock(&klp_mutex);
577+
578+
patch = container_of(kobj, struct klp_patch, kobj);
579+
if (patch != klp_transition_patch) {
580+
mutex_unlock(&klp_mutex);
581+
return -EINVAL;
582+
}
583+
584+
klp_force_transition();
585+
586+
mutex_unlock(&klp_mutex);
583587

584588
return count;
585589
}

0 commit comments

Comments
 (0)