seccomp: support allowlist/denylist in profiles

parent 59410099
...@@ -17,7 +17,7 @@ lxc.hook.clone = @LXCHOOKDIR@/clonehostname ...@@ -17,7 +17,7 @@ lxc.hook.clone = @LXCHOOKDIR@/clonehostname
# Default legacy cgroup configuration # Default legacy cgroup configuration
# #
# CGroup whitelist # CGroup allowlist
lxc.cgroup.devices.deny = a lxc.cgroup.devices.deny = a
## Allow any mknod (but not reading/writing the node) ## Allow any mknod (but not reading/writing the node)
lxc.cgroup.devices.allow = c *:* m lxc.cgroup.devices.allow = c *:* m
...@@ -46,7 +46,7 @@ lxc.cgroup.devices.allow = c 10:229 rwm ...@@ -46,7 +46,7 @@ lxc.cgroup.devices.allow = c 10:229 rwm
# Default unified cgroup configuration # Default unified cgroup configuration
# #
# CGroup whitelist # CGroup allowlist
lxc.cgroup2.devices.deny = a lxc.cgroup2.devices.deny = a
## Allow any mknod (but not reading/writing the node) ## Allow any mknod (but not reading/writing the node)
lxc.cgroup2.devices.allow = c *:* m lxc.cgroup2.devices.allow = c *:* m
......
2 2
blacklist denylist
reject_force_umount # comment this to allow umount -f; not recommended reject_force_umount # comment this to allow umount -f; not recommended
[all] [all]
kexec_load errno 1 kexec_load errno 1
......
...@@ -10,7 +10,7 @@ pkgexamples_DATA = \ ...@@ -10,7 +10,7 @@ pkgexamples_DATA = \
lxc-veth.conf \ lxc-veth.conf \
lxc-complex.conf \ lxc-complex.conf \
seccomp-v1.conf \ seccomp-v1.conf \
seccomp-v2-blacklist.conf \ seccomp-v2-denylist.conf \
seccomp-v2.conf seccomp-v2.conf
endif endif
...@@ -23,10 +23,10 @@ noinst_DATA = \ ...@@ -23,10 +23,10 @@ noinst_DATA = \
lxc-veth.conf.in \ lxc-veth.conf.in \
lxc-complex.conf.in \ lxc-complex.conf.in \
seccomp-v1.conf \ seccomp-v1.conf \
seccomp-v2-blacklist.conf \ seccomp-v2-denylist.conf \
seccomp-v2.conf seccomp-v2.conf
EXTRA_DIST = \ EXTRA_DIST = \
seccomp-v1.conf \ seccomp-v1.conf \
seccomp-v2-blacklist.conf \ seccomp-v2-denylist.conf \
seccomp-v2.conf seccomp-v2.conf
1 1
whitelist allowlist
0 0
1 1
2 2
......
2 2
blacklist denylist
# v2 allows comments after the second line, with '#' in first column, # 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 # 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 # simply be killed when it tried to mknod. 'errno 0' means do not allow
# the container to mknod, but immediately return 0. # the container to mknod, but immediately return 0.
......
2 2
whitelist trap allowlist trap
# 'whitelist' would normally mean kill a task doing any syscall which is not # 'allowlist' 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 # 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 # 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. # call but immediately return 0. 'errno 22' would mean return EINVAL immediately.
[x86_64] [x86_64]
...@@ -20,5 +20,5 @@ read ...@@ -20,5 +20,5 @@ read
write write
mount mount
umount2 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. # system container to boot.
...@@ -2239,7 +2239,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp> ...@@ -2239,7 +2239,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
standard namespace identifiers as seen in the standard namespace identifiers as seen in the
<filename>/proc/PID/ns</filename> directory. <filename>/proc/PID/ns</filename> directory.
The <option>lxc.namespace.keep</option> is a 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. must keep a specific set of namespaces.
--> -->
コンテナが、作成元のプロセスから継承する (新しい名前空間を作らずに元のプロセスの名前空間のまま実行する) 名前空間を指定します。継承する名前空間はスペース区切りのリストで指定します。指定する名前空間名は、<filename>/proc/PID/ns</filename> ディレクトリ内に存在する標準の名前空間指示子でなければなりません。<option>lxc.namespace.keep</option> はブラックリストを指定するオプションです。つまり、コンテナに特定の名前空間を使い続けることを強制したい場合に便利です。 コンテナが、作成元のプロセスから継承する (新しい名前空間を作らずに元のプロセスの名前空間のまま実行する) 名前空間を指定します。継承する名前空間はスペース区切りのリストで指定します。指定する名前空間名は、<filename>/proc/PID/ns</filename> ディレクトリ内に存在する標準の名前空間指示子でなければなりません。<option>lxc.namespace.keep</option> はブラックリストを指定するオプションです。つまり、コンテナに特定の名前空間を使い続けることを強制したい場合に便利です。
...@@ -2660,18 +2660,18 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp> ...@@ -2660,18 +2660,18 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
<para> <para>
<!-- <!--
Versions 1 and 2 are currently supported. In version 1, the Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must policy is a simple allowlist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric) read "allowlist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is whitelisted, syscall number per line. Each syscall number is allowlisted,
while every unlisted number is blacklisted for use in the container while every unlisted number is denylisted for use in the container
--> -->
現時点では、バージョン番号は 1 と 2 をサポートしています。バージョン 1 では、ポリシーはシンプルなホワイトリストですので、2 行目は "whitelist" でなければなりません。 現時点では、バージョン番号は 1 と 2 をサポートしています。バージョン 1 では、ポリシーはシンプルなホワイトリストですので、2 行目は "allowlist" でなければなりません。
そして残りの行には 1 行に 1 つずつ、システムコール番号を書きます。各行のシステムコール番号がホワイトリスト化され、リストにない番号は、そのコンテナではブラックリストに入ります。 そして残りの行には 1 行に 1 つずつ、システムコール番号を書きます。各行のシステムコール番号がホワイトリスト化され、リストにない番号は、そのコンテナではブラックリストに入ります。
</para> </para>
<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 supports per-rule and per-policy default actions, and supports
per-architecture system call resolution from textual names. per-architecture system call resolution from textual names.
--> -->
...@@ -2679,7 +2679,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp> ...@@ -2679,7 +2679,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
</para> </para>
<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 allowed except for mknod, which will simply do nothing and
return 0 (success), looks like: return 0 (success), looks like:
--> -->
...@@ -2688,7 +2688,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp> ...@@ -2688,7 +2688,7 @@ by KATOH Yasufumi <karma at jazz.email.ne.jp>
<programlisting> <programlisting>
2 2
blacklist denylist
mknod errno 0 mknod errno 0
ioctl notify ioctl notify
</programlisting> </programlisting>
......
...@@ -1736,17 +1736,17 @@ proc proc proc nodev,noexec,nosuid 0 0 ...@@ -1736,17 +1736,17 @@ proc proc proc nodev,noexec,nosuid 0 0
<para> <para>
<!-- <!--
Versions 1 and 2 are currently supported. In version 1, the Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must policy is a simple allowlist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric) read "allowlist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is whitelisted, syscall number per line. Each syscall number is allowlisted,
while every unlisted number is blacklisted for use in the container while every unlisted number is denylisted for use in the container
--> -->
현재는 버전1과 2만 지원된다. 버전 1에서는 정책은 단순한 화이트리스트이다. 그러므로 두번째 라인은 반드시 "whitelist"여야 한다. 파일의 나머지 내용은 한 줄에 하나의 시스템콜 번호로 채워진다. 화이트리스트에 없는 번호는 컨테이너에서 블랙리스트로 들어간다. 현재는 버전1과 2만 지원된다. 버전 1에서는 정책은 단순한 화이트리스트이다. 그러므로 두번째 라인은 반드시 "allowlist"여야 한다. 파일의 나머지 내용은 한 줄에 하나의 시스템콜 번호로 채워진다. 화이트리스트에 없는 번호는 컨테이너에서 블랙리스트로 들어간다.
</para> </para>
<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 supports per-rule and per-policy default actions, and supports
per-architecture system call resolution from textual names. per-architecture system call resolution from textual names.
--> -->
...@@ -1754,7 +1754,7 @@ proc proc proc nodev,noexec,nosuid 0 0 ...@@ -1754,7 +1754,7 @@ proc proc proc nodev,noexec,nosuid 0 0
</para> </para>
<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 allowed except for mknod, which will simply do nothing and
return 0 (success), looks like: return 0 (success), looks like:
--> -->
...@@ -1762,7 +1762,7 @@ proc proc proc nodev,noexec,nosuid 0 0 ...@@ -1762,7 +1762,7 @@ proc proc proc nodev,noexec,nosuid 0 0
</para> </para>
<screen> <screen>
2 2
blacklist denylist
mknod errno 0 mknod errno 0
</screen> </screen>
<variablelist> <variablelist>
......
...@@ -1676,7 +1676,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -1676,7 +1676,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
standard namespace identifiers as seen in the standard namespace identifiers as seen in the
<filename>/proc/PID/ns</filename> directory. <filename>/proc/PID/ns</filename> directory.
The <option>lxc.namespace.keep</option> is a 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. must keep a specific set of namespaces.
</para> </para>
...@@ -1984,26 +1984,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -1984,26 +1984,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</para> </para>
<para> <para>
Versions 1 and 2 are currently supported. In version 1, the Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must policy is a simple allowlist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric) read "allowlist", with the rest of the file containing one (numeric)
syscall number per line. Each syscall number is whitelisted, syscall number per line. Each syscall number is allowlisted,
while every unlisted number is blacklisted for use in the container while every unlisted number is denylisted for use in the container
</para> </para>
<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 supports per-rule and per-policy default actions, and supports
per-architecture system call resolution from textual names. per-architecture system call resolution from textual names.
</para> </para>
<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 allowed except for mknod, which will simply do nothing and
return 0 (success), looks like: return 0 (success), looks like:
</para> </para>
<programlisting> <programlisting>
2 2
blacklist denylist
mknod errno 0 mknod errno 0
ioctl notify ioctl notify
</programlisting> </programlisting>
......
...@@ -174,7 +174,7 @@ struct bpf_program *bpf_program_new(uint32_t prog_type) ...@@ -174,7 +174,7 @@ struct bpf_program *bpf_program_new(uint32_t prog_type)
prog->prog_type = prog_type; prog->prog_type = prog_type;
prog->kernel_fd = -EBADF; 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; prog->device_list_type = LXC_BPF_DEVICE_CGROUP_ALLOWLIST;
......
...@@ -99,7 +99,7 @@ static uint32_t get_v2_default_action(char *line) ...@@ -99,7 +99,7 @@ static uint32_t get_v2_default_action(char *line)
while (*line == ' ') while (*line == ' ')
line++; line++;
/* After 'whitelist' or 'blacklist' comes default behavior. */ /* After 'allowlist' or 'denylist' comes default behavior. */
if (strncmp(line, "kill", 4) == 0) { if (strncmp(line, "kill", 4) == 0) {
ret_action = SCMP_ACT_KILL; ret_action = SCMP_ACT_KILL;
} else if (strncmp(line, "errno", 5) == 0) { } else if (strncmp(line, "errno", 5) == 0) {
...@@ -562,6 +562,27 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, ...@@ -562,6 +562,27 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
} }
/* /*
* 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 * v2 consists of
* [x86] * [x86]
* open * open
...@@ -580,7 +601,7 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c ...@@ -580,7 +601,7 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
int ret; int ret;
char *p; char *p;
enum lxc_hostarch_t cur_rule_arch, native_arch; 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; uint32_t default_policy_action = -1, default_rule_action = -1;
struct seccomp_v2_rule rule; struct seccomp_v2_rule rule;
struct scmp_ctx_info { struct scmp_ctx_info {
...@@ -589,12 +610,10 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c ...@@ -589,12 +610,10 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
bool needs_merge[3]; bool needs_merge[3];
} ctx; } ctx;
if (strncmp(line, "blacklist", 9) == 0) if (is_denylist(line))
blacklist = true; denylist = true;
else if (strncmp(line, "whitelist", 9) != 0) { else if (!is_allowlist(line))
ERROR("Bad seccomp policy style \"%s\"", line); return log_error(-EINVAL, "Bad seccomp policy style \"%s\"", line);
return -1;
}
p = strchr(line, ' '); p = strchr(line, ' ');
if (p) { if (p) {
...@@ -603,8 +622,8 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c ...@@ -603,8 +622,8 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
return -1; return -1;
} }
/* for blacklist, allow any syscall which has no rule */ /* for denylist, allow any syscall which has no rule */
if (blacklist) { if (denylist) {
if (default_policy_action == -1) if (default_policy_action == -1)
default_policy_action = SCMP_ACT_ALLOW; default_policy_action = SCMP_ACT_ALLOW;
...@@ -1079,7 +1098,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) ...@@ -1079,7 +1098,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
* the second line has some directives * the second line has some directives
* then comes policy subject to the directives * then comes policy subject to the directives
* right now version must be '1' or '2' * 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). * (version == 2) and can include 'debug' (though debug is not yet supported).
*/ */
static int parse_config(FILE *f, struct lxc_conf *conf) static int parse_config(FILE *f, struct lxc_conf *conf)
...@@ -1099,8 +1118,8 @@ static int parse_config(FILE *f, struct lxc_conf *conf) ...@@ -1099,8 +1118,8 @@ static int parse_config(FILE *f, struct lxc_conf *conf)
goto bad_line; goto bad_line;
} }
if (version == 1 && !strstr(line, "whitelist")) { if (version == 1 && !strstr(line, "allowlist")) {
ERROR("Only whitelist policy is supported"); ERROR("Only allowlist policy is supported");
goto bad_line; goto bad_line;
} }
......
...@@ -118,4 +118,14 @@ static inline ssize_t safe_strlcat(char *src, const char *append, size_t len) ...@@ -118,4 +118,14 @@ static inline ssize_t safe_strlcat(char *src, const char *append, size_t len)
return (ssize_t)new_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 */ #endif /* __LXC_STRING_UTILS_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment