Skip to content

Commit 1f2f485

Browse files
committed
kpatch-build: Enable cross compiling with env TARGET_ARCH
llvm/clang supports cross compiling of the kernel. To build livepatch in the same cross compile environment, enable specifying TARGET_ARCH for kpatch-build. For example, in a x86_64 host, we can build livepatch for aarch64 kernel with: TARGET=aarch64 kpatch-build ... Signed-off-by: Song Liu <song@kernel.org>
1 parent a04e6e9 commit 1f2f485

File tree

2 files changed

+68
-24
lines changed

2 files changed

+68
-24
lines changed

doc/patch-author-guide.md

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Table of contents
2929
- [Exported symbol versioning](#exported-symbol-versioning)
3030
- [System calls](#system-calls)
3131
- [Symbol Namespaces](#symbol-namespaces)
32+
- [Cross Compile](#cross-compile)
33+
3234

3335
Patch analysis
3436
--------------
@@ -259,7 +261,7 @@ index 9bff3b28c357..18374fd35bd9 100644
259261
@@ -1751,6 +1751,8 @@ struct task_struct *fork_idle(int cpu)
260262
return task;
261263
}
262-
264+
263265
+#include <linux/livepatch.h>
264266
+#define KPATCH_SHADOW_NEWPID 0
265267
/*
@@ -277,7 +279,7 @@ index 9bff3b28c357..18374fd35bd9 100644
277279
+ NULL, NULL);
278280
+ if (newpid)
279281
+ *newpid = ctr++;
280-
282+
281283
trace_sched_process_fork(current, p);
282284
```
283285

@@ -294,7 +296,7 @@ index 39684c79e8e2..fe0259d057a3 100644
294296
@@ -394,13 +394,19 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
295297
seq_putc(m, '\n');
296298
}
297-
299+
298300
+#include <linux/livepatch.h>
299301
+#define KPATCH_SHADOW_NEWPID 0
300302
static inline void task_context_switch_counts(struct seq_file *m,
@@ -309,7 +311,7 @@ index 39684c79e8e2..fe0259d057a3 100644
309311
+ if (newpid)
310312
+ seq_printf(m, "newpid:\t%d\n", *newpid);
311313
}
312-
314+
313315
static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
314316
```
315317

@@ -324,7 +326,7 @@ index 148a7842928d..44b6fe61e912 100644
324326
@@ -791,6 +791,8 @@ static void check_stack_usage(void)
325327
static inline void check_stack_usage(void) {}
326328
#endif
327-
329+
328330
+#include <linux/livepatch.h>
329331
+#define KPATCH_SHADOW_NEWPID 0
330332
void do_exit(long code)
@@ -333,7 +335,7 @@ index 148a7842928d..44b6fe61e912 100644
333335
@@ -888,6 +890,8 @@ void do_exit(long code)
334336
check_stack_usage();
335337
exit_thread();
336-
338+
337339
+ klp_shadow_free(tsk, KPATCH_SHADOW_NEWPID, NULL);
338340
+
339341
/*
@@ -395,7 +397,7 @@ semantic of the associated object:
395397
aio_put_req(iocb);
396398
+ if (klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2))
397399
+ atomic_dec(&ctx->reqs_active);
398-
400+
399401
/*
400402
* We have to order our ring_info tail store above and test
401403
```
@@ -404,9 +406,9 @@ Likewise, shadow variable non-existence can be tested to continue applying the
404406
*old* data semantic:
405407
```diff
406408
@@ -310,7 +312,8 @@ static void free_ioctx(struct kioctx *ctx)
407-
409+
408410
avail = (head <= ctx->tail ? ctx->tail : ctx->nr_events) - head;
409-
411+
410412
- atomic_sub(avail, &ctx->reqs_active);
411413
+ if (!klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2))
412414
+ atomic_sub(avail, &ctx->reqs_active);
@@ -415,14 +417,14 @@ Likewise, shadow variable non-existence can be tested to continue applying the
415417
}
416418
@@ -757,6 +762,8 @@ static long aio_read_events_ring(struct kioctx *ctx,
417419
pr_debug("%li h%u t%u\n", ret, head, ctx->tail);
418-
420+
419421
atomic_sub(ret, &ctx->reqs_active);
420422
+ if (!klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2))
421423
+ atomic_sub(ret, &ctx->reqs_active);
422424
out:
423425
mutex_unlock(&ctx->ring_lock);
424426
```
425-
427+
426428
The previous example can be extended to use shadow variable storage to handle
427429
locking semantic changes. Consider the [upstream fix](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d147bfa64293b2723c4fec50922168658e613ba)
428430
for CVE-2014-2706, which added a `ps_lock` to `struct sta_info` to protect
@@ -439,7 +441,7 @@ index decd30c1e290..758533dda4d8 100644
439441
@@ -287,6 +287,8 @@ static int sta_prepare_rate_control(struct ieee80211_local *local,
440442
return 0;
441443
}
442-
444+
443445
+#include <linux/livepatch.h>
444446
+#define KPATCH_SHADOW_PS_LOCK 2
445447
struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
@@ -450,12 +452,12 @@ index decd30c1e290..758533dda4d8 100644
450452
struct ieee80211_tx_latency_bin_ranges *tx_latency;
451453
int i;
452454
+ spinlock_t *ps_lock;
453-
455+
454456
sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
455457
if (!sta)
456458
@@ -330,6 +333,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
457459
rcu_read_unlock();
458-
460+
459461
spin_lock_init(&sta->lock);
460462
+ ps_lock = klp_shadow_alloc(sta, KPATCH_SHADOW_PS_LOCK,
461463
+ sizeof(*ps_lock), gfp, NULL, NULL);
@@ -477,7 +479,7 @@ index 97a02d3f7d87..0edb0ed8dc60 100644
477479
@@ -459,12 +459,15 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
478480
return 1;
479481
}
480-
482+
481483
+#include <linux/livepatch.h>
482484
+#define KPATCH_SHADOW_PS_LOCK 2
483485
static ieee80211_tx_result
@@ -487,7 +489,7 @@ index 97a02d3f7d87..0edb0ed8dc60 100644
487489
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
488490
struct ieee80211_local *local = tx->local;
489491
+ spinlock_t *ps_lock;
490-
492+
491493
if (unlikely(!sta))
492494
return TX_CONTINUE;
493495
@@ -478,6 +481,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
@@ -588,7 +590,7 @@ local. That way patching the function doesn't inadvertently reset the variable
588590
to zero; instead the variable keeps its old value.
589591

590592
To work around this limitation one needs to retain the reference to the static local.
591-
This might be as simple as adding the variable back in the patched function in a
593+
This might be as simple as adding the variable back in the patched function in a
592594
non-functional way and ensuring the compiler doesn't optimize it away.
593595

594596
Code removal
@@ -607,7 +609,7 @@ diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
607609
@@ -3,15 +3,15 @@
608610
#include <linux/proc_fs.h>
609611
#include <linux/seq_file.h>
610-
612+
611613
-static int cmdline_proc_show(struct seq_file *m, void *v)
612614
-{
613615
- seq_printf(m, "%s\n", saved_command_line);
@@ -618,13 +620,13 @@ diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
618620
+ seq_printf(m, "%s kpatch\n", saved_command_line);
619621
+ return 0;
620622
+}
621-
623+
622624
static int cmdline_proc_open(struct inode *inode, struct file *file)
623625
{
624626
- return single_open(file, cmdline_proc_show, NULL);
625627
+ return single_open(file, cmdline_proc_show_v2, NULL);
626628
}
627-
629+
628630
static const struct file_operations cmdline_proc_fops = {
629631
```
630632
will generate an equivalent kpatch module to this patch (dead
@@ -636,7 +638,7 @@ diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
636638
@@ -9,9 +9,15 @@ static int cmdline_proc_show(struct seq_
637639
return 0;
638640
}
639-
641+
640642
+static int cmdline_proc_show_v2(struct seq_file *m, void *v)
641643
+{
642644
+ seq_printf(m, "%s kpatch\n", saved_command_line);
@@ -648,7 +650,7 @@ diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
648650
- return single_open(file, cmdline_proc_show, NULL);
649651
+ return single_open(file, cmdline_proc_show_v2, NULL);
650652
}
651-
653+
652654
static const struct file_operations cmdline_proc_fops = {
653655
```
654656
In both versions, `kpatch-build` will determine that only
@@ -964,3 +966,25 @@ ERROR: modpost: module livepatch-test uses symbol dma_buf_export from namespace
964966
```
965967
To manually import the required namespace, add the MODULE_IMPORT_NS() macro to
966968
the patch source. For example: `MODULE_IMPORT_NS("DMA_BUF")`
969+
970+
Cross Compile
971+
-------------
972+
973+
It is recommended to build the livepatch in the same environment (compiler/library/etc.) as
974+
the target kernel. When the target kernel was cross compiled for a different architecture,
975+
it is recommended to cross compile the livepatch.
976+
977+
There are two options to cross compile a livepatch.
978+
979+
To specify a separate set of cross compilers,
980+
we can set the `CROSS_COMPILE` environment variable. For example, to use `aarch64-gcc` and `aarch64-ld`,
981+
we can run kpatch-build as
982+
```
983+
CROSSCOMPILE=aarch64- kpatch-build ...
984+
```
985+
986+
llvm/clang supports cross compile with the same binaries. To specify a cross compile target, we can
987+
use the TARGET_ARCH environment variable, for example:
988+
```
989+
TARGET_ARCH=aarch64 kpatch-build ...
990+
```

kpatch-build/kpatch-build

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ set -o pipefail
4040
BASE="$PWD"
4141
SCRIPTDIR="$(readlink -f "$(dirname "$(type -p "$0")")")"
4242
ARCH="$(uname -m)"
43+
TARGET_ARCH="${TARGET_ARCH:-$ARCH}"
4344
CPUS="$(getconf _NPROCESSORS_ONLN)"
4445
CACHEDIR="${CACHEDIR:-$HOME/.kpatch}"
4546
KERNEL_SRCDIR="$CACHEDIR/src"
@@ -390,7 +391,7 @@ find_special_section_data() {
390391
check[e]=true # exception_table_entry
391392

392393
# Arch-specific features
393-
case "$ARCH" in
394+
case "$TARGET_ARCH" in
394395
"x86_64")
395396
check[a]=true # alt_instr
396397
kernel_version_gte 5.10.0 && check[s]=true # static_call_site
@@ -722,6 +723,15 @@ print_supported_distro(){
722723
fi
723724
}
724725

726+
# Used in "make ARCH=xxx" when making the kernel.
727+
# Match "aarch64" to "arm64", while keep everything else the same.
728+
kernel_make_arch() {
729+
if [[ "$1" == "aarch64" ]]; then
730+
echo "arm64"
731+
else
732+
echo "$1"
733+
fi
734+
}
725735

726736
usage() {
727737
echo "usage: $(basename "$0") [options] <patch1 ... patchN>" >&2
@@ -1299,6 +1309,11 @@ else
12991309
MAKEVARS+=("LD=${KPATCH_CC_PREFIX}${LD}")
13001310
fi
13011311

1312+
if [[ "$ARCH" != "$TARGET_ARCH" ]]; then
1313+
KARCH=$(kernel_make_arch "$TARGET_ARCH")
1314+
MAKEVARS+=("ARCH=$KARCH")
1315+
fi
1316+
13021317

13031318
# $TARGETS used as list, no quotes.
13041319
# shellcheck disable=SC2086
@@ -1489,7 +1504,12 @@ fi
14891504
cd "$TEMPDIR/output" || die
14901505
# $KPATCH_LDFLAGS and result of find used as list, no quotes.
14911506
# shellcheck disable=SC2086,SC2046
1492-
"$LD" -r $KPATCH_LDFLAGS -o ../patch/tmp_output.o $(find . -name "*.o") 2>&1 | logger || die
1507+
if [[ "$ARCH" != "$TARGET_ARCH" ]]; then
1508+
# if cross compiling, use LLD to link
1509+
"$LLD" -r $KPATCH_LDFLAGS -o ../patch/tmp_output.o $(find . -name "*.o") 2>&1 | logger || die
1510+
else
1511+
"$LD" -r $KPATCH_LDFLAGS -o ../patch/tmp_output.o $(find . -name "*.o") 2>&1 | logger || die
1512+
fi
14931513

14941514
if [[ "$USE_KLP" -eq 1 ]]; then
14951515
cp -f "$TEMPDIR"/patch/tmp_output.o "$TEMPDIR"/patch/output.o || die

0 commit comments

Comments
 (0)