bpf: Make bpf_cgroup_acquire() KF_RCU | KF_RET_NULL
authorDavid Vernet <void@manifault.com>
Tue, 11 Apr 2023 04:16:31 +0000 (23:16 -0500)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 12 Apr 2023 19:57:54 +0000 (12:57 -0700)
struct cgroup is already an RCU-safe type in the verifier. We can
therefore update bpf_cgroup_acquire() to be KF_RCU | KF_RET_NULL, and
subsequently remove bpf_cgroup_kptr_get(). This patch does the first of
these by updating bpf_cgroup_acquire() to be KF_RCU | KF_RET_NULL, and
also updates selftests accordingly.

Signed-off-by: David Vernet <void@manifault.com>
Link: https://lore.kernel.org/r/20230411041633.179404-1-void@manifault.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/helpers.c
tools/testing/selftests/bpf/progs/cgrp_kfunc_common.h
tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
tools/testing/selftests/bpf/progs/cgrp_kfunc_success.c

index b6a5cda..71f0604 100644 (file)
@@ -2037,8 +2037,7 @@ __bpf_kfunc void bpf_task_release(struct task_struct *p)
  */
 __bpf_kfunc struct cgroup *bpf_cgroup_acquire(struct cgroup *cgrp)
 {
-       cgroup_get(cgrp);
-       return cgrp;
+       return cgroup_tryget(cgrp) ? cgrp : NULL;
 }
 
 /**
@@ -2314,7 +2313,7 @@ BTF_ID_FLAGS(func, bpf_rbtree_add)
 BTF_ID_FLAGS(func, bpf_rbtree_first, KF_RET_NULL)
 
 #ifdef CONFIG_CGROUPS
-BTF_ID_FLAGS(func, bpf_cgroup_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS)
+BTF_ID_FLAGS(func, bpf_cgroup_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_cgroup_kptr_get, KF_ACQUIRE | KF_KPTR_GET | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_cgroup_release, KF_RELEASE)
 BTF_ID_FLAGS(func, bpf_cgroup_ancestor, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
index d0b7cd0..b0e279f 100644 (file)
@@ -61,6 +61,11 @@ static inline int cgrps_kfunc_map_insert(struct cgroup *cgrp)
        }
 
        acquired = bpf_cgroup_acquire(cgrp);
+       if (!acquired) {
+               bpf_map_delete_elem(&__cgrps_kfunc_map, &id);
+               return -ENOENT;
+       }
+
        old = bpf_kptr_xchg(&v->cgrp, acquired);
        if (old) {
                bpf_cgroup_release(old);
index 48b2034..49347f1 100644 (file)
@@ -41,6 +41,23 @@ int BPF_PROG(cgrp_kfunc_acquire_untrusted, struct cgroup *cgrp, const char *path
 
        /* Can't invoke bpf_cgroup_acquire() on an untrusted pointer. */
        acquired = bpf_cgroup_acquire(v->cgrp);
+       if (acquired)
+               bpf_cgroup_release(acquired);
+
+       return 0;
+}
+
+SEC("tp_btf/cgroup_mkdir")
+__failure __msg("Possibly NULL pointer passed to trusted arg0")
+int BPF_PROG(cgrp_kfunc_acquire_no_null_check, struct cgroup *cgrp, const char *path)
+{
+       struct cgroup *acquired;
+
+       acquired = bpf_cgroup_acquire(cgrp);
+       /*
+        * Can't invoke bpf_cgroup_release() without checking the return value
+        * of bpf_cgroup_acquire().
+        */
        bpf_cgroup_release(acquired);
 
        return 0;
@@ -54,7 +71,8 @@ int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)
 
        /* Can't invoke bpf_cgroup_acquire() on a random frame pointer. */
        acquired = bpf_cgroup_acquire((struct cgroup *)&stack_cgrp);
-       bpf_cgroup_release(acquired);
+       if (acquired)
+               bpf_cgroup_release(acquired);
 
        return 0;
 }
@@ -67,7 +85,8 @@ int BPF_PROG(cgrp_kfunc_acquire_unsafe_kretprobe, struct cgroup *cgrp)
 
        /* Can't acquire an untrusted struct cgroup * pointer. */
        acquired = bpf_cgroup_acquire(cgrp);
-       bpf_cgroup_release(acquired);
+       if (acquired)
+               bpf_cgroup_release(acquired);
 
        return 0;
 }
@@ -80,7 +99,8 @@ int BPF_PROG(cgrp_kfunc_acquire_trusted_walked, struct cgroup *cgrp, const char
 
        /* Can't invoke bpf_cgroup_acquire() on a pointer obtained from walking a trusted cgroup. */
        acquired = bpf_cgroup_acquire(cgrp->old_dom_cgrp);
-       bpf_cgroup_release(acquired);
+       if (acquired)
+               bpf_cgroup_release(acquired);
 
        return 0;
 }
@@ -93,9 +113,8 @@ int BPF_PROG(cgrp_kfunc_acquire_null, struct cgroup *cgrp, const char *path)
 
        /* Can't invoke bpf_cgroup_acquire() on a NULL pointer. */
        acquired = bpf_cgroup_acquire(NULL);
-       if (!acquired)
-               return 0;
-       bpf_cgroup_release(acquired);
+       if (acquired)
+               bpf_cgroup_release(acquired);
 
        return 0;
 }
@@ -137,6 +156,8 @@ int BPF_PROG(cgrp_kfunc_get_non_kptr_acquired, struct cgroup *cgrp, const char *
        struct cgroup *kptr, *acquired;
 
        acquired = bpf_cgroup_acquire(cgrp);
+       if (!acquired)
+               return 0;
 
        /* Cannot use bpf_cgroup_kptr_get() on a non-map-value, even if the kptr was acquired. */
        kptr = bpf_cgroup_kptr_get(&acquired);
@@ -256,6 +277,8 @@ int BPF_PROG(cgrp_kfunc_release_null, struct cgroup *cgrp, const char *path)
                return -ENOENT;
 
        acquired = bpf_cgroup_acquire(cgrp);
+       if (!acquired)
+               return -ENOENT;
 
        old = bpf_kptr_xchg(&v->cgrp, acquired);
 
index 030aff7..e9dbd1a 100644 (file)
@@ -38,7 +38,10 @@ int BPF_PROG(test_cgrp_acquire_release_argument, struct cgroup *cgrp, const char
                return 0;
 
        acquired = bpf_cgroup_acquire(cgrp);
-       bpf_cgroup_release(acquired);
+       if (!acquired)
+               err = 1;
+       else
+               bpf_cgroup_release(acquired);
 
        return 0;
 }