1

When I run the following code I get an error.

#include <uapi/linux/utsname.h>
#include <linux/pid_namespace.h>

struct uts_namespace {
    struct kref kref;
    struct new_utsname name;
};

static __always_inline char * get_task_uts_name(struct task_struct *task){
    return task->nsproxy->uts_ns->name.nodename;
}

int cmpNamespace(void *ctx) {
  struct task_struct *task;
  task = (struct task_struct *)bpf_get_current_task();

  if (strcmp(get_task_uts_name(task),"namespace")==0){

      ...

  }
  return 0;
}

Error:

bpf: Failed to load program: Invalid argument
unknown opcode 00
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

HINT: The 'unknown opcode' can happen if you reference a global or static variable, or data in read-only section. For example, 'char *p = "hello"' will result in p referencing a read-only section, and 'char p[] = "hello"' will have "hello" stored on the stack.

But this works just fine

int cmpNamespace(void *ctx) {
  char * test = "aaaa";

  if (strcmp(test,"namespace")==0){

      ...

  }
  return 0;
}

Can anyone tell me why this is happening and how I could go about correcting it ? I am using python bcc to hook the function.

Thanks!

Nuno Lopes
  • 57
  • 1
  • 7

1 Answers1

4

The issue is that you are using strcmp. BPF programs cannot use functions from the libc.

Your second example probably works because the compiler is able to optimize it and remove the call to strcmp. Since both arguments are known at compile-time, there's no need to use strcmp to know if they are equal.

As pointed out by @Qeole in comments, you can use __builtin_memcmp() instead, since you know the size of one of your strings and are only trying to know if they are equal.

pchaigno
  • 11,313
  • 2
  • 29
  • 54
  • Thanks for the quick response @pchaigno, makes sense!! Is there an alternative way to compare the string from get_task_uts_name(task) with a known at compile time string? – Nuno Lopes Feb 24 '20 at 21:43
  • It depends a lot on which kernel you want to support, what's the maximum length of the string, etc. On the latest kernels there is some support for bounded loops, so you could probably write your own `strcmp`. On older kernels (<5.3), you'll have to unroll that `strcmp`, which may make your BPF program too long or too complex. – pchaigno Feb 25 '20 at 07:01
  • 1
    `__builtin_memcmp()` is available and might also be helpful. – Qeole Feb 25 '20 at 08:38
  • 1
    how to link `__builtin_memcmp` in bpf code? it is not defined in LLVM – weima Jan 08 '23 at 16:21