Я пытаюсь настроить корректировку оценки убийцы OOM для процесса, вдохновленного oom_adjust_setup
в OpenSSH port_linux.c
. Для этого я открываю /proc/self/oom_score_adj
, читаю старое значение и записываю новое значение. Очевидно, что мой процесс должен быть root или иметь возможность CAP_SYS_RESOURCE
сделать это.
Я получаю результат, который я не могу объяснить. Когда у моего процесса нет возможности, я могу открыть этот файл и прочитать и записать значения, хотя значение, которое я пишу, не вступает в силу (достаточно справедливо):
$ ./a.out
CAP_SYS_RESOURCE: not effective, not permitted, not inheritable
oom_score_adj value: 0
wrote 5 bytes
oom_score_adj value: 0
Но когда у моего процесса есть возможность, я даже не могу открыть файл: он не работает с 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
Почему это так? Что мне не хватает?
Еще один гуглинг привел меня на этот lkml пост Азата Хужина 20 октября 2013 года. По-видимому, CAP_SYS_RESOURCE
позволяет вам изменять oom_score_adj
для любого процесса, кроме вас. Чтобы изменить собственную настройку оценки, вам необходимо объединить ее с CAP_DAC_OVERRIDE
то есть отключить элементы управления доступом для всех файлов. (Если бы я этого хотел, я бы сделал эту программу setuid root.)
Итак, мой вопрос: как я могу достичь этого без CAP_DAC_OVERRIDE
?
Я запускаю Ubuntu xenial 16.04.4, версию ядра 4.13.0-45-generic. Моя проблема аналогична, но отличается от этого вопроса: об ошибке при write
, когда у вас нет возможности.
Моя примерная программа:
#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;
}