요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
======================
(Un)patching Callbacks
======================
Livepatch (un)patch-callbacks provide a mechanism for livepatch modules
to execute callback functions when a kernel object is (un)patched. They
can be considered a **power feature** that **extends livepatching abilities**
to include:
- Safe updates to global data
- "Patches" to init and probe functions
- Patching otherwise unpatchable code (i.e. assembly)
In most cases, (un)patch callbacks will need to be used in conjunction
with memory barriers and kernel synchronization primitives, like
mutexes/spinlocks, or even stop_machine(), to avoid concurrency issues.
1. Motivation
=============
Callbacks differ from existing kernel facilities:
- Module init/exit code doesn't run when disabling and re-enabling a
patch.
- A module notifier can't stop a to-be-patched module from loading.
Callbacks are part of the klp_object structure and their implementation
is specific to that klp_object. Other livepatch objects may or may not
be patched, irrespective of the target klp_object's current state.
2. Callback types
=================
Callbacks can be registered for the following livepatch actions:
* Pre-patch
- before a klp_object is patched
* Post-patch
- after a klp_object has been patched and is active
across all tasks
* Pre-unpatch
- before a klp_object is unpatched (ie, patched code is
active), used to clean up post-patch callback
resources
* Post-unpatch
- after a klp_object has been patched, all code has
been restored and no tasks are running patched code,
used to cleanup pre-patch callback resources
3. How it works
===============
Each callback is optional, omitting one does not preclude specifying any
other. However, the livepatching core executes the handlers in
symmetry: pre-patch callbacks have a post-unpatch counterpart and
post-patch callbacks have a pre-unpatch counterpart. An unpatch
callback will only be executed if its corresponding patch callback was
executed. Typical use cases pair a patch handler that acquires and
configures resources with an unpatch handler tears down and releases
those same resources.
A callback is only executed if its host klp_object is loaded. For
in-kernel vmlinux targets, this means that callbacks will always execute
when a livepatch is enabled/disabled. For patch target kernel modules,
callbacks will only execute if the target module is loaded. When a
module target is (un)loaded, its callbacks will execute only if the
livepatch module is enabled.
The pre-patch callback, if specified, is expected to return a status
code (0 for success, -ERRNO on error). An error status code indicates
to the livepatching core that patching of the current klp_object is not
safe and to stop the current patching request. (When no pre-patch
callback is provided, the transition is assumed to be safe.) If a
pre-patch callback returns failure, the kernel's module loader will:
- Refuse to load a livepatch, if the livepatch is loaded after
targeted code.
or:
- Refuse to load a module, if the livepatch was already successfully
loaded.
No post-patch, pre-unpatch, or post-unpatch callbacks will be executed
for a given klp_object if the object failed to patch, due to a failed
pre_patch callback or for any other reason.
If a patch transition is reversed, no pre-unpatch handlers will be run
(this follows the previously mentioned symmetry -- pre-unpatch callbacks
will only occur if their corresponding post-patch callback executed).
If the object did successfully patch, but the patch transition never
started for some reason (e.g., if another object failed to patch),
only the post-unpatch callback will be called.
4. Use cases
============
Sample livepatch modules demonstrating the callback API can be found in
samples/livepatch/ directory. These samples were modified for use in
kselftests and can be found in the lib/livepatch directory.
Global data update
------------------
A pre-patch callback can be useful to update a global variable. For
example, commit 75ff39ccc1bd ("tcp: make challenge acks less predictable")
changes a global sysctl, as well as patches the tcp_send_challenge_ack()
function.
In this case, if we're being super paranoid, it might make sense to
patch the data *after* patching is complete with a post-patch callback,
so that tcp_send_challenge_ack() could first be changed to read
sysctl_tcp_challenge_ack_limit with READ_ONCE.
__init and probe function patches support
-----------------------------------------
Although __init and probe functions are not directly livepatch-able, it
may be possible to implement similar updates via pre/post-patch
callbacks.
The commit 48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST") change the way that
virtnet_probe() initialized its driver's net_device features. A
pre/post-patch callback could iterate over all such devices, making a
similar change to their hw_features value. (Client functions of the
value may need to be updated accordingly.)
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Patch·unpatch callback의 역할
1-26Livepatch patch·unpatch callback은 kernel object가 patch되거나 unpatch될 때 livepatch module이 callback function을 실행하게 합니다. Global data의 안전한 update, init·probe function에 해당하는 변경, assembly처럼 직접 patch하기 어려운 code의 보완까지 가능하게 하는 강력한 기능입니다.
대부분의 callback은 concurrency 문제를 피하려고 memory barrier와 mutex·spinlock 같은 kernel synchronization primitive, 경우에 따라 `stop_machine()`과 함께 사용해야 합니다.
Module init·exit code는 patch를 disable했다가 다시 enable할 때 실행되지 않고, module notifier는 patch 대상 module의 load를 중지시킬 수 없습니다. Callback은 이 기존 facility와 다른 lifecycle 지점을 제공합니다.
Callback은 `klp_object` 구조체에 속하며 구현도 해당 object에 한정됩니다. 다른 livepatch object의 patch 여부는 target `klp_object`의 현재 상태와 독립적일 수 있습니다.
일반 function redirect 밖의 상태 변경을 담당합니다.
======================
(Un)patching Callbacks
======================
Livepatch (un)patch-callbacks provide a mechanism for livepatch modules
to execute callback functions when a kernel object is (un)patched. They
can be considered a **power feature** that **extends livepatching abilities**
to include:
- Safe updates to global data
- "Patches" to init and probe functions
- Patching otherwise unpatchable code (i.e. assembly)
In most cases, (un)patch callbacks will need to be used in conjunction
with memory barriers and kernel synchronization primitives, like
mutexes/spinlocks, or even stop_machine(), to avoid concurrency issues.
1. Motivation
=============
Callbacks differ from existing kernel facilities:
- Module init/exit code doesn't run when disabling and re-enabling a
patch.
네 callback type과 대칭성
27-55등록 가능한 callback은 pre-patch, post-patch, pre-unpatch, post-unpatch 네 종류입니다. Pre-patch는 object를 patch하기 전, post-patch는 patch code가 모든 task에서 active가 된 뒤 실행됩니다.
Pre-unpatch는 patched code가 아직 active인 상태에서 unpatch 직전에 실행되어 post-patch resource를 정리합니다. Post-unpatch는 원래 code가 모두 복원되고 patched code를 실행하는 task가 없어진 뒤 실행되어 pre-patch resource를 정리합니다.
각 callback은 선택 사항이며 하나를 생략해도 다른 callback 등록을 막지 않습니다. 다만 core는 pre-patch와 post-unpatch, post-patch와 pre-unpatch를 대칭 pair로 실행합니다. 대응 patch callback이 실제 실행된 경우에만 unpatch callback도 실행됩니다.
일반적인 사용은 patch handler가 resource를 acquire·configure하고 대응 unpatch handler가 같은 resource를 teardown·release하는 것입니다.
Resource 취득과 해제의 대응 관계입니다.
- A module notifier can't stop a to-be-patched module from loading.
Callbacks are part of the klp_object structure and their implementation
is specific to that klp_object. Other livepatch objects may or may not
be patched, irrespective of the target klp_object's current state.
2. Callback types
=================
Callbacks can be registered for the following livepatch actions:
* Pre-patch
- before a klp_object is patched
* Post-patch
- after a klp_object has been patched and is active
across all tasks
* Pre-unpatch
- before a klp_object is unpatched (ie, patched code is
active), used to clean up post-patch callback
resources
* Post-unpatch
- after a klp_object has been patched, all code has
been restored and no tasks are running patched code,
used to cleanup pre-patch callback resources
실행 조건과 실패 처리
56-99Callback은 host `klp_object`가 load된 경우에만 실행됩니다. Kernel 내부 `vmlinux` target은 livepatch enable·disable 때 항상 실행되지만 module target은 target module이 load된 경우에만 실행됩니다. Target module이 load·unload될 때는 livepatch module이 enable 상태여야 callback이 실행됩니다.
Pre-patch callback은 성공 시 0, 실패 시 `-ERRNO` status를 반환해야 합니다. 실패는 현재 object의 patch가 안전하지 않음을 core에 알리고 patch 요청을 중단합니다. Pre-patch callback이 없으면 transition은 안전하다고 가정합니다.
Target code가 먼저 load된 뒤 livepatch가 load되는 경우 pre-patch 실패는 livepatch load를 거부합니다. Livepatch가 이미 성공적으로 load된 상태에서 target module을 load하려는 경우에는 target module load를 거부합니다.
Pre-patch 실패나 다른 이유로 object patch가 실패하면 그 object의 post-patch, pre-unpatch, post-unpatch callback은 실행되지 않습니다.
Patch transition이 역전되면 pre-unpatch는 실행되지 않습니다. 이는 대응 post-patch가 실행된 경우에만 pre-unpatch를 실행한다는 대칭 규칙을 따릅니다.
Object 자체는 성공적으로 patch됐지만 다른 object 실패 등으로 transition이 시작되지 않았다면 post-unpatch callback만 호출됩니다.
Target 종류와 module 상태에 따른 실행 여부입니다.
실패 시 어떤 module load가 거부되는지 구분합니다.
3. How it works
===============
Each callback is optional, omitting one does not preclude specifying any
other. However, the livepatching core executes the handlers in
symmetry: pre-patch callbacks have a post-unpatch counterpart and
post-patch callbacks have a pre-unpatch counterpart. An unpatch
callback will only be executed if its corresponding patch callback was
executed. Typical use cases pair a patch handler that acquires and
configures resources with an unpatch handler tears down and releases
those same resources.
A callback is only executed if its host klp_object is loaded. For
in-kernel vmlinux targets, this means that callbacks will always execute
when a livepatch is enabled/disabled. For patch target kernel modules,
callbacks will only execute if the target module is loaded. When a
module target is (un)loaded, its callbacks will execute only if the
livepatch module is enabled.
The pre-patch callback, if specified, is expected to return a status
code (0 for success, -ERRNO on error). An error status code indicates
to the livepatching core that patching of the current klp_object is not
safe and to stop the current patching request. (When no pre-patch
callback is provided, the transition is assumed to be safe.) If a
pre-patch callback returns failure, the kernel's module loader will:
- Refuse to load a livepatch, if the livepatch is loaded after
targeted code.
or:
- Refuse to load a module, if the livepatch was already successfully
loaded.
No post-patch, pre-unpatch, or post-unpatch callbacks will be executed
for a given klp_object if the object failed to patch, due to a failed
pre_patch callback or for any other reason.
If a patch transition is reversed, no pre-unpatch handlers will be run
(this follows the previously mentioned symmetry -- pre-unpatch callbacks
will only occur if their corresponding post-patch callback executed).
If the object did successfully patch, but the patch transition never
started for some reason (e.g., if another object failed to patch),
Callback 활용 사례
100-133Callback API를 보여주는 sample livepatch module은 `samples/livepatch/`에 있고, kselftest용으로 수정된 version은 `lib/livepatch`에 있습니다.
Pre-patch callback은 global variable update에 유용합니다. Commit `75ff39ccc1bd`는 global sysctl과 `tcp_send_challenge_ack()`를 함께 바꿉니다. 매우 보수적인 순서를 원하면 function patch가 완료된 뒤 post-patch callback에서 data를 바꾸고, 새 function이 `READ_ONCE`로 `sysctl_tcp_challenge_ack_limit`를 읽도록 먼저 전환할 수 있습니다.
`__init`과 probe function은 직접 livepatch할 수 없지만 pre·post-patch callback으로 비슷한 update를 구현할 수 있습니다.
Commit `48900cb6af42`는 `virtnet_probe()`가 driver의 `net_device` feature를 초기화하는 방식을 바꿨습니다. Callback은 이미 존재하는 모든 device를 순회하면서 `hw_features`에 같은 변경을 적용할 수 있고, 그 값을 사용하는 client function도 함께 update해야 할 수 있습니다.
직접 function 교체만으로 부족한 상태 변경입니다.
only the post-unpatch callback will be called.
4. Use cases
============
Sample livepatch modules demonstrating the callback API can be found in
samples/livepatch/ directory. These samples were modified for use in
kselftests and can be found in the lib/livepatch directory.
Global data update
------------------
A pre-patch callback can be useful to update a global variable. For
example, commit 75ff39ccc1bd ("tcp: make challenge acks less predictable")
changes a global sysctl, as well as patches the tcp_send_challenge_ack()
function.
In this case, if we're being super paranoid, it might make sense to
patch the data *after* patching is complete with a post-patch callback,
so that tcp_send_challenge_ack() could first be changed to read
sysctl_tcp_challenge_ack_limit with READ_ONCE.
__init and probe function patches support
-----------------------------------------
Although __init and probe functions are not directly livepatch-able, it
may be possible to implement similar updates via pre/post-patch
callbacks.
The commit 48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST") change the way that
virtnet_probe() initialized its driver's net_device features. A
pre/post-patch callback could iterate over all such devices, making a
similar change to their hw_features value. (Client functions of the
value may need to be updated accordingly.)
요약·해설
callbacks.rst:1-133Callback은 function redirect만으로 바꿀 수 없는 global state와 이미 실행된 initialization 효과를 안전하게 전환합니다.
대응 patch callback이 실행된 경우에만 unpatch callback이 실행된다는 대칭 규칙이 resource 수명을 결정합니다.