Skip to content

Commit

Permalink
seccomp: support allowlist/denylist in profiles
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
  • Loading branch information
Christian Brauner committed Jul 18, 2020
1 parent 5941009 commit 4bc5137
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 52 deletions.
4 changes: 2 additions & 2 deletions config/templates/common.conf.in
Expand Up @@ -17,7 +17,7 @@ lxc.hook.clone = @LXCHOOKDIR@/clonehostname

# Default legacy cgroup configuration
#
# CGroup whitelist
# CGroup allowlist
lxc.cgroup.devices.deny = a
## Allow any mknod (but not reading/writing the node)
lxc.cgroup.devices.allow = c *:* m
Expand Down Expand Up @@ -46,7 +46,7 @@ lxc.cgroup.devices.allow = c 10:229 rwm

# Default unified cgroup configuration
#
# CGroup whitelist
# CGroup allowlist
lxc.cgroup2.devices.deny = a
## Allow any mknod (but not reading/writing the node)
lxc.cgroup2.devices.allow = c *:* m
Expand Down
2 changes: 1 addition & 1 deletion config/templates/common.seccomp
@@ -1,5 +1,5 @@
2
blacklist
denylist
reject_force_umount # comment this to allow umount -f; not recommended
[all]
kexec_load errno 1
Expand Down
6 changes: 3 additions & 3 deletions doc/examples/Makefile.am
Expand Up @@ -10,7 +10,7 @@ pkgexamples_DATA = \
lxc-veth.conf \
lxc-complex.conf \
seccomp-v1.conf \
seccomp-v2-blacklist.conf \
seccomp-v2-denylist.conf \
seccomp-v2.conf
endif

Expand All @@ -23,10 +23,10 @@ noinst_DATA = \
lxc-veth.conf.in \
lxc-complex.conf.in \
seccomp-v1.conf \
seccomp-v2-blacklist.conf \
seccomp-v2-denylist.conf \
seccomp-v2.conf

EXTRA_DIST = \
seccomp-v1.conf \
seccomp-v2-blacklist.conf \
seccomp-v2-denylist.conf \
seccomp-v2.conf
2 changes: 1 addition & 1 deletion doc/examples/seccomp-v1.conf
@@ -1,5 +1,5 @@
1
whitelist
allowlist
0
1
2
Expand Down
@@ -1,7 +1,7 @@
2
blacklist
denylist
# v2 allows comments after the second line, with '#' in first column,
# blacklist will allow syscalls by default
# denylist will allow syscalls by default
# if 'errno 0' was not appended to 'mknod' below, then the task would
# simply be killed when it tried to mknod. 'errno 0' means do not allow
# the container to mknod, but immediately return 0.
Expand Down
8 changes: 4 additions & 4 deletions doc/examples/seccomp-v2.conf
@@ -1,7 +1,7 @@
2
whitelist trap
# 'whitelist' would normally mean kill a task doing any syscall which is not
# whitelisted below. By appending 'trap' to the line, we will cause a SIGSYS
allowlist trap
# 'allowlist' would normally mean kill a task doing any syscall which is not
# allowlisted below. By appending 'trap' to the line, we will cause a SIGSYS
# to be sent to the task instead. 'errno 0' would mean don't allow the system
# call but immediately return 0. 'errno 22' would mean return EINVAL immediately.
[x86_64]
Expand All @@ -20,5 +20,5 @@ read
write
mount
umount2
# Do note that this policy does not whitelist enough system calls to allow a
# Do note that this policy does not allowlist enough system calls to allow a
# system container to boot.
18 changes: 9 additions & 9 deletions doc/ja/lxc.container.conf.sgml.in
Expand Up @@ -2239,7 +2239,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
standard namespace identifiers as seen in the
<filename>/proc/PID/ns</filename> directory.
The <option>lxc.namespace.keep</option> is a
blacklist option, i.e. it is useful when enforcing that containers
denylist option, i.e. it is useful when enforcing that containers
must keep a specific set of namespaces.
-->
コンテナが、作成元のプロセスから継承する (新しい名前空間を作らずに元のプロセスの名前空間のまま実行する) 名前空間を指定します。継承する名前空間はスペース区切りのリストで指定します。指定する名前空間名は、<filename>/proc/PID/ns</filename> ディレクトリ内に存在する標準の名前空間指示子でなければなりません。<option>lxc.namespace.keep</option> はブラックリストを指定するオプションです。つまり、コンテナに特定の名前空間を使い続けることを強制したい場合に便利です。
Expand Down Expand Up @@ -2660,26 +2660,26 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
<para>
<!--
Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is whitelisted,
while every unlisted number is blacklisted for use in the container
policy is a simple allowlist. The second line therefore must
read "allowlist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is allowlisted,
while every unlisted number is denylisted for use in the container
-->
現時点では、バージョン番号は 1 と 2 をサポートしています。バージョン 1 では、ポリシーはシンプルなホワイトリストですので、2 行目は "whitelist" でなければなりません。
現時点では、バージョン番号は 1 と 2 をサポートしています。バージョン 1 では、ポリシーはシンプルなホワイトリストですので、2 行目は "allowlist" でなければなりません。
そして残りの行には 1 行に 1 つずつ、システムコール番号を書きます。各行のシステムコール番号がホワイトリスト化され、リストにない番号は、そのコンテナではブラックリストに入ります。
</para>

<para>
<!--
In version 2, the policy may be blacklist or whitelist,
In version 2, the policy may be denylist or allowlist,
supports per-rule and per-policy default actions, and supports
per-architecture system call resolution from textual names.
-->
バージョン 2 では、ポリシーはブラックリストもしくはホワイトリストで表され、ルールごとのアクションと、ポリシーごとのデフォルトのアクションを設定できます。そして、アーキテクチャごとの設定と、テキストで書かれたシステムコール名での設定が可能です。
</para>
<para>
<!--
An example blacklist policy, in which all system calls are
An example denylist policy, in which all system calls are
allowed except for mknod, which will simply do nothing and
return 0 (success), looks like:
-->
Expand All @@ -2688,7 +2688,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>

<programlisting>
2
blacklist
denylist
mknod errno 0
ioctl notify
</programlisting>
Expand Down
16 changes: 8 additions & 8 deletions doc/ko/lxc.container.conf.sgml.in
Expand Up @@ -1736,33 +1736,33 @@ proc proc proc nodev,noexec,nosuid 0 0
<para>
<!--
Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is whitelisted,
while every unlisted number is blacklisted for use in the container
policy is a simple allowlist. The second line therefore must
read "allowlist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is allowlisted,
while every unlisted number is denylisted for use in the container
-->
현재는 버전1과 2만 지원된다. 버전 1에서는 정책은 단순한 화이트리스트이다. 그러므로 두번째 라인은 반드시 "whitelist"여야 한다. 파일의 나머지 내용은 한 줄에 하나의 시스템콜 번호로 채워진다. 화이트리스트에 없는 번호는 컨테이너에서 블랙리스트로 들어간다.
현재는 버전1과 2만 지원된다. 버전 1에서는 정책은 단순한 화이트리스트이다. 그러므로 두번째 라인은 반드시 "allowlist"여야 한다. 파일의 나머지 내용은 한 줄에 하나의 시스템콜 번호로 채워진다. 화이트리스트에 없는 번호는 컨테이너에서 블랙리스트로 들어간다.
</para>

<para>
<!--
In version 2, the policy may be blacklist or whitelist,
In version 2, the policy may be denylist or allowlist,
supports per-rule and per-policy default actions, and supports
per-architecture system call resolution from textual names.
-->
버전 2에서는 폴리시는 블랙리스트 또는 화이트리스트가 될 수 있다. 그리고 각 규칙와 각 정책의 기본 동작, 아키텍쳐별 시스템콜 설정, 텍스트로된 이름을 지원한다.
</para>
<para>
<!--
An example blacklist policy, in which all system calls are
An example denylist policy, in which all system calls are
allowed except for mknod, which will simply do nothing and
return 0 (success), looks like:
-->
아래는 블랙리스트 정책 예제이다. 아래 정책에서는 mknod를 제외한 모든 시스템콜이 허용된다. mknod시에는 아무것도 수행하지 않고 0(성공)을 반환한다.
</para>
<screen>
2
blacklist
denylist
mknod errno 0
</screen>
<variablelist>
Expand Down
16 changes: 8 additions & 8 deletions doc/lxc.container.conf.sgml.in
Expand Up @@ -1676,7 +1676,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
standard namespace identifiers as seen in the
<filename>/proc/PID/ns</filename> directory.
The <option>lxc.namespace.keep</option> is a
blacklist option, i.e. it is useful when enforcing that containers
denylist option, i.e. it is useful when enforcing that containers
must keep a specific set of namespaces.
</para>

Expand Down Expand Up @@ -1984,26 +1984,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</para>
<para>
Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is whitelisted,
while every unlisted number is blacklisted for use in the container
policy is a simple allowlist. The second line therefore must
read "allowlist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is allowlisted,
while every unlisted number is denylisted for use in the container
</para>

<para>
In version 2, the policy may be blacklist or whitelist,
In version 2, the policy may be denylist or allowlist,
supports per-rule and per-policy default actions, and supports
per-architecture system call resolution from textual names.
</para>
<para>
An example blacklist policy, in which all system calls are
An example denylist policy, in which all system calls are
allowed except for mknod, which will simply do nothing and
return 0 (success), looks like:
</para>

<programlisting>
2
blacklist
denylist
mknod errno 0
ioctl notify
</programlisting>
Expand Down
2 changes: 1 addition & 1 deletion src/lxc/cgroups/cgroup2_devices.c
Expand Up @@ -174,7 +174,7 @@ struct bpf_program *bpf_program_new(uint32_t prog_type)
prog->prog_type = prog_type;
prog->kernel_fd = -EBADF;
/*
* By default a whitelist is used unless the user tells us otherwise.
* By default a allowlist is used unless the user tells us otherwise.
*/
prog->device_list_type = LXC_BPF_DEVICE_CGROUP_ALLOWLIST;

Expand Down
45 changes: 32 additions & 13 deletions src/lxc/seccomp.c
Expand Up @@ -99,7 +99,7 @@ static uint32_t get_v2_default_action(char *line)
while (*line == ' ')
line++;

/* After 'whitelist' or 'blacklist' comes default behavior. */
/* After 'allowlist' or 'denylist' comes default behavior. */
if (strncmp(line, "kill", 4) == 0) {
ret_action = SCMP_ACT_KILL;
} else if (strncmp(line, "errno", 5) == 0) {
Expand Down Expand Up @@ -561,6 +561,27 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
return true;
}

/*
* It is unfortunate, but we can't simply remove those terms since this would
* break way too many users.
*/
#define BACKWARDCOMPAT_TERMINOLOGY_DENYLIST "blacklist"
#define BACKWARDCOMPAT_TERMINOLOGY_ALLOWLIST "whitelist"

static inline bool is_denylist(const char *type)
{
return strnequal(type, "denylist", STRLITERALLEN("denylist")) ||
strnequal(type, BACKWARDCOMPAT_TERMINOLOGY_DENYLIST,
STRLITERALLEN(BACKWARDCOMPAT_TERMINOLOGY_DENYLIST));
}

static inline bool is_allowlist(const char *type)
{
return strnequal(type, "allowlist", STRLITERALLEN("allowlist")) ||
strnequal(type, BACKWARDCOMPAT_TERMINOLOGY_ALLOWLIST,
STRLITERALLEN(BACKWARDCOMPAT_TERMINOLOGY_ALLOWLIST));
}

/*
* v2 consists of
* [x86]
Expand All @@ -580,7 +601,7 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
int ret;
char *p;
enum lxc_hostarch_t cur_rule_arch, native_arch;
bool blacklist = false;
bool denylist = false;
uint32_t default_policy_action = -1, default_rule_action = -1;
struct seccomp_v2_rule rule;
struct scmp_ctx_info {
Expand All @@ -589,12 +610,10 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
bool needs_merge[3];
} ctx;

if (strncmp(line, "blacklist", 9) == 0)
blacklist = true;
else if (strncmp(line, "whitelist", 9) != 0) {
ERROR("Bad seccomp policy style \"%s\"", line);
return -1;
}
if (is_denylist(line))
denylist = true;
else if (!is_allowlist(line))
return log_error(-EINVAL, "Bad seccomp policy style \"%s\"", line);

p = strchr(line, ' ');
if (p) {
Expand All @@ -603,8 +622,8 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
return -1;
}

/* for blacklist, allow any syscall which has no rule */
if (blacklist) {
/* for denylist, allow any syscall which has no rule */
if (denylist) {
if (default_policy_action == -1)
default_policy_action = SCMP_ACT_ALLOW;

Expand Down Expand Up @@ -1079,7 +1098,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
* the second line has some directives
* then comes policy subject to the directives
* right now version must be '1' or '2'
* the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
* the directives must include 'allowlist'(version == 1 or 2) or 'denylist'
* (version == 2) and can include 'debug' (though debug is not yet supported).
*/
static int parse_config(FILE *f, struct lxc_conf *conf)
Expand All @@ -1099,8 +1118,8 @@ static int parse_config(FILE *f, struct lxc_conf *conf)
goto bad_line;
}

if (version == 1 && !strstr(line, "whitelist")) {
ERROR("Only whitelist policy is supported");
if (version == 1 && !strstr(line, "allowlist")) {
ERROR("Only allowlist policy is supported");
goto bad_line;
}

Expand Down
10 changes: 10 additions & 0 deletions src/lxc/string_utils.h
Expand Up @@ -118,4 +118,14 @@ static inline ssize_t safe_strlcat(char *src, const char *append, size_t len)
return (ssize_t)new_len;
}

static inline bool strnequal(const char *str, const char *eq, size_t len)
{
return strncmp(str, eq, len) == 0;
}

static inline bool strequal(const char *str, const char *eq)
{
return strcmp(str, eq) == 0;
}

#endif /* __LXC_STRING_UTILS_H */

0 comments on commit 4bc5137

Please sign in to comment.