goto free_prog_sec;
        }
 
+       /*
+        * Bookkeeping for managing the program attachment chain.
+        *
+        * It might be tempting to set attach_tracing_prog flag at the attachment
+        * time, but this will not prevent from loading bunch of tracing prog
+        * first, then attach them one to another.
+        *
+        * The flag attach_tracing_prog is set for the whole program lifecycle, and
+        * doesn't have to be cleared in bpf_tracing_link_release, since tracing
+        * programs cannot change attachment target.
+        */
+       if (type == BPF_PROG_TYPE_TRACING && dst_prog &&
+           dst_prog->type == BPF_PROG_TYPE_TRACING) {
+               prog->aux->attach_tracing_prog = true;
+       }
+
        /* find program type: socket_filter vs tracing_filter */
        err = find_prog_type(type, prog);
        if (err < 0)
        }
 
        if (tgt_prog_fd) {
-               /* For now we only allow new targets for BPF_PROG_TYPE_EXT */
+               /*
+                * For now we only allow new targets for BPF_PROG_TYPE_EXT. If this
+                * part would be changed to implement the same for
+                * BPF_PROG_TYPE_TRACING, do not forget to update the way how
+                * attach_tracing_prog flag is set.
+                */
                if (prog->type != BPF_PROG_TYPE_EXT) {
                        err = -EINVAL;
                        goto out_put_prog;
 
                            struct bpf_attach_target_info *tgt_info)
 {
        bool prog_extension = prog->type == BPF_PROG_TYPE_EXT;
+       bool prog_tracing = prog->type == BPF_PROG_TYPE_TRACING;
        const char prefix[] = "btf_trace_";
        int ret = 0, subprog = -1, i;
        const struct btf_type *t;
                        bpf_log(log, "Can attach to only JITed progs\n");
                        return -EINVAL;
                }
-               if (tgt_prog->type == prog->type) {
-                       /* Cannot fentry/fexit another fentry/fexit program.
-                        * Cannot attach program extension to another extension.
-                        * It's ok to attach fentry/fexit to extension program.
+               if (prog_tracing) {
+                       if (aux->attach_tracing_prog) {
+                               /*
+                                * Target program is an fentry/fexit which is already attached
+                                * to another tracing program. More levels of nesting
+                                * attachment are not allowed.
+                                */
+                               bpf_log(log, "Cannot nest tracing program attach more than once\n");
+                               return -EINVAL;
+                       }
+               } else if (tgt_prog->type == prog->type) {
+                       /*
+                        * To avoid potential call chain cycles, prevent attaching of a
+                        * program extension to another extension. It's ok to attach
+                        * fentry/fexit to extension program.
                         */
                        bpf_log(log, "Cannot recursively attach\n");
                        return -EINVAL;
                         * except fentry/fexit. The reason is the following.
                         * The fentry/fexit programs are used for performance
                         * analysis, stats and can be attached to any program
-                        * type except themselves. When extension program is
-                        * replacing XDP function it is necessary to allow
-                        * performance analysis of all functions. Both original
-                        * XDP program and its program extension. Hence
-                        * attaching fentry/fexit to BPF_PROG_TYPE_EXT is
-                        * allowed. If extending of fentry/fexit was allowed it
-                        * would be possible to create long call chain
-                        * fentry->extension->fentry->extension beyond
-                        * reasonable stack size. Hence extending fentry is not
-                        * allowed.
+                        * type. When extension program is replacing XDP function
+                        * it is necessary to allow performance analysis of all
+                        * functions. Both original XDP program and its program
+                        * extension. Hence attaching fentry/fexit to
+                        * BPF_PROG_TYPE_EXT is allowed. If extending of
+                        * fentry/fexit was allowed it would be possible to create
+                        * long call chain fentry->extension->fentry->extension
+                        * beyond reasonable stack size. Hence extending fentry
+                        * is not allowed.
                         */
                        bpf_log(log, "Cannot extend fentry/fexit\n");
                        return -EINVAL;