Skip to content

Commit 9b78229

Browse files
reddevillgComixHe
authored andcommitted
feat: custom user/group content exposed in container
Write minimal /etc/passwd and /etc/group containing only the current user and "nobody". This reduces the information visible inside the container and ensures the user always exists, even when an nss module is used on the host. Signed-off-by: reddevillg <reddevillg@gmail.com>
1 parent b24be64 commit 9b78229

3 files changed

Lines changed: 72 additions & 14 deletions

File tree

libs/linglong/src/linglong/runtime/container_builder.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ auto ContainerBuilder::prepareContainer(runtime::RunContext &context,
328328
.setBundlePath(prepared.context->getBundleDir())
329329
.addUIdMapping(uid, uid, 1)
330330
.addGIdMapping(gid, gid, 1)
331-
.bindUserGroup()
332331
.bindDefault()
333332
.bindCgroup();
334333

@@ -385,6 +384,7 @@ auto ContainerBuilder::configureBuildContainer(PreparedContainer &prepared,
385384
LINGLONG_TRACE("configure build container");
386385

387386
prepared.cfgBuilder.setBasePath(options.basePath, false)
387+
.bindUserGroup()
388388
.forwardDefaultEnv()
389389
.appendEnv("LINYAPS_INIT_SINGLE_MODE", "1")
390390
.disableUserNamespace()
@@ -461,7 +461,11 @@ auto ContainerBuilder::configureInitContainer(PreparedContainer &prepared) noexc
461461

462462
auto &runContext = *prepared.runContext;
463463

464-
prepared.cfgBuilder.bindXDGRuntime().bindHostRoot().bindHostStatics().forwardDefaultEnv();
464+
prepared.cfgBuilder.bindUserGroup()
465+
.bindXDGRuntime()
466+
.bindHostRoot()
467+
.bindHostStatics()
468+
.forwardDefaultEnv();
465469

466470
if (runContext.getConfig().overlayfs) {
467471
auto res = prepared.context->setupOverlayFS(runContext, true);
@@ -518,6 +522,7 @@ auto ContainerBuilder::configureRunContainer(PreparedContainer &prepared,
518522
std::filesystem::path homePath{ homeEnv };
519523

520524
prepared.cfgBuilder.setAnnotation(generator::ANNOTATION::LAST_PID, std::to_string(::getpid()))
525+
.bindUserGroup(true)
521526
.bindXDGRuntime()
522527
.bindRemovableStorageMounts()
523528
.bindHostRoot()

libs/oci-cfg-generators/src/linglong/oci-cfg-generators/container_cfg_builder.cpp

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <sstream>
3333
#include <vector>
3434

35+
#include <grp.h>
36+
#include <pwd.h>
3537
#include <sys/stat.h>
3638
#include <sys/types.h>
3739
#include <unistd.h>
@@ -372,22 +374,70 @@ ContainerCfgBuilder &ContainerCfgBuilder::bindTmp() noexcept
372374
return *this;
373375
}
374376

375-
ContainerCfgBuilder &ContainerCfgBuilder::bindUserGroup() noexcept
377+
ContainerCfgBuilder &ContainerCfgBuilder::bindUserGroup(bool minimal) noexcept
376378
{
377-
UGMount = {
378-
Mount{ .destination = "/etc/passwd",
379-
.options = string_list{ "rbind", "ro" },
380-
.source = "/etc/passwd",
381-
.type = "bind" },
382-
Mount{ .destination = "/etc/group",
383-
.options = string_list{ "rbind", "ro" },
384-
.source = "/etc/group",
385-
.type = "bind" },
386-
};
379+
UGBind = minimal;
387380

388381
return *this;
389382
}
390383

384+
utils::error::Result<void> ContainerCfgBuilder::buildUserGroup() noexcept
385+
{
386+
LINGLONG_TRACE("build user group");
387+
388+
if (!UGBind.has_value()) {
389+
return LINGLONG_OK;
390+
}
391+
392+
std::filesystem::path passwdSrc{ "/etc/passwd" };
393+
std::filesystem::path groupSrc{ "/etc/group" };
394+
395+
if (UGBind.value()) {
396+
auto uid = ::getuid();
397+
auto gid = ::getgid();
398+
399+
passwdSrc = bundlePath / "passwd";
400+
groupSrc = bundlePath / "group";
401+
402+
{
403+
std::ofstream ofs(passwdSrc);
404+
if (!ofs.is_open()) {
405+
return LINGLONG_ERR(fmt::format("{} can't be created", passwdSrc));
406+
}
407+
408+
if (auto *pw = ::getpwuid(uid); pw != nullptr) {
409+
ofs << pw->pw_name << ":x:" << pw->pw_uid << ":" << pw->pw_gid << ":"
410+
<< (pw->pw_gecos ? pw->pw_gecos : "") << ":" << (pw->pw_dir ? pw->pw_dir : "")
411+
<< ":" << (pw->pw_shell ? pw->pw_shell : "") << "\n";
412+
}
413+
ofs << "nobody:x:65534:65534:nobody:/:/usr/sbin/nologin\n";
414+
}
415+
416+
{
417+
std::ofstream ofs(groupSrc);
418+
if (!ofs.is_open()) {
419+
return LINGLONG_ERR(fmt::format("{} can't be created", groupSrc));
420+
}
421+
422+
if (auto *gr = ::getgrgid(gid); gr != nullptr) {
423+
ofs << gr->gr_name << ":x:" << gr->gr_gid << ":\n";
424+
}
425+
ofs << "nobody:x:65534:\n";
426+
}
427+
}
428+
429+
UGMount = { Mount{ .destination = "/etc/passwd",
430+
.options = string_list{ "rbind", "ro" },
431+
.source = passwdSrc,
432+
.type = "bind" },
433+
Mount{ .destination = "/etc/group",
434+
.options = string_list{ "rbind", "ro" },
435+
.source = groupSrc,
436+
.type = "bind" } };
437+
438+
return LINGLONG_OK;
439+
}
440+
391441
ContainerCfgBuilder &ContainerCfgBuilder::bindRemovableStorageMounts() noexcept
392442
{
393443
// 绑定可移动存储设备的挂载点
@@ -2243,6 +2293,7 @@ utils::error::Result<void> ContainerCfgBuilder::build() noexcept
22432293
BUILD_STEP(buildLDCache);
22442294
BUILD_STEP(buildEnv);
22452295
BUILD_STEP(buildHooks);
2296+
BUILD_STEP(buildUserGroup);
22462297
BUILD_STEP(mergeMount);
22472298
BUILD_STEP(finalize);
22482299
BUILD_STEP(applyPatch);

libs/oci-cfg-generators/src/linglong/oci-cfg-generators/container_cfg_builder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class ContainerCfgBuilder
106106
ContainerCfgBuilder &bindXDGRuntime() noexcept;
107107
ContainerCfgBuilder &bindRun() noexcept;
108108
ContainerCfgBuilder &bindTmp() noexcept;
109-
ContainerCfgBuilder &bindUserGroup() noexcept;
109+
ContainerCfgBuilder &bindUserGroup(bool minimal = false) noexcept;
110110
ContainerCfgBuilder &bindRemovableStorageMounts() noexcept;
111111

112112
ContainerCfgBuilder &forwardDefaultEnv() noexcept;
@@ -213,6 +213,7 @@ class ContainerCfgBuilder
213213
utils::error::Result<void> buildLDCache() noexcept;
214214
utils::error::Result<void> buildMountTimeZone() noexcept;
215215
utils::error::Result<void> buildMountNetworkConf() noexcept;
216+
utils::error::Result<void> buildUserGroup() noexcept;
216217
utils::error::Result<void> buildQuirkVolatile() noexcept;
217218
utils::error::Result<void> buildXDGRuntime() noexcept;
218219
utils::error::Result<void> buildEnv() noexcept;
@@ -276,6 +277,7 @@ class ContainerCfgBuilder
276277
std::optional<std::vector<ocppi::runtime::config::types::Mount>> runMount;
277278
std::optional<ocppi::runtime::config::types::Mount> tmpMount;
278279
std::optional<std::vector<ocppi::runtime::config::types::Mount>> UGMount;
280+
std::optional<bool> UGBind{ std::nullopt };
279281
std::optional<std::vector<ocppi::runtime::config::types::Mount>> removableStorageMounts;
280282
std::optional<std::vector<ocppi::runtime::config::types::Mount>> hostRootMount;
281283
std::optional<std::vector<ocppi::runtime::config::types::Mount>> hostStaticsMount;

0 commit comments

Comments
 (0)