如果我具有适当的能力,则无法打开/proc/self/oom_score_adj [英] Cannot open /proc/self/oom_score_adj when I have the right capability

查看:149
本文介绍了如果我具有适当的能力,则无法打开/proc/self/oom_score_adj的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据 Azat Khuzhin于2013年10月20日发布的lkml帖子.显然,CAP_SYS_RESOURCE 允许您为除您自己以外的任何进程更改 oom_score_adj.要更改自己的分数调整,您需要将其与 CAP_DAC_OVERRIDE 结合使用-也就是说,禁用所有文件的访问控制.(如果需要的话,我将使该程序的setuid为root.)

所以我的问题是,如何在没有的情况下实现 CAP_DAC_OVERRIDE ?


我正在运行Ubuntu xenial 16.04.4,内核版本为4.13.0-45(通用).我的问题与这个问题相似,但有所不同:这是关于 write 上的错误,当没有能力.

我的示例程序:

  #include< stdio.h>#include< string.h>#include< errno.h>#include< sys/capability.h>无效的read_value(FILE * fp){整数值倒带(fp);if(fscanf(fp,%d",& value)!= 1){fprintf(stderr,读取失败:%s \ n",ferror(fp)吗?strerror(errno):无法解析");}别的 {fprintf(stderr,"oom_score_adj值:%d \ n",值);}}无效write_value(FILE * fp){结果倒带(fp);结果= fprintf(fp,"-1000");如果(结果< 0){fprintf(stderr,写入失败:%s \ n",strerror(errno));}别的 {fprintf(stderr,写%d个字节\ n",结果);}}int main(){文件* fp;struct __user_cap_header_struct h;struct __user_cap_data_struct d;h.version = _LINUX_CAPABILITY_VERSION_3;h.pid = 0;如果(0!= capget(& h,& d)){fprintf(stderr,"capget failed:%s \ n",strerror(errno));}别的 {fprintf(stderr,"CAP_SYS_RESOURCE:%s,%s,%s \ n",d.有效的(1<< CAP_SYS_RESOURCE)?有效":无效",d.许可的(1<< CAP_SYS_RESOURCE)?"permitted":不允许",d.可继承的(1<< CAP_SYS_RESOURCE)?"inheritable":不可继承");}fp = fopen("/proc/self/oom_score_adj","r +");如果(!fp){fprintf(stderr,无法打开/proc/self/oom_score_adj:%s \ n",strerror(errno));返回1;}别的 {read_value(fp);write_value(fp);read_value(fp);fclose(fp);}返回0;} 

解决方案

破解这个非常有趣,花了我一段时间.

第一个真正的提示是对另一个问题的答案:/proc/self/下的文件归root所有-与 CAP_SYS_RESOURCE 或大约 oom _ * 个文件.您可以通过调用 stat 并使用其他功能来验证这一点.引用 man 5 proc :

/proc/[pid]

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

每个/proc/[pid]子目录包含下面描述的伪文件和目录.这些文件通常由进程的有效用户和有效组ID拥有.但是,作为一项安全措施,如果进程的"dumpable"属性设置为非1的值,则将所有权设置为root:root.此属性可能由于以下原因而发生更改:

将"dumpable"属性重置为1会将/proc/[pid]/*文件的所有权还原为进程的真实UID和真实GID.

这已经暗示了解决方案,但首先让我们更深入地研究一下,看看 man prctl :

PR_SET_DUMPABLE(从Linux 2.3.20开始)

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

在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)中包含的当前值:

不能转储的进程不能通过ptrace(2)PTRACE_ATTACH附加;有关更多详细信息,请参见ptrace(2).

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

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

如何使其工作

该修补程序很简单,只需在尝试打开文件之前重新设置该dumpable属性即可.打开文件之前,粘贴以下内容或类似内容:

  prctl(PR_SET_DUMPABLE,1,0,0,0); 

希望有帮助;)

I'm trying to set the OOM killer score adjustment for a process, inspired by oom_adjust_setup in OpenSSH's port_linux.c. 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. 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: 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;
}

解决方案

This one was very interesting to crack, took me a while.

The first real hint was this answer to a different question: https://unix.stackexchange.com/questions/364568/how-to-read-the-proc-pid-fd-directory-of-a-process-which-has-a-linux-capabil - just wanted to give the credit.

The reason it does not work as is

The real reason you get "permission denied" there is files under /proc/self/ are owned by root if the process has any capabilities - it's not about CAP_SYS_RESOURCE or about oom_* files specifically. You can verify this by calling stat and using different capabilities. Quoting man 5 proc:

/proc/[pid]

There is a numerical subdirectory for each running process; the subdirectory is named by the process ID.

Each /proc/[pid] subdirectory contains the pseudo-files and directories described below. These files are normally owned by the effective user and effective group ID of the process. However, as a security measure, the ownership is made root:root if the process's "dumpable" attribute is set to a value other than 1. This attribute may change for the following reasons:

  • The attribute was explicitly set via the prctl(2) PR_SET_DUMPABLE operation.

  • The attribute was reset to the value in the file /proc/sys/fs/suid_dumpable (described below), for the reasons described in prctl(2).

Resetting the "dumpable" attribute to 1 reverts the ownership of the /proc/[pid]/* files to the process's real UID and real GID.

This already hints to the solution, but first let's dig a little deeper and see that man prctl:

PR_SET_DUMPABLE (since Linux 2.3.20)

Set the state of the "dumpable" flag, which determines whether core dumps are produced for the calling process upon delivery of a signal whose default behavior is to produce a core dump.

In kernels up to and including 2.6.12, arg2 must be either 0 (SUID_DUMP_DISABLE, process is not dumpable) or 1 (SUID_DUMP_USER, process is dumpable). Between kernels 2.6.13 and 2.6.17, the value 2 was also permitted, which caused any binary which normally would not be dumped to be dumped readable by root only; for security reasons, this feature has been removed. (See also the description of /proc/sys/fs/suid_dumpable in proc(5).)

Normally, this flag is set to 1. However, it is reset to the current value contained in the file /proc/sys/fs/suid_dumpable (which by default has the value 0), in the following circumstances:

  • The process's effective user or group ID is changed.

  • The process's filesystem user or group ID is changed (see credentials(7)).

  • The process executes (execve(2)) a set-user-ID or set-group-ID program, resulting in a change of either the effective user ID or the effective group ID.

  • The process executes (execve(2)) a program that has file capabilities (see capabilities(7)), but only if the permitted capabilities gained exceed those already permitted for the process.

Processes that are not dumpable can not be attached via ptrace(2) PTRACE_ATTACH; see ptrace(2) for further details.

If a process is not dumpable, the ownership of files in the process's /proc/[pid] directory is affected as described in proc(5).

Now it's clear: our process has a capability that the shell used to launch it did not have, thus the dumpable attribute was set to false, thus files under /proc/self/ are owned by root rather than the current user.

How to make it work

The fix is as simple as re-setting that dumpable attribute before trying to open the file. Stick the following or something similar before opening the file:

prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);

Hope that helps ;)

这篇关于如果我具有适当的能力,则无法打开/proc/self/oom_score_adj的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆