diff --git a/.github/workflows/diffdiff.py b/.github/workflows/diffdiff.py new file mode 100755 index 0000000000000..dc2c5ab0d1e9d --- /dev/null +++ b/.github/workflows/diffdiff.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# + +import argparse +import copy +import difflib +import io +import git +import os +import re +import subprocess +import sys +import tempfile + +verbose = False + + +def get_upstream_commit(upstream, c): + for l in c.message.splitlines(): + try: + sha = re.match('\s*commit\s+(?P\S+)', l).groups()[0].upper() + return upstream.commit(sha) + except: + True + +def get_diff(d): + dif = '' + df = False + for l in d.splitlines(): + if l[:10] == 'diff --git': + df = True + if not df: + continue + dif = dif + l + '\n' + return dif + + +def trim_unchanged_files(lines): + dl = [] + ld = 0 # Last line with a 'diff --git' we saw + hd = False # Have we seen a changed line since ld? + i = 0 + for i, l in enumerate(lines): + if l[:4] == '+++ ' or l[:4] == '--- ' : + continue + if l[0] == '+' or l[0] == '-': + hd = True + if l[:11] == ' diff --git': + if ld: # We are at a new diff now, last one started at 'ld' + if not hd: + dl.insert(0, (ld, i+1),) + ld = i + hd = False # Reset hasdiff to False as we start a new section + # and check the tail + if not hd: + dl.insert(0, (ld, i+1),) + # delete the unchanged file sections + for d in dl: + del lines[d[0]:d[1]] + return lines + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-v', action='store_true', help='Verbose') + parser.add_argument('--colour', action='store_true', help='Colorize the diff. Green for additions, red for deletions') + parser.add_argument('--commit', help='Commit in current tree to diffdiff. Default is the most recent commit.') + parser.add_argument('--upstream', help='A directory that contains the current upstream of linus kernel tree where we can find the commits we reference. Default is the current repo') + args = parser.parse_args() + + + if args.v: + verbose = True + + srcgit = git.Repo.init('.') + upstream = git.Repo.init(args.upstream) + c = srcgit.head.commit if not args.commit else srcgit.commit(args.commit) + uc = get_upstream_commit(upstream, c) + + dc = get_diff(srcgit.git.show(c)) + duc = get_diff(upstream.git.show(uc)) + + with open('c.diff', 'w') as f: + f.write(dc) + with open('u.diff', 'w') as f: + f.write(duc) + + res = subprocess.run(['diff', '-u', 'u.diff', 'c.diff'], + check=False, stdout=subprocess.PIPE) + lines = res.stdout.splitlines() + dd = [] + for l in lines: + l = str(l)[2:-1] + if l[:6] == '-index': + continue + if l[:6] == '+index': + continue + if l[:3] == '-@@': + continue + if l[:3] == '+@@': + dd.append(' ' + l[1:]) + continue + dd.append(l) + + # trim diffs for files that did not change + lines = trim_unchanged_files(dd) + + # colorize the diff + diffs = 0 + if args.colour: + dd = [] + for l in lines: + if l[0:4] != '+++ ' and l[0:4] != '--- ': + if l[0] == '+': + l = '\033[42m' + l + '\033[0m' + diffs = diffs + 1 + if l[0] == '-': + l = '\033[41m' + l + '\033[0m' + diffs = diffs + 1 + dd.append(l) + lines = dd + + + if diffs: + for l in lines: + print(l) + + sys.exit(diffs) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml new file mode 100644 index 0000000000000..de3dbc4d34b9b --- /dev/null +++ b/.github/workflows/github-actions-demo.yml @@ -0,0 +1,26 @@ +name: GitHub Actions Sanity Check +run-name: ${{ github.actor }} is running actions - this runs as a sanity check 🚀 +on: + push: + branches: + - '**' + - '!mainline' + +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v4 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "🖥️ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + df . + df / + pwd + - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/.github/workflows/process-git-request.rb b/.github/workflows/process-git-request.rb new file mode 100644 index 0000000000000..04a2ccd49b8bc --- /dev/null +++ b/.github/workflows/process-git-request.rb @@ -0,0 +1,140 @@ +require 'open3' + +requestors = { "gvrose8192" => "" } + +def file_prepend(file, str) + new_contents = "" + File.open(file, 'r') do |fd| + contents = fd.read + new_contents = str << contents + end + # Overwrite file but now with prepended string on it + File.open(file, 'w') do |fd| + fd.write(new_contents) + end +end + +def process_git_request(fname, target_branch, source_branch, prj_dir) + retcode = 200 #presume success +# puts "Opening file " + fname + file = File.new(fname, "w") + working_dir = prj_dir +# puts "Working Dir : " + working_dir + Dir.chdir working_dir +# puts "pwd : " + Dir.pwd + git_cmd = "git log --oneline --no-abbrev-commit origin/" + target_branch + ".." + "origin/" + source_branch +# puts git_cmd + out, err, status = Open3.capture3(git_cmd) + if status.exitstatus != 0 + puts "Command error output is " + err + file.write("Command error output is " + err) + file.close + retcode = 201 + return retcode + end + output_lines = out.split(' ') +# we just want the commit sha IDs + output_lines.each { |x| +# puts "This is output_lines " + x + upstream_diff = false + if !x[/\H/] + if x.length < 40 + next + end + git_cmd = "git show " + x + gitlog_out, gitlog_err, gitlog_status = Open3.capture3(git_cmd) + if gitlog_status.exitstatus != 0 + file.write("git show command error output is " + gitlog_err) + retcode = 201 + end + loglines = gitlog_out.lines.map(&:chomp) + lines_counted = 0 + local_diffdiff_sha = "" + upstream_diffdiff_sha = "" + loglines.each { |logline| + lines_counted = lines_counted + 1 + if lines_counted == 1 + local_commit_sha = logline.match("[0-9a-f]\{40\}") + local_diffdiff_sha = local_commit_sha.to_s +# puts "Local : " + local_diffdiff_sha + file.write("Merge Request sha: " + local_diffdiff_sha) + file.write("\n") + end + if lines_counted == 2 #email address + if !logline.downcase.include? "ciq.com" + # Bad Author + s = "error:\nBad " + logline + "\n" + puts s + file.write(s) + retcode = 201 + else + file.write("\t" + logline + "\n") + end + end + if lines_counted > 1 + if logline.downcase.include? "jira" + file.write("\t" + logline + "\n") + end + if logline.downcase.include? "upstream-diff" + upstream_diff = true + end + if logline.downcase.include? "commit" + commit_sha = logline.match("[0-9a-f]\{40\}") + upstream_diffdiff_sha = commit_sha.to_s +# puts "Upstream : " + upstream_diffdiff_sha + if (!upstream_diffdiff_sha.empty?) + file.write("\tUpstream sha: " + upstream_diffdiff_sha) + file.write("\n") + end + end + end + if lines_counted > 8 #Everything we need should be in the first 8 lines + break + end + } + if !local_diffdiff_sha.empty? && !upstream_diffdiff_sha.empty? + diff_cmd = Dir.pwd + "/.github/workflows/diffdiff.py --colour --commit " + local_diffdiff_sha + puts "diffdiff: " + diff_cmd + diff_out, diff_err, diff_status = Open3.capture3(diff_cmd) + if diff_status.exitstatus != 0 && !upstream_diff + puts "diffdiff out: " + diff_out + puts "diffdiff err: " + diff_err + retcode = 201 + file.write("error:\nCommit: " + local_diffdiff_sha + " differs with no upstream tag in commit message\n") + end + end + end + } + file.close + return retcode +end + +first_arg, *argv_in = ARGV +if argv_in.length < 5 + puts "Not enough arguments: fname, target_branch, source_branch, prj_dir, pull_request, requestor" + exit +end +fname = first_arg.to_s +fname = "tmp-" + fname +# puts "filename is " + fname +target_branch = argv_in[0].to_s +# puts "target branch is " + target_branch +source_branch = argv_in[1].to_s +# puts "source branch is " + source_branch +prj_dir = argv_in[2].to_s +# puts "project dir is " + prj_dir +pullreq = argv_in[3].to_s +# puts "pull request is " + pullreq +requestor = argv_in[4].to_s +retcode = process_git_request(fname, target_branch, source_branch, prj_dir) +if retcode != 200 + File.open(fname, 'r') do |fd| + contents = fd.read + puts contents + end + exit(1) +else + puts "Done" +end +exit(0) + diff --git a/.github/workflows/process-pull-request.yml b/.github/workflows/process-pull-request.yml new file mode 100644 index 0000000000000..5764537bed632 --- /dev/null +++ b/.github/workflows/process-pull-request.yml @@ -0,0 +1,54 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Pull Request Checker + +on: + pull_request: + branches: + - '**' + - '!mainline' + +permissions: + contents: read + +jobs: + test: + + runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: ['3.0'] + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, + # change this to (see https://github.com/ruby/setup-ruby#versioning): + uses: ruby/setup-ruby@v1 + # uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Set up Python + uses: actions/setup-python@v5 + - name: Run tests + run: | + /usr/bin/pip3 install gitPython + python -c "import sys; import git; print(sys.version)" + git fetch origin ${{ github.base_ref }} + git fetch origin ${{ github.head_ref }} + git remote add linux https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + git fetch --shallow-since="3 years ago" linux + echo "Will run process-git-request.rb with:" + echo "fname = ${{ github.run_id }}" + echo "target_branch = ${{ github.base_ref }}" + echo "source_branch = ${{ github.head_ref }}" + echo "prj_dir = ${{ github.workspace }}" + echo "pull_request = ${{ github.ref }}" + echo "requestor = ${{ github.actor }}" + cd ${{ github.workspace }} + /usr/bin/ruby .github/workflows/process-git-request.rb ${{ github.run_id }} ${{ github.base_ref }} \ + ${{ github.head_ref }} ${{ github.workspace }} ${{ github.ref }} ${{ github.actor }} diff --git a/.github/workflows/push-check_aarch64.yml b/.github/workflows/push-check_aarch64.yml new file mode 100644 index 0000000000000..de372fd5ce48b --- /dev/null +++ b/.github/workflows/push-check_aarch64.yml @@ -0,0 +1,33 @@ +name: CI +on: + push: + branches: + - '**' + - '!mainline' + +jobs: + kernel-build-job: + runs-on: + labels: kernel-build-arm64 + container: + image: rockylinux:9 + env: + ROCKY_ENV: rocky9 + ports: + - 80 + options: --cpus 8 + steps: + - name: Install tools and Libraries + run: | + dnf groupinstall 'Development Tools' -y + dnf install --enablerepo=crb bc dwarves kernel-devel openssl-devel elfutils-libelf-devel -y + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build the Kernel + run: | + git config --global --add safe.directory /__w/kernel-src-git/kernel-src-git + cp configs/kernel-5.14.0-aarch64.config .config + make olddefconfig + make -j8 diff --git a/.github/workflows/push-check_x86_64.yml b/.github/workflows/push-check_x86_64.yml new file mode 100644 index 0000000000000..28a9ed0ee219c --- /dev/null +++ b/.github/workflows/push-check_x86_64.yml @@ -0,0 +1,33 @@ +name: CI +on: + push: + branches: + - '**' + - '!mainline' + +jobs: + kernel-build-job: + runs-on: + labels: kernel-build + container: + image: rockylinux:9 + env: + ROCKY_ENV: rocky9 + ports: + - 80 + options: --cpus 8 + steps: + - name: Install tools and Libraries + run: | + dnf groupinstall 'Development Tools' -y + dnf install --enablerepo=crb bc dwarves kernel-devel openssl-devel elfutils-libelf-devel -y + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build the Kernel + run: | + git config --global --add safe.directory /__w/kernel-src-git/kernel-src-git + cp configs/kernel-5.14.0-x86_64.config .config + make olddefconfig + make -j8 diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index c536092bb35fc..3463833a938f1 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -346,6 +346,7 @@ static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status) { + queue->rcv_state = NVMET_TCP_RECV_ERR; if (status == -EPIPE || status == -ECONNRESET) kernel_sock_shutdown(queue->sock, SHUT_RDWR); else @@ -872,15 +873,11 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) iov.iov_len = sizeof(*icresp); ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); if (ret < 0) - goto free_crypto; + return ret; /* queue removal will cleanup */ queue->state = NVMET_TCP_Q_LIVE; nvmet_prepare_receive_pdu(queue); return 0; -free_crypto: - if (queue->hdr_digest || queue->data_digest) - nvmet_tcp_free_crypto(queue); - return ret; } static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index bb031e0e9006d..68347085e3259 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -695,6 +695,12 @@ static bool dynptr_type_refcounted(enum bpf_dynptr_type type) return type == BPF_DYNPTR_TYPE_RINGBUF; } +static void __mark_reg_not_init(const struct bpf_verifier_env *env, + struct bpf_reg_state *reg); + +static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, + struct bpf_func_state *state, int spi); + static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg, enum bpf_arg_type arg_type, int insn_idx) { @@ -762,6 +768,55 @@ static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_re return 0; } +static void __mark_reg_unknown(const struct bpf_verifier_env *env, + struct bpf_reg_state *reg); + +static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, + struct bpf_func_state *state, int spi) +{ + int i; + + /* We always ensure that STACK_DYNPTR is never set partially, + * hence just checking for slot_type[0] is enough. This is + * different for STACK_SPILL, where it may be only set for + * 1 byte, so code has to use is_spilled_reg. + */ + if (state->stack[spi].slot_type[0] != STACK_DYNPTR) + return 0; + + /* Reposition spi to first slot */ + if (!state->stack[spi].spilled_ptr.dynptr.first_slot) + spi = spi + 1; + + if (dynptr_type_refcounted(state->stack[spi].spilled_ptr.dynptr.type)) { + verbose(env, "cannot overwrite referenced dynptr\n"); + return -EINVAL; + } + + mark_stack_slot_scratched(env, spi); + mark_stack_slot_scratched(env, spi - 1); + + /* Writing partially to one dynptr stack slot destroys both. */ + for (i = 0; i < BPF_REG_SIZE; i++) { + state->stack[spi].slot_type[i] = STACK_INVALID; + state->stack[spi - 1].slot_type[i] = STACK_INVALID; + } + + /* TODO: Invalidate any slices associated with this dynptr */ + + /* Do not release reference state, we are destroying dynptr on stack, + * not using some helper to release it. Just reset register. + */ + __mark_reg_not_init(env, &state->stack[spi].spilled_ptr); + __mark_reg_not_init(env, &state->stack[spi - 1].spilled_ptr); + + /* Same reason as unmark_stack_slots_dynptr above */ + state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; + state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; + + return 0; +} + static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg) { struct bpf_func_state *state = func(env, reg); @@ -1300,9 +1355,6 @@ static const int caller_saved[CALLER_SAVED_REGS] = { BPF_REG_0, BPF_REG_1, BPF_REG_2, BPF_REG_3, BPF_REG_4, BPF_REG_5 }; -static void __mark_reg_not_init(const struct bpf_verifier_env *env, - struct bpf_reg_state *reg); - /* This helper doesn't clear reg->id */ static void ___mark_reg_known(struct bpf_reg_state *reg, u64 imm) { @@ -2645,6 +2697,21 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, } } else if (opcode == BPF_EXIT) { return -ENOTSUPP; + } else if (BPF_SRC(insn->code) == BPF_X) { + if (!(*reg_mask & (dreg | sreg))) + return 0; + /* dreg sreg + * Both dreg and sreg need precision before + * this insn. If only sreg was marked precise + * before it would be equally necessary to + * propagate it to dreg. + */ + *reg_mask |= (sreg | dreg); + /* else dreg K + * Only dreg still needs precision before + * this insn, so for the K-based conditional + * there is nothing new to be marked. + */ } } else if (class == BPF_LD) { if (!(*reg_mask & dreg)) @@ -3037,6 +3104,10 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, env->insn_aux_data[insn_idx].sanitize_stack_spill = true; } + err = destroy_if_dynptr_stack_slot(env, state, spi); + if (err) + return err; + mark_stack_slot_scratched(env, spi); if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && !register_is_null(reg) && env->bpf_capable) { @@ -3150,6 +3221,14 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env, if (err) return err; + for (i = min_off; i < max_off; i++) { + int spi; + + spi = get_spi(i); + err = destroy_if_dynptr_stack_slot(env, state, spi); + if (err) + return err; + } /* Variable offset writes destroy any spilled pointers in range. */ for (i = min_off; i < max_off; i++) { @@ -5111,6 +5190,31 @@ static int check_stack_range_initialized( } if (meta && meta->raw_mode) { + /* Ensure we won't be overwriting dynptrs when simulating byte + * by byte access in check_helper_call using meta.access_size. + * This would be a problem if we have a helper in the future + * which takes: + * + * helper(uninit_mem, len, dynptr) + * + * Now, uninint_mem may overlap with dynptr pointer. Hence, it + * may end up writing to dynptr itself when touching memory from + * arg 1. This can be relaxed on a case by case basis for known + * safe cases, but reject due to the possibilitiy of aliasing by + * default. + */ + for (i = min_off; i < max_off + access_size; i++) { + int stack_off = -i - 1; + + spi = get_spi(i); + /* raw_mode may write past allocated_stack */ + if (state->allocated_stack <= stack_off) + continue; + if (state->stack[spi].slot_type[stack_off % BPF_REG_SIZE] == STACK_DYNPTR) { + verbose(env, "potential write to dynptr at off=%d disallowed\n", i); + return -EACCES; + } + } meta->access_size = access_size; meta->regno = regno; return 0; diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 4b79df6ecf6c6..11e24f56bf805 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -1981,6 +1981,10 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set, goto cont; e = f->mt[r].e; + + if (!nft_set_elem_active(&e->ext, iter->genmask)) + goto cont; + if (nft_set_elem_expired(&e->ext)) goto cont; diff --git a/tools/testing/selftests/bpf/progs/pyperf180.c b/tools/testing/selftests/bpf/progs/pyperf180.c index c39f559d3100e..42c4a8b62e360 100644 --- a/tools/testing/selftests/bpf/progs/pyperf180.c +++ b/tools/testing/selftests/bpf/progs/pyperf180.c @@ -1,4 +1,26 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Facebook #define STACK_MAX_LEN 180 + +/* llvm upstream commit at clang18 + * https://github.com/llvm/llvm-project/commit/1a2e77cf9e11dbf56b5720c607313a566eebb16e + * changed inlining behavior and caused compilation failure as some branch + * target distance exceeded 16bit representation which is the maximum for + * cpu v1/v2/v3. Macro __BPF_CPU_VERSION__ is later implemented in clang18 + * to specify which cpu version is used for compilation. So a smaller + * unroll_count can be set if __BPF_CPU_VERSION__ is less than 4, which + * reduced some branch target distances and resolved the compilation failure. + * + * To capture the case where a developer/ci uses clang18 but the corresponding + * repo checkpoint does not have __BPF_CPU_VERSION__, a smaller unroll_count + * will be set as well to prevent potential compilation failures. + */ +#ifdef __BPF_CPU_VERSION__ +#if __BPF_CPU_VERSION__ < 4 +#define UNROLL_COUNT 90 +#endif +#elif __clang_major__ == 18 +#define UNROLL_COUNT 90 +#endif + #include "pyperf.h"