1. 26 Mar, 2023 33 commits
  2. 25 Mar, 2023 4 commits
    • Alexei Starovoitov's avatar
      Merge branch 'Don't invoke KPTR_REF destructor on NULL xchg' · 496f4f1b
      Alexei Starovoitov authored
      David Vernet says:
      
      ====================
      
      When a map value is being freed, we loop over all of the fields of the
      corresponding BPF object and issue the appropriate cleanup calls
      corresponding to the field's type. If the field is a referenced kptr, we
      atomically xchg the value out of the map, and invoke the kptr's
      destructor on whatever was there before.
      
      Currently, we always invoke the destructor (or bpf_obj_drop() for a
      local kptr) on any kptr, including if no value was xchg'd out of the
      map. This means that any function serving as the kptr's KF_RELEASE
      destructor must always treat the argument as possibly NULL, and we
      invoke unnecessary (and seemingly unsafe) cleanup logic for the local
      kptr path as well.
      
      This is an odd requirement -- KF_RELEASE kfuncs that are invoked by BPF
      programs do not have this restriction, and the verifier will fail to
      load the program if the register containing the to-be-released type has
      any untrusted modifiers (e.g. PTR_UNTRUSTED or PTR_MAYBE_NULL). So as to
      simplify the expectations required for a KF_RELEASE kfunc, this patch
      set updates the KPTR_REF destructor logic to only be invoked when a
      non-NULL value is xchg'd out of the map.
      
      Additionally, the patch removes now-unnecessary KF_RELEASE calls from
      several kfuncs, and finally, updates the verifier to have KF_RELEASE
      automatically imply KF_TRUSTED_ARGS. This restriction was already
      implicitly happening because of the aforementioned logic in the verifier
      to reject any regs with untrusted modifiers, and to enforce that
      KF_RELEASE args are passed with a 0 offset. This change just updates the
      behavior to match that of other trusted args. This patch is left to the
      end of the series in case it happens to be controversial, as it arguably
      is slightly orthogonal to the purpose of the rest of the series.
      ====================
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      496f4f1b
    • David Vernet's avatar
      bpf: Treat KF_RELEASE kfuncs as KF_TRUSTED_ARGS · 6c831c46
      David Vernet authored
      KF_RELEASE kfuncs are not currently treated as having KF_TRUSTED_ARGS,
      even though they have a superset of the requirements of KF_TRUSTED_ARGS.
      Like KF_TRUSTED_ARGS, KF_RELEASE kfuncs require a 0-offset argument, and
      don't allow NULL-able arguments. Unlike KF_TRUSTED_ARGS which require
      _either_ an argument with ref_obj_id > 0, _or_ (ref->type &
      BPF_REG_TRUSTED_MODIFIERS) (and no unsafe modifiers allowed), KF_RELEASE
      only allows for ref_obj_id > 0.  Because KF_RELEASE today doesn't
      automatically imply KF_TRUSTED_ARGS, some of these requirements are
      enforced in different ways that can make the behavior of the verifier
      feel unpredictable. For example, a KF_RELEASE kfunc with a NULL-able
      argument will currently fail in the verifier with a message like, "arg#0
      is ptr_or_null_ expected ptr_ or socket" rather than "Possibly NULL
      pointer passed to trusted arg0". Our intention is the same, but the
      semantics are different due to implemenetation details that kfunc authors
      and BPF program writers should not need to care about.
      
      Let's make the behavior of the verifier more consistent and intuitive by
      having KF_RELEASE kfuncs imply the presence of KF_TRUSTED_ARGS. Our
      eventual goal is to have all kfuncs assume KF_TRUSTED_ARGS by default
      anyways, so this takes us a step in that direction.
      
      Note that it does not make sense to assume KF_TRUSTED_ARGS for all
      KF_ACQUIRE kfuncs. KF_ACQUIRE kfuncs can have looser semantics than
      KF_RELEASE, with e.g. KF_RCU | KF_RET_NULL. We may want to have
      KF_ACQUIRE imply KF_TRUSTED_ARGS _unless_ KF_RCU is specified, but that
      can be left to another patch set, and there are no such subtleties to
      address for KF_RELEASE.
      Signed-off-by: default avatarDavid Vernet <void@manifault.com>
      Link: https://lore.kernel.org/r/20230325213144.486885-4-void@manifault.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      6c831c46
    • David Vernet's avatar
      bpf: Remove now-unnecessary NULL checks for KF_RELEASE kfuncs · fb2211a5
      David Vernet authored
      Now that we're not invoking kfunc destructors when the kptr in a map was
      NULL, we no longer require NULL checks in many of our KF_RELEASE kfuncs.
      This patch removes those NULL checks.
      Signed-off-by: default avatarDavid Vernet <void@manifault.com>
      Link: https://lore.kernel.org/r/20230325213144.486885-3-void@manifault.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      fb2211a5
    • David Vernet's avatar
      bpf: Only invoke kptr dtor following non-NULL xchg · 1431d0b5
      David Vernet authored
      When a map value is being freed, we loop over all of the fields of the
      corresponding BPF object and issue the appropriate cleanup calls
      corresponding to the field's type. If the field is a referenced kptr, we
      atomically xchg the value out of the map, and invoke the kptr's
      destructor on whatever was there before (or bpf_obj_drop() it if it was
      a local kptr).
      
      Currently, we always invoke the destructor (either bpf_obj_drop() or the
      kptr's registered destructor) on any KPTR_REF-type field in a map, even
      if there wasn't a value in the map. This means that any function serving
      as the kptr's KF_RELEASE destructor must always treat the argument as
      possibly NULL, as the following can and regularly does happen:
      
      void *xchgd_field;
      
      /* No value was in the map, so xchgd_field is NULL */
      xchgd_field = (void *)xchg(unsigned long *field_ptr, 0);
      field->kptr.dtor(xchgd_field);
      
      These are odd semantics to impose on KF_RELEASE kfuncs -- BPF programs
      are prohibited by the verifier from passing NULL pointers to KF_RELEASE
      kfuncs, so it doesn't make sense to require this of BPF programs, but
      not the main kernel destructor path. It's also unnecessary to invoke any
      cleanup logic for local kptrs. If there is no object there, there's
      nothing to drop.
      
      So as to allow KF_RELEASE kfuncs to fully assume that an argument is
      non-NULL, this patch updates a KPTR_REF's destructor to only be invoked
      when a non-NULL value is xchg'd out of the kptr map field.
      Signed-off-by: default avatarDavid Vernet <void@manifault.com>
      Link: https://lore.kernel.org/r/20230325213144.486885-2-void@manifault.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      1431d0b5
  3. 24 Mar, 2023 1 commit
  4. 23 Mar, 2023 2 commits
    • Martin KaFai Lau's avatar
      Merge branch 'Transit between BPF TCP congestion controls.' · 226bc6ae
      Martin KaFai Lau authored
      Kui-Feng Lee says:
      
      ====================
      
      Major changes:
      
       - Create bpf_links in the kernel for BPF struct_ops to register and
         unregister it.
      
       - Enables switching between implementations of bpf-tcp-cc under a
         name instantly by replacing the backing struct_ops map of a
         bpf_link.
      
      Previously, BPF struct_ops didn't go off, as even when the user
      program creating it was terminated, none of these ever were pinned.
      For instance, the TCP congestion control subsystem indirectly
      maintains a reference count on the struct_ops of any registered BPF
      implemented algorithm. Thus, the algorithm won't be deactivated until
      someone deliberately unregisters it.  For compatibility with other BPF
      programs, bpf_links have been created to work in coordination with
      struct_ops maps. This ensures that the registration and unregistration
      of these respective maps is carried out at the start and end of the
      bpf_link.
      
      We also faced complications when attempting to replace an existing TCP
      congestion control algorithm with a new implementation on the fly. A
      struct_ops map was used to register a TCP congestion control algorithm
      with a unique name.  We had to either register the alternative
      implementation with a new name and move over or unregister the current
      one before being able to reregistration with the same name.  To fix
      this problem, we can an option to migrate the registration of the
      algorithm from struct_ops maps to bpf_links. By modifying the backing
      map of a bpf_link, it suddenly becomes possible to replace an existing
      TCP congestion control algorithm with ease.
      ---
      
      The major differences from v11:
      
       - Fix incorrectly setting both old_prog_fd and old_map_fd.
      
      The major differences from v10:
      
       - Add old_map_fd as an additional field instead of an union in
         bpf_link_update_opts.
      
      The major differences from v9:
      
       - Add test case for BPF_F_LINK.  Includes adding old_map_fd to struct
         bpf_link_update_opts in patch 6.
      
       - Return -EPERM instead of -EINVAL when the old map fd doesn't match
         with BPF_F_LINK.
      
       - Fix -EBUSY case in bpf_map__attach_struct_ops().
      
      The major differences form v8:
      
       - Check bpf_struct_ops::{validate,update} in
         bpf_struct_ops_map_alloc()
      
      The major differences from v7:
      
       - Use synchronize_rcu_mult(call_rcu, call_rcu_tasks) to replace
         synchronize_rcu() and synchronize_rcu_tasks().
      
       - Call synchronize_rcu() in tcp_update_congestion_control().
      
       - Handle -EBUSY in bpf_map__attach_struct_ops() to allow a struct_ops
         can be used to create links more than once.  Include a test case.
      
       - Add old_map_fd to bpf_attr and handle BPF_F_REPLACE in
         bpf_struct_ops_map_link_update().
      
       - Remove changes in bpf_dummy_struct_ops.c and add a check of .update
         function pointer of bpf_struct_ops.
      
      The major differences from v6:
      
       - Reword commit logs of the patch 1, 2, and 8.
      
       - Call synchronize_rcu_tasks() as well in bpf_struct_ops_map_free().
      
       - Refactor bpf_struct_ops_map_free() so that
         bpf_struct_ops_map_alloc() can free a struct_ops without waiting
         for a RCU grace period.
      
      The major differences from v5:
      
       - Add a new step to bpf_object__load() to prepare vdata.
      
       - Accept BPF_F_REPLACE.
      
       - Check section IDs in find_struct_ops_map_by_offset()
      
       - Add a test case to check mixing w/ and w/o link struct_ops.
      
       - Add a test case of using struct_ops w/o link to update a link.
      
       - Improve bpf_link__detach_struct_ops() to handle the w/ link case.
      
      The major differences from v4:
      
       - Rebase.
      
       - Reorder patches and merge part 4 to part 2 of the v4.
      
      The major differences from v3:
      
       - Remove bpf_struct_ops_map_free_rcu(), and use synchronize_rcu().
      
       - Improve the commit log of the part 1.
      
       - Before transitioning to the READY state, we conduct a value check
         to ensure that struct_ops can be successfully utilized and links
         created later.
      
      The major differences from v2:
      
       - Simplify states
      
         - Remove TOBEUNREG.
      
         - Rename UNREG to READY.
      
       - Stop using the refcnt of the kvalue of a struct_ops. Explicitly
         increase and decrease the refcount of struct_ops.
      
       - Prepare kernel vdata during the load phase of libbpf.
      
      The major differences from v1:
      
       - Added bpf_struct_ops_link to replace the previous union-based
         approach.
      
       - Added UNREG and TOBEUNREG to the state of bpf_struct_ops_map.
      
         - bpf_struct_ops_transit_state() maintains state transitions.
      
       - Fixed synchronization issue.
      
       - Prepare kernel vdata of struct_ops during the loading phase of
         bpf_object.
      
       - Merged previous patch 3 to patch 1.
      
      v11: https://lore.kernel.org/all/20230323010409.2265383-1-kuifeng@meta.com/
      v10: https://lore.kernel.org/all/20230321232813.3376064-1-kuifeng@meta.com/
      v9: https://lore.kernel.org/all/20230320195644.1953096-1-kuifeng@meta.com/
      v8: https://lore.kernel.org/all/20230318053144.1180301-1-kuifeng@meta.com/
      v7: https://lore.kernel.org/all/20230316023641.2092778-1-kuifeng@meta.com/
      v6: https://lore.kernel.org/all/20230310043812.3087672-1-kuifeng@meta.com/
      v5: https://lore.kernel.org/all/20230308005050.255859-1-kuifeng@meta.com/
      v4: https://lore.kernel.org/all/20230307232913.576893-1-andrii@kernel.org/
      v3: https://lore.kernel.org/all/20230303012122.852654-1-kuifeng@meta.com/
      v2: https://lore.kernel.org/bpf/20230223011238.12313-1-kuifeng@meta.com/
      v1: https://lore.kernel.org/bpf/20230214221718.503964-1-kuifeng@meta.com/
      ====================
      Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
      226bc6ae
    • Kui-Feng Lee's avatar
      selftests/bpf: Test switching TCP Congestion Control algorithms. · 06da9f3b
      Kui-Feng Lee authored
      Create a pair of sockets that utilize the congestion control algorithm
      under a particular name. Then switch up this congestion control
      algorithm to another implementation and check whether newly created
      connections using the same cc name now run the new implementation.
      
      Also, try to update a link with a struct_ops that is without
      BPF_F_LINK or with a wrong or different name.  These cases should fail
      due to the violation of assumptions.  To update a bpf_link of a
      struct_ops, it must be replaced with another struct_ops that is
      identical in type and name and has the BPF_F_LINK flag.
      
      The other test case is to create links from the same struct_ops more
      than once.  It makes sure a struct_ops can be used repeatly.
      Signed-off-by: default avatarKui-Feng Lee <kuifeng@meta.com>
      Link: https://lore.kernel.org/r/20230323032405.3735486-9-kuifeng@meta.comSigned-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
      06da9f3b