Context |
Check |
Description |
bpf/vmtest-bpf-next-PR |
success
|
PR summary
|
bpf/vmtest-bpf-next-VM_Test-0 |
success
|
Logs for Lint
|
bpf/vmtest-bpf-next-VM_Test-1 |
success
|
Logs for ShellCheck
|
bpf/vmtest-bpf-next-VM_Test-2 |
success
|
Logs for Unittests
|
bpf/vmtest-bpf-next-VM_Test-3 |
success
|
Logs for Validate matrix.py
|
bpf/vmtest-bpf-next-VM_Test-5 |
success
|
Logs for aarch64-gcc / build-release
|
bpf/vmtest-bpf-next-VM_Test-4 |
success
|
Logs for aarch64-gcc / build / build for aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-6 |
success
|
Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-9 |
success
|
Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-10 |
success
|
Logs for aarch64-gcc / veristat
|
bpf/vmtest-bpf-next-VM_Test-11 |
success
|
Logs for s390x-gcc / build / build for s390x with gcc
|
bpf/vmtest-bpf-next-VM_Test-12 |
success
|
Logs for s390x-gcc / build-release
|
bpf/vmtest-bpf-next-VM_Test-15 |
success
|
Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
|
bpf/vmtest-bpf-next-VM_Test-17 |
success
|
Logs for set-matrix
|
bpf/vmtest-bpf-next-VM_Test-16 |
success
|
Logs for s390x-gcc / veristat
|
bpf/vmtest-bpf-next-VM_Test-18 |
success
|
Logs for x86_64-gcc / build / build for x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-19 |
success
|
Logs for x86_64-gcc / build-release
|
bpf/vmtest-bpf-next-VM_Test-20 |
success
|
Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-21 |
success
|
Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-22 |
success
|
Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-23 |
success
|
Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-24 |
success
|
Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-25 |
success
|
Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-26 |
success
|
Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-27 |
success
|
Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
|
bpf/vmtest-bpf-next-VM_Test-28 |
success
|
Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
|
bpf/vmtest-bpf-next-VM_Test-29 |
success
|
Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
|
bpf/vmtest-bpf-next-VM_Test-30 |
success
|
Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
|
bpf/vmtest-bpf-next-VM_Test-31 |
success
|
Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
|
bpf/vmtest-bpf-next-VM_Test-32 |
success
|
Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
|
bpf/vmtest-bpf-next-VM_Test-33 |
success
|
Logs for x86_64-llvm-17 / veristat
|
bpf/vmtest-bpf-next-VM_Test-34 |
success
|
Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
|
bpf/vmtest-bpf-next-VM_Test-35 |
success
|
Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
|
bpf/vmtest-bpf-next-VM_Test-36 |
success
|
Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
|
bpf/vmtest-bpf-next-VM_Test-37 |
success
|
Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
|
bpf/vmtest-bpf-next-VM_Test-38 |
success
|
Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
|
bpf/vmtest-bpf-next-VM_Test-39 |
success
|
Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
|
bpf/vmtest-bpf-next-VM_Test-40 |
success
|
Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
|
bpf/vmtest-bpf-next-VM_Test-41 |
success
|
Logs for x86_64-llvm-18 / veristat
|
bpf/vmtest-bpf-next-VM_Test-7 |
success
|
Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-8 |
success
|
Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
|
bpf/vmtest-bpf-next-VM_Test-13 |
success
|
Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
|
bpf/vmtest-bpf-next-VM_Test-14 |
success
|
Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
|
netdev/series_format |
success
|
Posting correctly formatted
|
netdev/tree_selection |
success
|
Clearly marked for bpf-next, async
|
netdev/ynl |
success
|
Generated files up to date;
no warnings/errors;
no diff in generated;
|
netdev/fixes_present |
success
|
Fixes tag not required for -next series
|
netdev/header_inline |
success
|
No static functions without inline keyword in header files
|
netdev/build_32bit |
fail
|
Errors and warnings before: 272 this patch: 274
|
netdev/build_tools |
success
|
Errors and warnings before: 0 this patch: 0
|
netdev/cc_maintainers |
warning
|
8 maintainers not CCed: sdf@fomichev.me eddyz87@gmail.com haoluo@google.com jolsa@kernel.org daniel@iogearbox.net yonghong.song@linux.dev kpsingh@kernel.org john.fastabend@gmail.com
|
netdev/build_clang |
fail
|
Errors and warnings before: 340 this patch: 343
|
netdev/verify_signedoff |
success
|
Signed-off-by tag matches author and committer
|
netdev/deprecated_api |
success
|
None detected
|
netdev/check_selftest |
success
|
No net selftest shell script
|
netdev/verify_fixes |
success
|
No Fixes tag
|
netdev/build_allmodconfig_warn |
fail
|
Errors and warnings before: 7032 this patch: 7034
|
netdev/checkpatch |
warning
|
WARNING: line length of 84 exceeds 80 columns
WARNING: line length of 86 exceeds 80 columns
WARNING: line length of 97 exceeds 80 columns
|
netdev/build_clang_rust |
success
|
No Rust files in patch. Skipping build
|
netdev/kdoc |
success
|
Errors and warnings before: 15 this patch: 15
|
netdev/source_inline |
success
|
Was 0 now: 0
|
@@ -477,6 +477,8 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size)
data_race(*ldst++ = *lsrc++);
}
+void bpf_obj_unpin_uptr(const struct btf_field *field, void *addr);
+
/* copy everything but bpf_spin_lock, bpf_timer, and kptrs. There could be one of each. */
static inline void bpf_obj_memcpy(struct btf_record *rec,
void *dst, void *src, u32 size,
@@ -503,6 +505,34 @@ static inline void bpf_obj_memcpy(struct btf_record *rec,
memcpy(dst + curr_off, src + curr_off, size - curr_off);
}
+static inline void bpf_obj_uptrcpy(struct btf_record *rec,
+ void *dst, void *src)
+{
+ int i;
+
+ if (IS_ERR_OR_NULL(rec))
+ return;
+
+ for (i = 0; i < rec->cnt; i++) {
+ u32 next_off = rec->fields[i].offset;
+ void *addr;
+
+ if (rec->fields[i].type == BPF_UPTR) {
+ /* Unpin old address.
+ *
+ * Alignments are guaranteed by btf_find_field_one().
+ */
+ addr = *(void **)(dst + next_off);
+ if (addr)
+ bpf_obj_unpin_uptr(&rec->fields[i], addr);
+
+ *(void **)(dst + next_off) = *(void **)(src + next_off);
+ }
+ }
+}
+
+void copy_map_uptr_locked(struct bpf_map *map, void *dst, void *src, bool lock_src);
+
static inline void copy_map_value(struct bpf_map *map, void *dst, void *src)
{
bpf_obj_memcpy(map->record, dst, src, map->value_size, false);
@@ -388,6 +388,26 @@ void copy_map_value_locked(struct bpf_map *map, void *dst, void *src,
preempt_enable();
}
+/* Copy map value and uptr from src to dst, with lock_src indicating
+ * whether src or dst is locked.
+ */
+void copy_map_uptr_locked(struct bpf_map *map, void *src, void *dst,
+ bool lock_src)
+{
+ struct bpf_spin_lock *lock;
+
+ if (lock_src)
+ lock = src + map->record->spin_lock_off;
+ else
+ lock = dst + map->record->spin_lock_off;
+ preempt_disable();
+ __bpf_spin_lock_irqsave(lock);
+ copy_map_value(map, dst, src);
+ bpf_obj_uptrcpy(map->record, dst, src);
+ __bpf_spin_unlock_irqrestore(lock);
+ preempt_enable();
+}
+
BPF_CALL_0(bpf_jiffies64)
{
return get_jiffies_64();
@@ -155,6 +155,138 @@ static void maybe_wait_bpf_programs(struct bpf_map *map)
synchronize_rcu();
}
+void bpf_obj_unpin_uptr(const struct btf_field *field, void *addr)
+{
+ struct page *pages[1];
+ u32 size, type_id;
+ int npages;
+ void *ptr;
+
+ type_id = field->kptr.btf_id;
+ btf_type_id_size(field->kptr.btf, &type_id, &size);
+ if (size == 0)
+ return;
+
+ ptr = (void *)((intptr_t)addr & PAGE_MASK);
+
+ npages = (((intptr_t)addr + size + ~PAGE_MASK) - (intptr_t)ptr) >> PAGE_SHIFT;
+ if (WARN_ON_ONCE(npages > 1))
+ return;
+
+ pages[0] = virt_to_page(ptr);
+ unpin_user_pages(pages, 1);
+}
+
+/* Unpin uptr fields in the record up to cnt */
+static void bpf_obj_unpin_uptrs_cnt(struct btf_record *rec, int cnt, void *src)
+{
+ u32 next_off;
+ void **kaddr_ptr;
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ if (rec->fields[i].type != BPF_UPTR)
+ continue;
+
+ next_off = rec->fields[i].offset;
+ kaddr_ptr = src + next_off;
+ if (*kaddr_ptr) {
+ bpf_obj_unpin_uptr(&rec->fields[i], *kaddr_ptr);
+ *kaddr_ptr = NULL;
+ }
+ }
+}
+
+/* Find all BPF_UPTR fields in the record, pin the user memory, map it
+ * to kernel space, and update the addresses in the source memory.
+ *
+ * The map value passing from userspace may contain user kptrs pointing to
+ * user memory. This function pins the user memory and maps it to kernel
+ * memory so that BPF programs can access it.
+ */
+static int bpf_obj_trans_pin_uptrs(struct btf_record *rec, void *src, u32 size)
+{
+ u32 type_id, tsz, npages, next_off;
+ void *uaddr, *kaddr, **uaddr_ptr;
+ const struct btf_type *t;
+ struct page *pages[1];
+ int i, err;
+
+ if (IS_ERR_OR_NULL(rec))
+ return 0;
+
+ if (!btf_record_has_field(rec, BPF_UPTR))
+ return 0;
+
+ for (i = 0; i < rec->cnt; i++) {
+ if (rec->fields[i].type != BPF_UPTR)
+ continue;
+
+ next_off = rec->fields[i].offset;
+ if (next_off + sizeof(void *) > size) {
+ err = -EFAULT;
+ goto rollback;
+ }
+ uaddr_ptr = src + next_off;
+ uaddr = *uaddr_ptr;
+ if (!uaddr)
+ continue;
+
+ /* Make sure the user memory takes up at most one page */
+ type_id = rec->fields[i].kptr.btf_id;
+ t = btf_type_id_size(rec->fields[i].kptr.btf, &type_id, &tsz);
+ if (!t) {
+ err = -EFAULT;
+ goto rollback;
+ }
+ if (tsz == 0) {
+ *uaddr_ptr = NULL;
+ continue;
+ }
+ npages = (((intptr_t)uaddr + tsz + ~PAGE_MASK) -
+ ((intptr_t)uaddr & PAGE_MASK)) >> PAGE_SHIFT;
+ if (npages > 1) {
+ /* Allow only one page */
+ err = -EFAULT;
+ goto rollback;
+ }
+
+ /* Pin the user memory */
+ err = pin_user_pages_fast((intptr_t)uaddr, 1, FOLL_LONGTERM | FOLL_WRITE, pages);
+ if (err < 0)
+ goto rollback;
+
+ /* Map to kernel space */
+ kaddr = page_address(pages[0]);
+ if (unlikely(!kaddr)) {
+ WARN_ON_ONCE(1);
+ unpin_user_pages(pages, 1);
+ err = -EFAULT;
+ goto rollback;
+ }
+ *uaddr_ptr = kaddr + ((intptr_t)uaddr & ~PAGE_MASK);
+ }
+
+ return 0;
+
+rollback:
+ /* Unpin the user memory of earlier fields */
+ bpf_obj_unpin_uptrs_cnt(rec, i, src);
+
+ return err;
+}
+
+static void bpf_obj_unpin_uptrs(struct btf_record *rec, void *src)
+{
+ if (IS_ERR_OR_NULL(rec))
+ return;
+
+ if (!btf_record_has_field(rec, BPF_UPTR))
+ return;
+
+ bpf_obj_unpin_uptrs_cnt(rec, rec->cnt, src);
+}
+
static int bpf_map_update_value(struct bpf_map *map, struct file *map_file,
void *key, void *value, __u64 flags)
{
The helper functions manage uptrs in BPF map values from userspace. These uptrs point to user memory, so we must pin and convert them into kernel address space for BPF programs to access them in the kernel. These helper functions will be utilized by the upcoming patches. To access uptrs in BPF programs, they are pinned using pin_user_pages_fast(), but the conversion to kernel addresses is actually done by page_address(). The uptrs can be unpinned using unpin_user_pages(). Currently, the memory block pointed to by a uptr must reside in a single memory page, as crossing multiple pages is not supported. Cc: linux-mm@kvack.org Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com> --- include/linux/bpf.h | 30 ++++++++++ kernel/bpf/helpers.c | 20 +++++++ kernel/bpf/syscall.c | 132 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+)