diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index fcc620b007..9469fdf52e 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install dependencies run: | diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 6bccb6ffbb..45af834105 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'lxc/lxc' steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Download Coverity Build Tool run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9fb0805066..061b85f06a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install dependencies run: | @@ -64,7 +64,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install dependencies run: | diff --git a/config/init/common/lxc-net.in b/config/init/common/lxc-net.in index 2e0958028a..5e2083832e 100755 --- a/config/init/common/lxc-net.in +++ b/config/init/common/lxc-net.in @@ -10,6 +10,7 @@ varlib="@LOCALSTATEDIR@/lib" USE_LXC_BRIDGE="true" LXC_BRIDGE="lxcbr0" LXC_BRIDGE_MAC="10:66:6a:00:00:00" +LXC_BRIDGE_MTU="1500" LXC_ADDR="10.0.3.1" LXC_NETMASK="255.255.255.0" LXC_NETWORK="10.0.3.0/24" @@ -59,6 +60,7 @@ _ifup() { CIDR_ADDR="${LXC_ADDR}/${MASK}" ip addr add ${CIDR_ADDR} broadcast + dev ${LXC_BRIDGE} ip link set dev ${LXC_BRIDGE} address $LXC_BRIDGE_MAC + ip link set dev ${LXC_BRIDGE} mtu ${LXC_BRIDGE_MTU:-1500} ip link set dev ${LXC_BRIDGE} up } diff --git a/doc/ja/lxc.container.conf.sgml.in b/doc/ja/lxc.container.conf.sgml.in index 9e04085d30..40b5d5dee9 100644 --- a/doc/ja/lxc.container.conf.sgml.in +++ b/doc/ja/lxc.container.conf.sgml.in @@ -2069,27 +2069,20 @@ explanation of the differences between the two versions. --> カーネルにおける cgroup 実装は長年にわたって大きく変化してきました。 - Linux 4.5 で新しい cgroup ファイルシステムのサポートが追加されました。通常は "cgroup2" や "unified hierarchy"(単一階層構造) と呼ばれています。 - それ以来、通常は古い cgroup ファイルシステムは "cgroup1" や "legacy hierarchies"(レガシー階層構造)と呼ばれています。 + Linux 4.5 で新しい cgroup ファイルシステムのサポートが追加されました。通常は "cgroup v2" や "unified hierarchy"(単一階層構造) と呼ばれています。 + それ以来、通常は古い cgroup ファイルシステムは "cgroup v1" や "legacy hierarchies"(レガシー階層構造)と呼ばれています。 この 2 つのバージョンの違いについての詳細な説明は、cgroup のマニュアルページをご覧ください。 - LXC は cgroup1(レガシー階層構造)と cgroup2(単一階層構造)に対する設定を、異なる設定プレフィックスを使って区別しています。 - cgroup1 に対する設定を変更するには というプレフィックスを使う必要があり、cgroup2 の設定を変更するには を使う必要があります。 - LXC は、cgroup2 だけが使われているシステム上の を無視します。逆に cgroup1 だけが使われているシステム上の を無視します。 + Since LXC 7.0, only the unified cgroup hierarchy (cgroup v2) is + supported. To alter settings for controllers in the unified hierarchy, + the key prefix must be used. + The key prefix, which was used for + legacy and hybrid hierarchy configurations, is no longer supported. + --> + LXC 7.0 以降、cgroup v2(単一階層構造)のみがサポートされています。cgroup v2 のコントローラーの設定を変更するには、 というプレフィックスを使う必要があります。cgroup v1(レガシー階層構造)や v1 と v2 のハイブリッドな構成で使われていた というプレフィックスはサポートされなくなりました。 @@ -2108,67 +2101,44 @@ cgroup 階層の本質は、プロセスを階層的に構造化する方法です。通常は、cgroup 階層では 1 つ以上の「コントローラー」が有効になっています。 通常、cgroup 階層の「コントローラー」は階層に従って特定のタイプのシステムリソースを分配する役割を果たします。 コントローラーには "pids" コントローラー、"cpu" コントローラー、"memory" コントローラーなどがあります。 - しかし、システムリソースの分配するという役割に該当しないコントローラーもあります。このようなコントローラーは「ユーティリティー」コントローラーと呼ばれたりします。 + しかし、システムリソースを分配するという役割に該当しないコントローラーもあります。このようなコントローラーは「ユーティリティー」コントローラーと呼ばれたりします。 ユーティリティーコントローラーの 1 つにデバイスコントローラーがあります。このコントローラーはシステムリソースを分配する代わりにデバイスへのアクセスを管理できます。 - cgroup1 では、デバイスコントローラーは他の多くのコントローラーと同様に、書き込みできるファイルのセットとして実装されていました。 - これらのファイルは "devices.allow" と "devices.deny" という名前のファイルでした。レガシーデバイスコントローラーは「許可リスト(allowlists)」と「拒否リスト(denylists)」の両方を実装できました。 + LXC supports both "allowlist" and "denylist" semantics for device + access control. An allowlist blocks access to all devices by default, + and allow rules must be specified for particular devices or device + classes. A denylist allows access to all devices by default, and "deny + rules" must be specified to restrict access to particular devices or + device classes. + --> + LXC は、デバイスアクセスコントロールにおいて、「許可リスト(allowlist)」と「拒否リスト(denylist)」の両方をサポートしています。許可リストは、デフォルトですべてのデバイスへのアクセスをブロックし、特定のデバイスまたはデバイスクラスに対して「許可ルール(allow rules)」を指定する必要があります。拒否リストは、デフォルトですべてのデバイスへのアクセスを許可し、特定のデバイスまたはデバイスクラスへのアクセスを拒否するには「拒否ルール(deny rules)」を指定する必要があります。 - 許可リスト(allowlist)とは、すべてのデバイスへのアクセスをブロックするデバイスプログラムです。特定のデバイスへのアクセスを行うには、特定のデバイスもしくはデバイスクラスに対する「許可ルール(allow rules)」を指定する必要があります。 - 一方、拒否リスト(denylist)はデフォルトですべてのデバイスへのアクセスを許可するデバイスプログラムです。特定のデバイスへのアクセスを拒否するには、特定のデバイスもしくはデバイスクラスに対する「拒否ルール(deny rules)」を指定する必要があります。 + cgroup v2 では、デバイスコントローラーは、以前使用されていたファイルベースのインターフェースではなく、cgroup にアタッチされたタイプ の eBPF プログラムを介して実装されています。LXC は、この eBPF ベースのデバイスコントローラーで、v1 のときと同じ許可リスト・拒否リストのセマンティクスを保持します。このあとの段落では、cgroup v2 の eBPF デバイスコントローラーに対するセマンティクスを説明します。 - cgroup2 では、デバイスコントローラーの実装が完全に変わりました。読み書きするファイルの代わりに、 の eBPF プログラムを cgroup にアタッチできます。 - カーネルの実装が完全に変わったのにもかかわらず、LXC は cgroup1 のデバイスコントローラーと cgroup2 の eBPF ベースのデバイスコントローラーで同じセマンティクスに従えるようにしています。 - このあとの段落では、cgroup2 の eBPF デバイスコントローラーに対するセマンティクスを説明します。 + cgroup v2 の eBPF ベースのデバイスコントローラーのデバイスルールは、 を使って指定します。 - - - 先に述べたように、cgroup2 の eBPF ベースのデバイスコントローラーに対するデバイスルールを指定するフォーマットは、cgroup1 のデバイスコントローラーと同じです。ただし、設定キーのプレフィックスは変更されています。 - 具体的には、cgroup1 のデバイスコントローラーに対するデバイスルールは を使って指定します。一方、cgroup2 の eBPF ベースのコントローラーでは を使わなければなりません。 - @@ -2376,22 +2346,16 @@ - - コンテナの cgroup を作成するパスやディレクトリを指定します。 - 例えば、"c1" という名前のコンテナで のように設定すると、"my-cgroup" のサブ cgroup のようにコンテナの cgroup を作成します。 - 例えば、ユーザのカレントの cgroup である "my-user" が cgroup v1 階層にある cpuset コントローラの root cgroup 内に存在する場合、この設定は "/sys/fs/cgroup/cpuset/my-user/my-cgroup/first/c1" という cgroup をこのコンテナ向けに作成します。 - 存在しない cgroup は LXC が作成しますが、ユーザがカレントの cgroup に書き込み権を持っていることが前提となります。 + named "c1", if the user's current cgroup is "my-user", will + create the container's cgroups under "my-user/my-cgroup/first". + Any missing cgroups will be created by LXC. This presupposes + that the user has write access to its current cgroup. + --> + コンテナの cgroup を作成するパスやディレクトリを指定します。例えば、"c1" という名前のコンテナで のように設定すると、ユーザのカレント cgroup が "my-user" の場合、コンテナの cgroup は "my-user/my-cgroup/first" の下に作成されます。存在しない cgroup は LXC が作成しますが、ユーザーがカレントの cgroup に書き込み権を持っていることが前提となります。 @@ -4139,11 +4103,11 @@ devices.allow は、特定のデバイスを使用可能にします。 - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw @@ -4177,11 +4141,11 @@ lxc.net.2.hwaddr = 4a:49:43:49:79:ff lxc.net.2.ipv4.address = 10.2.3.6/24 lxc.net.2.ipv6.address = 2003:db8:1:0:214:1234:fe0b:3297 - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw lxc.mount.fstab = /etc/fstab.complex lxc.mount.entry = /lib /root/myrootfs/lib none ro,bind 0 0 lxc.rootfs.path = dir:/mnt/rootfs.complex diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index 8ba375df9c..b0eca005f8 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -1546,17 +1546,11 @@ - LXC distinguishes settings for the legacy and the unified hierarchy by - using different configuration key prefixes. To alter settings for - controllers in a legacy hierarchy the key prefix - must be used and in order to alter the - settings for a controller in the unified hierarchy the - key must be used. Note that LXC will - ignore settings on systems that only use - the unified hierarchy. Conversely, it will ignore - options on systems that only use legacy - hierarchies. (legacy and hybrid hierarchy) - support is dropped. + Since LXC 7.0, only the unified cgroup hierarchy (cgroup v2) is + supported. To alter settings for controllers in the unified hierarchy, + the key prefix must be used. + The key prefix, which was used for + legacy and hybrid hierarchy configurations, is no longer supported. @@ -1573,45 +1567,30 @@ - In the legacy hierarchy the device controller was implemented like most - other controllers as a set of files that could be written to. These - files where named "devices.allow" and "devices.deny". The legacy device - controller allowed the implementation of both "allowlists" and - "denylists". + LXC supports both "allowlist" and "denylist" semantics for device + access control. An allowlist blocks access to all devices by default, + and "allow rules" must be specified for particular devices or device + classes. A denylist allows access to all devices by default, and "deny + rules" must be specified to restrict access to particular devices or + device classes. - An allowlist is a device program that by default blocks access to all - devices. In order to access specific devices "allow rules" for - particular devices or device classes must be specified. In contrast, a - denylist is a device program that by default allows access to all - devices. In order to restrict access to specific devices "deny rules" - for particular devices or device classes must be specified. + In the unified cgroup hierarchy, the device controller is implemented + via an eBPF program of type + attached to a cgroup, + rather than the file-based interface used previously. LXC preserves + the same allowlist/denylist semantics in this eBPF-based device + controller. The following paragraphs explain these semantics in + detail. - In the unified cgroup hierarchy the implementation of the device - controller has completely changed. Instead of files to read from and - write to a eBPF program of - can be attached to a - cgroup. Even though the kernel implementation has changed completely - LXC tries to allow for the same semantics to be followed in the legacy - device cgroup and the unified eBPF-based device controller. The - following paragraphs explain the semantics for the unified eBPF-based - device controller. + Device rules for the cgroup2 eBPF-based device controller are + specified via and + . - - As mentioned the format for specifying device rules for the unified - eBPF-based device controller is the same as for the legacy cgroup - device controller; only the configuration key prefix has changed. - Specifically, device rules for the legacy cgroup device controller are - specified via and - whereas for the - cgroup2 eBPF-based device controller - and - must be used. - @@ -1722,21 +1701,6 @@ switch from an allowlist program to a denylist program. - - - - - - - Specify the control group value to be set on a legacy cgroup - hierarchy. The controller name is the literal name of the control - group. The permitted names and the syntax of their values is not - dictated by LXC, instead it depends on the features of the Linux - kernel running at the time the container is started, eg. - - - - @@ -1758,16 +1722,13 @@ - specify a directory or path in which the container's cgroup will + Specify a directory or path in which the container's cgroup will be created. For example, setting for a container - named "c1" will create the container's cgroup as a sub-cgroup of - "my-cgroup". For example, if the user's current cgroup "my-user" - is located in the root cgroup of the cpuset controller in a - cgroup v1 hierarchy this would create the cgroup - "/sys/fs/cgroup/cpuset/my-user/my-cgroup/first/c1" for the - container. Any missing cgroups will be created by LXC. This - presupposes that the user has write access to its current cgroup. + named "c1", if the user's current cgroup is "my-user", will + create the container's cgroups under "my-user/my-cgroup/first". + Any missing cgroups will be created by LXC. This presupposes + that the user has write access to its current cgroup. @@ -3093,11 +3054,11 @@ cpus.share prioritize the control group, devices.allow makes usable the specified devices. - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw @@ -3128,11 +3089,11 @@ lxc.net.2.hwaddr = 4a:49:43:49:79:ff lxc.net.2.ipv4.address = 10.2.3.6/24 lxc.net.2.ipv6.address = 2003:db8:1:0:214:1234:fe0b:3297 - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw lxc.mount.fstab = /etc/fstab.complex lxc.mount.entry = /lib /root/myrootfs/lib none ro,bind 0 0 lxc.rootfs.path = dir:/mnt/rootfs.complex diff --git a/src/lxc/attach.c b/src/lxc/attach.c index f22f83f0df..55f748e9ab 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -1368,8 +1368,21 @@ __noreturn static void do_attach(struct attach_payload *ap) lxc_seccomp_close_notifier_fd(&conf->seccomp); } - if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) - goto on_error; + if (conf->nonroot_keepcaps) { + ret = lxc_set_keepcaps(); + if (ret < 0) + goto on_error; + + if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) + goto on_error; + + ret = lxc_bounding_as_ambient_caps(); + if (ret < 0) + goto on_error; + } else { + if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) + goto on_error; + } put_attach_payload(ap); diff --git a/src/lxc/caps.c b/src/lxc/caps.c index f6c5770ed3..df3a3da5c1 100644 --- a/src/lxc/caps.c +++ b/src/lxc/caps.c @@ -323,4 +323,46 @@ bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag) return lxc_cap_is_set(caps, cap, flag); } + +int lxc_bounding_as_ambient_caps(void) +{ + call_cleaner(cap_free) cap_t caps = NULL; + int ret; + cap_value_t cap; + + caps = cap_get_proc(); + if (!caps) + return log_error_errno(-1, errno, "Failed to retrieve capabilities"); + + for (cap = 0; cap <= CAP_LAST_CAP; cap++) { + if (cap_get_bound(cap) <= 0) + continue; + + ret = cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_SET); + if (ret < 0) { + return log_error_errno(ret, errno, "Failed to set cap %d as permitted", cap); + } + ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_SET); + if (ret < 0) { + return log_error_errno(ret, errno, "Failed to set cap %d as inheritable", cap); + } + + ret = cap_set_proc(caps); + if (ret < 0) + return log_error_errno(ret, errno, "Failed to set capabilities"); + + cap_set_ambient(cap, CAP_SET); + } + + return 0; +} + +int lxc_set_keepcaps(void) { + int ret = prctl(PR_SET_KEEPCAPS, prctl_arg(1)); + if (ret < 0) + return log_error_errno(ret, errno, "Failed to set PR_SET_KEEPCAPS"); + + return ret; +} + #endif diff --git a/src/lxc/caps.h b/src/lxc/caps.h index fbec1fdb54..13f6ea71ee 100644 --- a/src/lxc/caps.h +++ b/src/lxc/caps.h @@ -21,6 +21,8 @@ __hidden extern int lxc_caps_init(void); __hidden extern int lxc_caps_last_cap(__u32 *cap); __hidden extern bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag); __hidden extern bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag); +__hidden extern int lxc_bounding_as_ambient_caps(void); +__hidden extern int lxc_set_keepcaps(void); #else static inline int lxc_caps_down(void) { @@ -64,6 +66,17 @@ static inline bool lxc_file_cap_is_set(const char *path, cap_value_t cap, { return false; } + +static inline int lxc_bounding_as_ambiant_caps(void) +{ + return 0; +} + +static inline int lxc_set_keepcaps(void) +{ + return 0; +} + #endif #define lxc_priv(__lxc_function) \ diff --git a/src/lxc/commands.c b/src/lxc/commands.c index 8c6460cdcc..b6d36bdf58 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -1028,8 +1028,19 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req, int cilen; struct lxc_config_t *item; struct lxc_cmd_rsp rsp; + ssize_t ret; memset(&rsp, 0, sizeof(rsp)); + + if (req->datalen <= 0) { + rsp.ret = -EINVAL; + return lxc_cmd_rsp_send_reap(fd, &rsp); + } + + ret = validate_string_request(fd, req); + if (ret != 0) + return ret; + item = lxc_get_config(req->data); cilen = item->get(req->data, NULL, 0, handler->conf, NULL); if (cilen <= 0) @@ -1554,6 +1565,12 @@ static int lxc_cmd_console_log_callback(int fd, struct lxc_cmd_req *req, rsp.ret = -EFAULT; rsp.datalen = 0; rsp.data = NULL; + + if (req->datalen != sizeof(struct lxc_cmd_console_log) || !req->data) { + rsp.ret = -EINVAL; + goto out; + } + if (buffer_size <= 0) goto out; diff --git a/src/lxc/conf.h b/src/lxc/conf.h index ea4e199404..cf1c9aa4f2 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -534,6 +534,10 @@ struct lxc_conf { /* The groups to use for the container. */ lxc_groups_t init_groups; + /* Defines whether a privileged container with a nonroot user (init_uid != 0) + * will keep capabilities */ + bool nonroot_keepcaps; + /* indicator if the container will be destroyed on shutdown */ unsigned int ephemeral; diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 0bebe4687e..72238b10be 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -92,6 +92,7 @@ lxc_config_define(init_cmd); lxc_config_define(init_cwd); lxc_config_define(init_gid); lxc_config_define(init_uid); +lxc_config_define(nonroot_keepcaps); lxc_config_define(init_groups); lxc_config_define(jump_table_net); lxc_config_define(keyring_session); @@ -235,6 +236,7 @@ static struct lxc_config_t config_jump_table[] = { { "lxc.init.gid", true, set_config_init_gid, get_config_init_gid, clr_config_init_gid, }, { "lxc.init.groups", true, set_config_init_groups, get_config_init_groups, clr_config_init_groups, }, { "lxc.init.uid", true, set_config_init_uid, get_config_init_uid, clr_config_init_uid, }, + { "lxc.cap.nonroot", true, set_config_nonroot_keepcaps, get_config_nonroot_keepcaps, clr_config_nonroot_keepcaps, }, { "lxc.init.cwd", true, set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, }, { "lxc.keyring.session", true, set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session }, { "lxc.log.file", true, set_config_log_file, get_config_log_file, clr_config_log_file, }, @@ -1287,6 +1289,12 @@ static int set_config_init_uid(const char *key, const char *value, return 0; } +static int set_config_nonroot_keepcaps(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + return set_config_bool_item(&lxc_conf->nonroot_keepcaps, value, false); +} + static int set_config_init_gid(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { @@ -2675,7 +2683,7 @@ static int set_config_console_size(const char *key, const char *value, * lxc.include. * 'x' and 'X' are substituted in-place. */ -static void update_hwaddr(const char *line) +static void update_hwaddr(char *line) { char *p; @@ -2701,7 +2709,7 @@ static void update_hwaddr(const char *line) rand_complete_hwaddr(p); } -int append_unexp_config_line(const char *line, struct lxc_conf *conf) +int append_unexp_config_line(char *line, struct lxc_conf *conf) { size_t linelen; size_t len = conf->unexpanded_len; @@ -4213,7 +4221,7 @@ static int get_config_uts_name(const char *key, char *retv, int inlen, static int get_config_hooks(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - char *subkey; + const char *subkey; int len, fulllen = 0, found = -1; struct string_entry *entry; int i; @@ -4535,6 +4543,12 @@ static int get_config_init_uid(const char *key, char *retv, int inlen, return lxc_get_conf_int(c, retv, inlen, c->init_uid); } +static int get_config_nonroot_keepcaps(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) +{ + return lxc_get_conf_bool(c, retv, inlen, c->nonroot_keepcaps); +} + static int get_config_init_gid(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { @@ -5268,6 +5282,13 @@ static inline int clr_config_init_uid(const char *key, struct lxc_conf *c, return 0; } +static inline int clr_config_nonroot_keepcaps(const char *key, struct lxc_conf *c, + void *data) +{ + c->nonroot_keepcaps = false; + return 0; +} + static inline int clr_config_init_gid(const char *key, struct lxc_conf *c, void *data) { diff --git a/src/lxc/confile.h b/src/lxc/confile.h index 33e97dbd46..cb9263849a 100644 --- a/src/lxc/confile.h +++ b/src/lxc/confile.h @@ -75,7 +75,7 @@ __hidden extern int lxc_list_net(struct lxc_conf *c, const char *key, char *retv __hidden extern int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include); -__hidden extern int append_unexp_config_line(const char *line, struct lxc_conf *conf); +__hidden extern int append_unexp_config_line(char *line, struct lxc_conf *conf); extern int lxc_config_define_add(struct lxc_list *defines, char *arg); diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c index 7dcd735698..1467a112a2 100644 --- a/src/lxc/confile_utils.c +++ b/src/lxc/confile_utils.c @@ -903,7 +903,7 @@ int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath, { __do_free char *dup = NULL; int fd, pid; - char *lastslash; + const char *lastslash; if (nsfd_path[0] == '/') { return open(nsfd_path, O_RDONLY | O_CLOEXEC); diff --git a/src/lxc/criu.c b/src/lxc/criu.c index 9996b888aa..d6c2c4cd65 100644 --- a/src/lxc/criu.c +++ b/src/lxc/criu.c @@ -939,6 +939,21 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_ goto out_fini_handler; } + if (!cgroup_ops->payload_delegate_controllers(cgroup_ops)) { + ERROR("Failed to delegate controllers to payload cgroup"); + goto out_fini_handler; + } + + if (!cgroup_ops->setup_limits(cgroup_ops, handler)) { + ERROR("Failed to setup cgroup limits"); + goto out_fini_handler; + } + + if (!cgroup_ops->chown(cgroup_ops, handler->conf)) + goto out_fini_handler; + + cgroup_ops->finalize(cgroup_ops); + if (!restore_net_info(c)) { ERROR("failed restoring network info"); goto out_fini_handler; diff --git a/src/lxc/pam/pam_cgfs.c b/src/lxc/pam/pam_cgfs.c index e638269bc8..f066345fab 100644 --- a/src/lxc/pam/pam_cgfs.c +++ b/src/lxc/pam/pam_cgfs.c @@ -362,7 +362,7 @@ static char *copy_to_eol(char *s) /* Check if given entry under /proc//mountinfo is a fuse.lxcfs mount. */ static bool is_lxcfs(const char *line) { - char *p = strstr(line, " - "); + const char *p = strstr(line, " - "); if (!p) return false; @@ -1914,7 +1914,7 @@ static bool cgv1_handle_cpuset_hierarchy(struct cgv1_hierarchy *h, if (*cgroup == '/') cgroup++; - slash = strchr(cgroup, '/'); + slash = (char *)strchr(cgroup, '/'); if (slash) *slash = '\0'; diff --git a/src/lxc/start.c b/src/lxc/start.c index 7e4381b5a3..55866e0268 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1616,20 +1616,36 @@ static int do_start(void *data) goto out_warn_father; } - if (!lxc_switch_uid_gid(new_uid, new_gid)) - goto out_warn_father; + if (handler->conf->nonroot_keepcaps) { + NOTICE("Keep capabilities"); + ret = lxc_set_keepcaps(); + if (ret < 0) + goto out_warn_father; + + if (!lxc_switch_uid_gid(new_uid, new_gid)) + goto out_warn_father; + + ret = lxc_bounding_as_ambient_caps(); + if (ret < 0) { + ERROR("Failed to set bounding capabilities as ambiant"); + goto out_warn_father; + } + } else { + if (!lxc_switch_uid_gid(new_uid, new_gid)) + goto out_warn_father; + + ret = lxc_ambient_caps_down(); + if (ret < 0) { + ERROR("Failed to clear ambient capabilities"); + goto out_warn_father; + } + } ret = prctl(PR_SET_DUMPABLE, prctl_arg(1), prctl_arg(0), prctl_arg(0), prctl_arg(0)); if (ret < 0) goto out_warn_father; - ret = lxc_ambient_caps_down(); - if (ret < 0) { - ERROR("Failed to clear ambient capabilities"); - goto out_warn_father; - } - if (handler->conf->monitor_signal_pdeath != SIGKILL) { ret = lxc_set_death_signal(handler->conf->monitor_signal_pdeath, handler->monitor_pid, status_fd); diff --git a/src/lxc/storage/nbd.c b/src/lxc/storage/nbd.c index c35f9e8659..73ea19b8c3 100644 --- a/src/lxc/storage/nbd.c +++ b/src/lxc/storage/nbd.c @@ -291,7 +291,7 @@ static void nbd_detach(const char *path) */ static int nbd_get_partition(const char *src) { - char *p = strchr(src, ':'); + const char *p = strchr(src, ':'); if (!p) return 0; diff --git a/src/lxc/storage/zfs.c b/src/lxc/storage/zfs.c index 521a9fd637..c3075962ab 100644 --- a/src/lxc/storage/zfs.c +++ b/src/lxc/storage/zfs.c @@ -461,7 +461,7 @@ int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, orig_src = cmd_output; } - tmp = strrchr(orig_src, '/'); + tmp = (char *)strrchr(orig_src, '/'); if (!tmp) { ERROR("Failed to detect \"/\" in \"%s\"", orig_src); return -1;