Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当我有正确的能力时,无法打开/proc/self/oom\u score\u adj_C_Linux - Fatal编程技术网

当我有正确的能力时,无法打开/proc/self/oom\u score\u adj

当我有正确的能力时,无法打开/proc/self/oom\u score\u adj,c,linux,C,Linux,我正试图设置一个过程的OOM killer分数调整,灵感来自。为此,我打开/proc/self/oom\u score\u adj,读取旧值,然后写入新值。显然,我的进程需要是根进程,或者具有CAP\u SYS\u RESOURCE这样做的能力 我得到了一个无法解释的结果。当我的进程不具备该功能时,我可以打开该文件并读取和写入值,尽管我写入的值没有生效(足够公平): 但当我的进程确实具备此功能时,我甚至无法打开该文件:它在EACCES中失败: $ sudo setcap CAP_SYS_RESO

我正试图设置一个过程的OOM killer分数调整,灵感来自。为此,我打开
/proc/self/oom\u score\u adj
,读取旧值,然后写入新值。显然,我的进程需要是根进程,或者具有
CAP\u SYS\u RESOURCE
这样做的能力

我得到了一个无法解释的结果。当我的进程不具备该功能时,我可以打开该文件并读取和写入值,尽管我写入的值没有生效(足够公平):

但当我的进程确实具备此功能时,我甚至无法打开该文件:它在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
为什么会这样?我错过了什么


进一步的谷歌搜索让我找到了。显然,
CAP\u SYS\u RESOURCE
允许您更改除您自己之外的任何流程的
oom\u score\u adj
。要更改自己的分数调整,您需要将其与
CAP\u DAC\u OVERRIDE
相结合,即禁用所有文件的访问控制。(如果我想要的话,我会让这个程序成为setuid root。)

所以我的问题是,如果没有
CAP\u DAC\u OVERRIDE
,我如何实现这一点


我正在运行UbuntuXenial 16.04.4,内核版本4.13.0-45-generic。我的问题类似于但不同于:这是关于
写入时发生错误,当时没有该功能

我的示例程序:

#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;
}
#包括
#包括
#包括
#包括
无效读取值(文件*fp)
{
int值;
倒带(fp);
如果(fscanf(fp、%d、&value)!=1){
fprintf(stderr,“读取失败:%s\n”,ferror(fp)?strerror(errno):“无法解析”);
}
否则{
fprintf(标准,“oom\u得分调整值:%d\n”,值);
}
}
无效写入值(文件*fp)
{
int结果;
倒带(fp);
结果=fprintf(fp,“-1000”);
如果(结果<0){
fprintf(stderr,“写入失败:%s\n”,strerror(errno));
}
否则{
fprintf(stderr,“写入%d字节\n”,结果);
}
}
int main()
{
文件*fp;
结构uu用户u封顶u标题u结构h;
结构uu用户u cap u数据u结构d;
h、 版本=\u LINUX\u功能\u版本\u 3;
h、 pid=0;
如果(0!=capget(&h,&d)){
fprintf(stderr,“capget失败:%s\n”,strerror(errno));
}
否则{
fprintf(标准,“CAP系统资源:%s,%s,%s\n”,

d、 有效&(1这一个非常有趣,我花了一段时间才破解

第一个真正的暗示是对另一个问题的回答:-只是想给予信任

它不能正常工作的原因是 你被“拒绝许可”的真正原因如果进程具有任何功能,则
/proc/self/
下的文件归root所有-这不是关于
CAP\u SYS\u RESOURCE
或关于
oom*
文件。您可以通过调用
stat
并使用不同的功能来验证这一点。引用
man 5 proc

/过程/[pid]

每个正在运行的进程都有一个数字子目录;子目录由进程ID命名

每个/proc/[pid]子目录都包含下面描述的伪文件和目录。这些文件通常由进程的有效用户和有效组ID拥有。但是,作为安全措施,如果进程的“可转储”,则将所有权设为root:root属性设置为1以外的值。此属性可能会因以下原因而更改:

  • 该属性是通过prctl(2)PR_set_DUMPABLE操作显式设置的

  • 由于prctl(2)中描述的原因,该属性被重置为文件/proc/sys/fs/suid_dumpable(如下所述)中的值

将“dumpable”属性重置为1会将/proc/[pid]/*文件的所有权恢复为进程的真实UID和真实GID

这已经暗示了解决方案,但首先让我们深入一点,看看
manprctl

PR_SET_DUMPABLE(从Linux 2.3.20开始)

设置“dumpable”标志的状态,该标志确定在传递默认行为为生成核心转储的信号时,是否为调用进程生成核心转储

在2.6.12之前(含2.6.12)的内核中,arg2必须是0(SUID_DUMP_DISABLE,进程不可转储)或1(SUID_DUMP_USER,进程可转储)。在内核2.6.13和2.6.17之间,还允许使用值2,这导致任何通常不会转储的二进制文件只能由root读取转储;出于安全原因,此功能已被删除。(另请参见proc(5)中的/proc/sys/fs/suid_dumpable说明。)

通常,此标志设置为1。但是,在以下情况下,它将重置为文件/proc/sys/fs/suid_dumpable中包含的当前值(默认值为0):

  • 进程的有效用户或组ID已更改

  • 进程的文件系统用户或组ID已更改(请参阅凭据(7))

  • 该进程执行(execve(2))设置用户ID或设置组ID程序,导致有效用户ID或有效组ID的更改

  • 进程执行(execve(2))一个具有文件功能的程序(请参阅功能(7)),但前提是获得的允许功能超过了进程已经允许的功能。

无法通过ptrace(2)ptrace_ATTACH连接不可转储的进程;有关更多详细信息,请参阅ptrace(2)

如果进程不可转储,则进程的/proc/[pid]目录中文件的所有权将受到影响,如proc(5)所述

现在很清楚了:我们的进程具有用于启动它的shell所没有的功能,因此dumpable属性被设置为false,因此
/proc/self/
下的文件由root用户而不是当前用户拥有

如何让它工作 修复方法非常简单,只需在尝试恢复之前重新设置可转储属性
#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;
}
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);