Skip to content

Commit 308b80b

Browse files
committed
feat: add rootfsPropagation support and improve error handling
- Add rootfsPropagation field to linux config (shared/slave/private/unbindable) - Fix mount propagation flag handling (use |= instead of &=) - Replace std::cerr with LINYAPS_BOX_ERR() for consistent logging - Use _exit() instead of exit() in child processes - Improve error messages with better context Allows control over mount propagation for the root filesystem according to OCI spec. Signed-off-by: ComixHe <ComixHe1895@outlook.com>
1 parent 16f40a4 commit 308b80b

File tree

4 files changed

+67
-22
lines changed

4 files changed

+67
-22
lines changed

src/linyaps_box/app.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ try {
7777
} },
7878
options.subcommand_opt);
7979
} catch (const std::exception &e) {
80-
std::cerr << "Error: " << e.what() << std::endl;
80+
LINYAPS_BOX_ERR() << "Error: " << e.what();
8181
return -1;
8282
} catch (...) {
83-
std::cerr << "Error: unknown" << std::endl;
83+
LINYAPS_BOX_ERR() << "unknown error";
8484
return -1;
8585
}
8686

src/linyaps_box/config.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ parse_mount_options(const std::vector<std::string> &options)
7979
continue;
8080
}
8181
if (auto it = propagation_flags_map.find(opt); it != propagation_flags_map.end()) {
82-
propagation_flags &= it->second;
82+
propagation_flags |= it->second;
8383
continue;
8484
}
8585

@@ -262,6 +262,21 @@ linyaps_box::config::linux_t parse_linux(const nlohmann::json &obj,
262262
linux.readonly_paths = std::move(readonly_paths);
263263
}
264264

265+
if (auto rootfs_propagation = ptr / "rootfsPropagation"; obj.contains(rootfs_propagation)) {
266+
auto val = obj[rootfs_propagation].get<std::string>();
267+
if (val == "shared") {
268+
linux.rootfs_propagation = MS_SHARED;
269+
} else if (val == "slave") {
270+
linux.rootfs_propagation = MS_SLAVE;
271+
} else if (val == "private") {
272+
linux.rootfs_propagation = MS_PRIVATE;
273+
} else if (val == "unbindable") {
274+
linux.rootfs_propagation = MS_UNBINDABLE;
275+
} else {
276+
throw std::runtime_error("unsupported rootfs propagation: " + val);
277+
}
278+
}
279+
265280
return linux;
266281
}
267282

src/linyaps_box/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ struct config
123123
std::optional<std::vector<id_mapping_t>> gid_mappings;
124124
std::optional<std::vector<std::filesystem::path>> masked_paths;
125125
std::optional<std::vector<std::filesystem::path>> readonly_paths;
126+
unsigned int rootfs_propagation{ 0 };
126127
};
127128

128129
std::optional<linux_t> linux;

src/linyaps_box/container.cpp

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct container_data
5555
{
5656
bool deny_setgroups{ false };
5757
bool mount_dev_from_host{ false };
58+
unsigned int rootfs_propagation{ 0 };
5859
};
5960

6061
container_data &get_private_data(const linyaps_box::container &c) noexcept
@@ -215,8 +216,16 @@ void execute_hook(const linyaps_box::config::hooks_t::hook_t &hook)
215216
const_cast<char *const *>(c_args.data()), // NOLINT
216217
const_cast<char *const *>(c_env.data())); // NOLINT
217218

218-
std::cerr << "execvp: " << strerror(errno) << " errno=" << errno << std::endl;
219-
exit(1);
219+
LINYAPS_BOX_ERR() << "execute hook " << [&bin, &c_args]() -> std::string {
220+
std::stringstream stream;
221+
stream << bin;
222+
for (const auto &arg : c_args) {
223+
stream << " " << arg;
224+
}
225+
return std::move(stream).str();
226+
}() << " failed: "
227+
<< strerror(errno);
228+
_exit(EXIT_FAILURE);
220229
}
221230

222231
int status = 0;
@@ -687,20 +696,31 @@ class mounter
687696

688697
// we will pivot root later
689698
LINYAPS_BOX_DEBUG() << "configure rootfs";
699+
auto flags = config.linux->rootfs_propagation;
700+
if ((flags & propagations_flag) == 0) {
701+
flags = MS_PRIVATE | MS_REC;
702+
}
703+
704+
// change the propagation type of rootfs mountpoint to configured type
705+
// otherwise bind mount will inherit the propagation type of rootfs mountpoint
690706
do_propagation_mount(linyaps_box::utils::open("/", O_PATH | O_CLOEXEC | O_DIRECTORY),
691-
MS_REC | MS_PRIVATE);
707+
flags);
692708

693-
// make sure the parent mount of rootfs is private
709+
// make sure the parent mountpoint of new root is private
694710
// pivot root will fail if it has shared propagation type
695711
make_rootfs_private();
696712

713+
// pivot root will reset the propagation type of rootfs mountpoint
714+
// we need to save the propagation type to make sure the parent mountpoint of new root is
715+
// what we want
716+
get_private_data(container).rootfs_propagation = flags;
717+
697718
LINYAPS_BOX_DEBUG() << "rebind container rootfs";
698719

699720
linyaps_box::config::mount_t mount;
700721
mount.source = root.current_path();
701722
mount.destination = ".";
702-
mount.flags = MS_BIND | MS_REC;
703-
// mount.propagation_flags = MS_PRIVATE | MS_REC;
723+
mount.flags = MS_BIND | MS_REC | MS_PRIVATE;
704724
auto ret = do_mount(container, root, mount);
705725
assert(!ret);
706726

@@ -1278,7 +1298,7 @@ void create_container_hooks(const linyaps_box::container &container,
12781298
LINYAPS_BOX_DEBUG() << "Sync message sent";
12791299
}
12801300

1281-
void do_pivot_root(const std::filesystem::path &rootfs)
1301+
void do_pivot_root(const linyaps_box::container &container, const std::filesystem::path &rootfs)
12821302
{
12831303
LINYAPS_BOX_DEBUG() << "start pivot root";
12841304
LINYAPS_BOX_DEBUG() << linyaps_box::utils::inspect_fds();
@@ -1303,6 +1323,15 @@ void do_pivot_root(const std::filesystem::path &rootfs)
13031323
throw std::system_error(errno, std::generic_category(), "pivot_root");
13041324
}
13051325

1326+
ret = fchdir(old_root.get());
1327+
if (ret < 0) {
1328+
throw std::system_error(errno, std::generic_category(), "fchdir");
1329+
}
1330+
1331+
// make sure that umount event couldn't propagate to host
1332+
do_propagation_mount(old_root, MS_REC | MS_PRIVATE);
1333+
1334+
// umount old root
13061335
ret = umount2(".", MNT_DETACH);
13071336
if (ret < 0) {
13081337
throw std::system_error(errno, std::generic_category(), "umount2");
@@ -1322,6 +1351,10 @@ void do_pivot_root(const std::filesystem::path &rootfs)
13221351
if (ret < 0) {
13231352
throw std::system_error(errno, std::generic_category(), "chdir");
13241353
}
1354+
1355+
// restore the propagation type of rootfs mountpoint
1356+
do_propagation_mount(linyaps_box::utils::open("/", O_PATH | O_CLOEXEC | O_DIRECTORY),
1357+
get_private_data(container).rootfs_propagation);
13251358
}
13261359

13271360
void set_umask(const std::optional<mode_t> &mask)
@@ -1614,18 +1647,18 @@ try {
16141647
wait_create_runtime_result(container, socket);
16151648
create_container_hooks(container, socket);
16161649
// TODO: selinux label/apparmor profile
1617-
do_pivot_root(rootfs);
1650+
do_pivot_root(container, rootfs);
16181651
set_umask(container.get_config().process.user.umask);
16191652
// processing all extensions before drop capabilities
16201653
processing_extensions(container);
16211654
set_capabilities(container, runtime_cap);
16221655
start_container_hooks(container, socket);
16231656
execute_process(process);
16241657
} catch (const std::exception &e) {
1625-
std::cerr << e.what() << std::endl;
1658+
LINYAPS_BOX_ERR() << "clone failed: " << e.what();
16261659
return -1;
16271660
} catch (...) {
1628-
std::cerr << "unknown error" << std::endl;
1661+
LINYAPS_BOX_ERR() << "clone failed: unknown error";
16291662
return -1;
16301663
}
16311664

@@ -1719,8 +1752,7 @@ class child_stack
17191752
return;
17201753
}
17211754

1722-
const auto code = errno;
1723-
std::cerr << "munmap: " << strerror(code) << std::endl;
1755+
LINYAPS_BOX_ERR() << "munmap child stack failed: " << strerror(errno);
17241756
assert(false);
17251757
}
17261758

@@ -1827,12 +1859,9 @@ std::tuple<int, linyaps_box::utils::file_descriptor> start_container_process(
18271859
}
18281860

18291861
c_args.push_back(nullptr);
1830-
auto ret = execvp(c_args[0], const_cast<char *const *>(c_args.data()));
1831-
if (ret < 0) {
1832-
exit(errno);
1833-
}
1834-
1835-
exit(0);
1862+
execvp(c_args[0], const_cast<char *const *>(c_args.data()));
1863+
LINYAPS_BOX_ERR() << "execute helper " << c_args[0] << " failed: " << strerror(errno);
1864+
_exit(EXIT_FAILURE);
18361865
}
18371866

18381867
int status = 0;
@@ -2214,7 +2243,7 @@ void poststop_hooks(const linyaps_box::container &container) noexcept
22142243
try {
22152244
execute_hook(hook);
22162245
} catch (const std::exception &e) {
2217-
std::cerr << "Error: " << e.what() << std::endl;
2246+
LINYAPS_BOX_ERR() << "execute poststop hook " << hook.path << " failed: " << e.what();
22182247
}
22192248
}
22202249
}

0 commit comments

Comments
 (0)