I'm trying to set the OOM killer score adjustment for a process, inspired by [`oom_adjust_setup` in OpenSSH's `port_linux.c`](https://github.com/openssh/openssh-portable/blob/89a85d724765b6b82e0135ee5a1181fdcccea9c6/openbsd-compat/port-linux.c#L240-L311). To do that, I open `/proc/self/oom_score_adj`, read the old value, and write a new value. Obviously, my process needs to be root or have the capability `CAP_SYS_RESOURCE` to do that.

I'm getting a result that I can't explain. When my process doesn't have the capability, I'm able to open that file and read and write values, though the value I write doesn't take effect (fair enough):

```
$ ./a.out 
CAP_SYS_RESOURCE: not effective, not permitted, not inheritable
oom_score_adj value: 0
wrote 5 bytes
oom_score_adj value: 0

```

But when my process *does* have the capability, I *can't even open* the file: it fails with EACCES:

```
$ sudo setcap CAP_SYS_RESOURCE+eip a.out
$ ./a.out 
CAP_SYS_RESOURCE: effective, permitted, not inheritable
failed to open /proc/self/oom_score_adj: Permission denied

```

Why does it do that? What am I missing?

---

Some further googling led me to [this lkml post by Azat Khuzhin on 20 Oct 2013](https://lkml.org/lkml/2013/10/20/29). Apparently `CAP_SYS_RESOURCE` lets you change `oom_score_adj` for any process but yourself. To change your own score adjustment, you need to combine it with `CAP_DAC_OVERRIDE` - that is, disable access controls for all files. (If I wanted that, I would have made this program setuid root.)

So my question is, how can I achieve this *without* `CAP_DAC_OVERRIDE`?

---

I'm running Ubuntu xenial 16.04.4, kernel version 4.13.0-45-generic. My problem is similar to but different from [this question](https://stackoverflow.com/q/26963700/113848): that's about an error on `write`, when not having the capability.

My sample program:

```
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/capability.h>

void read_value(FILE *fp)
{
  int value;
  rewind(fp);
  if (fscanf(fp, "%d", &value) != 1) {
    fprintf(stderr, "read failed: %s\n", ferror(fp) ? strerror(errno) : "cannot parse");
  }
  else {
    fprintf(stderr, "oom_score_adj value: %d\n", value);
  }
}

void write_value(FILE *fp)
{
  int result;
  rewind(fp);
  result = fprintf(fp, "-1000");
  if (result < 0) {
    fprintf(stderr, "write failed: %s\n", strerror(errno));
  }
  else {
    fprintf(stderr, "wrote %d bytes\n", result);
  }
}

int main()
{
  FILE *fp;

  struct __user_cap_header_struct h;
  struct __user_cap_data_struct d;

  h.version = _LINUX_CAPABILITY_VERSION_3;
  h.pid = 0;
  if (0 != capget(&h, &d)) {
      fprintf(stderr, "capget failed: %s\n", strerror(errno));
  }
  else {
      fprintf(stderr, "CAP_SYS_RESOURCE: %s, %s, %s\n",
          d.effective & (1 << CAP_SYS_RESOURCE) ? "effective" : "not effective",
          d.permitted & (1 << CAP_SYS_RESOURCE) ? "permitted" : "not permitted",
          d.inheritable & (1 << CAP_SYS_RESOURCE) ? "inheritable" : "not inheritable");
  }

  fp = fopen("/proc/self/oom_score_adj", "r+");
  if (!fp) {
    fprintf(stderr, "failed to open /proc/self/oom_score_adj: %s\n", strerror(errno));
    return 1;
  }
  else {
    read_value(fp);
    write_value(fp);
    read_value(fp);
    fclose(fp);
  }
  return 0;
}

```