Re: [RFC PATCH bpf-next 1/2] bpf: Add bpf_current_capable kfunc

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 17, 2023 at 11:31 AM Alexei Starovoitov
<alexei.starovoitov@xxxxxxxxx> wrote:
>
> On Wed, Aug 16, 2023 at 7:31 PM Yafang Shao <laoar.shao@xxxxxxxxx> wrote:
> >
> > On Thu, Aug 17, 2023 at 9:54 AM Alexei Starovoitov
> > <alexei.starovoitov@xxxxxxxxx> wrote:
> > >
> > > On Mon, Aug 14, 2023 at 7:46 PM Yafang Shao <laoar.shao@xxxxxxxxx> wrote:
> > > >
> > > > On Tue, Aug 15, 2023 at 8:28 AM Yonghong Song <yonghong.song@xxxxxxxxx> wrote:
> > > > >
> > > > >
> > > > >
> > > > > On 8/14/23 7:33 AM, Yafang Shao wrote:
> > > > > > Add a new bpf_current_capable kfunc to check whether the current task
> > > > > > has a specific capability. In our use case, we will use it in a lsm bpf
> > > > > > program to help identify if the user operation is permitted.
> > > > > >
> > > > > > Signed-off-by: Yafang Shao <laoar.shao@xxxxxxxxx>
> > > > > > ---
> > > > > >   kernel/bpf/helpers.c | 6 ++++++
> > > > > >   1 file changed, 6 insertions(+)
> > > > > >
> > > > > > diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> > > > > > index eb91cae..bbee7ea 100644
> > > > > > --- a/kernel/bpf/helpers.c
> > > > > > +++ b/kernel/bpf/helpers.c
> > > > > > @@ -2429,6 +2429,11 @@ __bpf_kfunc void bpf_rcu_read_unlock(void)
> > > > > >       rcu_read_unlock();
> > > > > >   }
> > > > > >
> > > > > > +__bpf_kfunc bool bpf_current_capable(int cap)
> > > > > > +{
> > > > > > +     return has_capability(current, cap);
> > > > > > +}
> > > > >
> > > > > Since you are testing against 'current' capabilities, I assume
> > > > > that the context should be process. Otherwise, you are testing
> > > > > against random task which does not make much sense.
> > > >
> > > > It is in the process context.
> > > >
> > > > >
> > > > > Since you are testing against 'current' cap, and if the capability
> > > > > for that task is stable, you do not need this kfunc.
> > > > > You can test cap in user space and pass it into the bpf program.
> > > > >
> > > > > But if the cap for your process may change in the middle of
> > > > > run, then you indeed need bpf prog to test capability in real time.
> > > > > Is this your use case and could you describe in in more detail?
> > > >
> > > > After we convert the capability of our networking bpf program from
> > > > CAP_SYS_ADMIN to CAP_BPF+CAP_NET_ADMIN to enhance the security, we
> > > > encountered the "pointer comparison prohibited" error, because
> > > > allow_ptr_leaks is enabled only when CAP_PERFMON is set. However, if
> > > > we enable the CAP_PERFMON for the networking bpf program, it can run
> > > > tracing bpf prog, perf_event bpf prog and etc, that is not expected by
> > > > us.
> > > >
> > > > Hence we are planning to use a lsm bpf program to disallow it from
> > > > running other bpf programs. In our lsm bpf program we will check the
> > > > capability of processes, if the process has cap_net_admin, cap_bpf and
> > > > cap_perfmon but don't have cap_sys_admin we will refuse it to run
> > > > tracing and perf_event bpf program. While if a process has  cap_bpf
> > > > and cap_perfmon but doesn't have cap_net_admin, that said it is a bpf
> > > > program which wants to run trace bpf, we will allow it.
> > > >
> > > > We can't use lsm_cgroup because it is supported on cgroup2 only, while
> > > > we're still using cgroup1.
> > > >
> > > > Another possible solution is enable allow_ptr_leaks for cap_net_admin
> > > > as well, but after I checked the commit which introduces the cap_bpf
> > > > and cap_perfmon [1], I think we wouldn't like to do it.
> > >
> > > Sorry. None of these options are acceptable.
> > >
> > > The idea of introducing a bpf_current_capable() kfunc just to work
> > > around a deficiency in the verifier is not sound.
> >
> > So what should we do then?
> > Just enabling the cap_perfmon for it? That does not sound as well ...
>
> Yonghong already pointed out upthread that
> comparison of two packet pointers is not a pointer leak.
> See this code:
>         } else if (!try_match_pkt_pointers(insn, dst_reg, &regs[insn->src_reg],
>                                            this_branch, other_branch) &&
>                    is_pointer_value(env, insn->dst_reg)) {
>                 verbose(env, "R%d pointer comparison prohibited\n",
>                         insn->dst_reg);
>                 return -EACCES;
>         }
>
> It's not clear why it doesn't address your case.

It can address the issue.
It seems we should do the code change below.

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 0b9da95..c66dc61 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -13819,6 +13819,18 @@ static int check_cond_jmp_op(struct
bpf_verifier_env *env,
                return -EINVAL;
        }

+       other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx,
+                                 false);
+       if (!other_branch)
+               return -EFAULT;
+
+       /* check src2 operand */
+       err = check_reg_arg(env, insn->dst_reg, SRC_OP);
+       if (err)
+               return err;
+
+       dst_reg = &regs[insn->dst_reg];
+
        if (BPF_SRC(insn->code) == BPF_X) {
                if (insn->imm != 0) {
                        verbose(env, "BPF_JMP/JMP32 uses reserved fields\n");
@@ -13830,7 +13842,9 @@ static int check_cond_jmp_op(struct
bpf_verifier_env *env,
                if (err)
                        return err;

-               if (is_pointer_value(env, insn->src_reg)) {
+               if (!try_match_pkt_pointers(insn, dst_reg, &regs[insn->src_reg],
+                                          this_branch, other_branch) &&
+                   is_pointer_value(env, insn->src_reg)) {
                        verbose(env, "R%d pointer comparison prohibited\n",
                                insn->src_reg);
                        return -EACCES;
@@ -13843,12 +13857,6 @@ static int check_cond_jmp_op(struct
bpf_verifier_env *env,
                }
        }

-       /* check src2 operand */
-       err = check_reg_arg(env, insn->dst_reg, SRC_OP);
-       if (err)
-               return err;
-
-       dst_reg = &regs[insn->dst_reg];
        is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;

        if (BPF_SRC(insn->code) == BPF_K) {
@@ -13920,10 +13928,6 @@ static int check_cond_jmp_op(struct
bpf_verifier_env *env,
                return 0;
        }

-       other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx,
-                                 false);
-       if (!other_branch)
-               return -EFAULT;
        other_branch_regs = other_branch->frame[other_branch->curframe]->regs;

        /* detect if we are comparing against a constant value so we can adjust


-- 
Regards
Yafang





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux