Skip to content

Commit

Permalink
added mount tunnel based addMount() implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
goruklu committed Oct 2, 2024
1 parent 59c8437 commit 40911e3
Show file tree
Hide file tree
Showing 12 changed files with 648 additions and 12 deletions.
5 changes: 2 additions & 3 deletions bundle/lib/source/templates/OciConfigJson1.0.2-dobby.template
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ static const char* ociJsonTemplate = R"JSON(
"readonly": true
},

"rootfsPropagation": "rprivate",

"hostname": "dobby",

"mounts": [
Expand Down Expand Up @@ -377,7 +375,8 @@ static const char* ociJsonTemplate = R"JSON(
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
],
"rootfsPropagation": "slave"
},
{{#ENABLE_LEGACY_PLUGINS}}
"legacyPlugins": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ static const char* ociJsonTemplate = R"JSON(
"readonly": true
},

"rootfsPropagation": "rprivate",

"hostname": "dobby",

"mounts": [
Expand Down Expand Up @@ -388,7 +386,8 @@ static const char* ociJsonTemplate = R"JSON(
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
],
"rootfsPropagation": "slave"
},
{{#ENABLE_LEGACY_PLUGINS}}
"legacyPlugins": {
Expand Down
24 changes: 24 additions & 0 deletions bundle/runtime-schemas/defs-plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,30 @@
}
}
},
"mounttunnel": {
"type": "array",
"items": {
"type": "object",
"required": [
"destination",
"source"
],
"properties": {
"destination": {
"type": "string"
},
"flags": {
"$ref": "defs.json#/definitions/int32"
},
"options": {
"$ref": "defs.json#/definitions/ArrayOfStrings"
},
"source": {
"type": "string"
}
}
}
},
"mountOwner": {
"type": "array",
"items": {
Expand Down
127 changes: 123 additions & 4 deletions daemon/lib/source/DobbyManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1849,7 +1849,7 @@ bool DobbyManager::addMount(int32_t cd, const std::string &source, const std::st
AI_LOG_FN_EXIT();
return false;
}

#ifdef HAVE_LINUX_MOUNT_H
int fdMnt = syscall(SYS_open_tree, -EBADF, source.c_str(), OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE);
if (fdMnt < 0)
Expand Down Expand Up @@ -1924,9 +1924,128 @@ bool DobbyManager::addMount(int32_t cd, const std::string &source, const std::st
AI_LOG_FN_EXIT();
return true;
#else
AI_LOG_ERROR("open_tree and move_mount are not supported on this platform, aborting mount operation inside %s", id.c_str());
AI_LOG_FN_EXIT();
return false;
// get the mount tunnel configuration from storage plugin
if(it->second->rdkPluginManager == nullptr ||
it->second->rdkPluginManager->getContainerConfig()->rdk_plugins->storage == nullptr ||
it->second->rdkPluginManager->getContainerConfig()->rdk_plugins->storage->data->mounttunnel_len == 0)
{
AI_LOG_ERROR("mount tunnel is not configured in %s", id.c_str());
AI_LOG_FN_EXIT();
return false;
}

auto mounttunnel = it->second->rdkPluginManager->getContainerConfig()->rdk_plugins->storage->data->mounttunnel[0];
if(mounttunnel->source == nullptr || mounttunnel->destination == nullptr)
{
AI_LOG_ERROR("mount tunnel source or destination not found for %s", id.c_str());
AI_LOG_FN_EXIT();
return false;
}

std::string mountPointInsideContainer = destination;
std::string tempMountPointInsideContainer = std::string(mounttunnel->destination) + "/tmpdir";
std::string tempMountPointOutsideContainer = std::string(mounttunnel->source) + "/tmpdir";

AI_LOG_INFO("temp mount point outside container: %s", tempMountPointOutsideContainer.c_str());
AI_LOG_INFO("temp mount point inside container: %s", tempMountPointInsideContainer.c_str());

// create the temporary mount point outside the container
mUtilities->mkdirRecursive(tempMountPointOutsideContainer.c_str(), 0755);

// mount the source dir on the temporary mount point outside the container
// this is needed to move the mount inside the container namespace later
if(mount(source.c_str(), tempMountPointOutsideContainer.c_str(), nullptr, mountOptions, nullptr))
{
AI_LOG_WARN("mount failed for %s errno: %d", destination.c_str(), errno);
mUtilities->rmdirRecursive(tempMountPointOutsideContainer.c_str());
AI_LOG_FN_EXIT();
return false;
}

AI_LOG_INFO("%s is mounted on %s inside %s", source.c_str(), tempMountPointOutsideContainer.c_str(), id.c_str());

auto doMoveMountLambda = [containerUID, containerGID, tempMountPointInsideContainer, mountPointInsideContainer, mountOptions, mountData]()
{
// switch to uid / gid of the host since we are still in the host user namespace
if (syscall(SYS_setresgid, -1, containerGID, -1) != 0)
{
AI_LOG_ERROR("failed to setresgid for container with GID: %d", containerGID);
return false;
}

if (syscall(SYS_setresuid, -1, containerUID, -1) != 0)
{
AI_LOG_ERROR("failed to setresuid for container with UID: %d", containerUID);
return false;
}

if (mkdir(mountPointInsideContainer.c_str(), 0755) != 0)
{
AI_LOG_ERROR("failed to create destination directory %s", mountPointInsideContainer.c_str());
return false;
}
// revert back to root for the mount
if (syscall(SYS_setresgid, -1, 0, -1) != 0)
{
AI_LOG_ERROR("failed to setresgid for root");
return false;
}

if (syscall(SYS_setresuid, -1, 0, -1) != 0)
{
AI_LOG_ERROR("failed to setresuid for root");
return false;
}
// move the mount from the temporary mount point inside the container to the final mount point
if(mount(tempMountPointInsideContainer.c_str(), mountPointInsideContainer.c_str(), nullptr, mountOptions | MS_MOVE, nullptr))
{
AI_LOG_WARN("mount failed for src %s, dest %s errno: %d", tempMountPointInsideContainer.c_str(), mountPointInsideContainer.c_str(), errno);
return false;
}
return true;

};

bool success = true;
if(!mUtilities->callInNamespace(containerPid, CLONE_NEWNS, doMoveMountLambda))
{
AI_LOG_ERROR("failed to addMount for %s in %s", source.c_str(), id.c_str());
success = false;
}

// cleanup the temporary mount on the host, we don't need it anymore
if (umount2(tempMountPointOutsideContainer.c_str(), UMOUNT_NOFOLLOW) != 0)
{
AI_LOG_SYS_ERROR(errno, "failed to unmount '%s'",
tempMountPointOutsideContainer.c_str());
}
else
{
AI_LOG_INFO("unmounted temp mount @ '%s', now deleting mount point",
tempMountPointOutsideContainer.c_str());

// can now delete the temporary mount point
if (rmdir(tempMountPointOutsideContainer.c_str()) != 0)
{
AI_LOG_SYS_ERROR(errno, "failed to delete temp mount point @ '%s'",
tempMountPointOutsideContainer.c_str());
}else{
AI_LOG_INFO("deleted temp mount point @ '%s'", tempMountPointOutsideContainer.c_str());
}
}

if(success)
{
AI_LOG_INFO("%s is mounted on %s inside %s", source.c_str(), destination.c_str(), id.c_str());
AI_LOG_FN_EXIT();
return true;
}
else
{
AI_LOG_ERROR("failed to addMount for %s in %s", source.c_str(), id.c_str());
AI_LOG_FN_EXIT();
return false;
}
#endif
}

Expand Down
5 changes: 5 additions & 0 deletions pluginLauncher/lib/include/DobbyRdkPluginManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ class DobbyRdkPluginManager
// This is public as RDKPluginManager isn't responsible for handling logging
std::shared_ptr<IDobbyRdkLoggingPlugin> getContainerLogger() const;
void setExitStatus(int status) const;

std::shared_ptr<rt_dobby_schema> getContainerConfig() const
{
return mContainerConfig;
};

private:
bool loadPlugins();
Expand Down
1 change: 1 addition & 0 deletions rdkPlugins/Storage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ add_library( ${PROJECT_NAME}
source/LoopMountDetails.cpp
source/DynamicMountDetails.cpp
source/MountOwnerDetails.cpp
source/MountTunnelDetails.cpp
)

target_include_directories(${PROJECT_NAME}
Expand Down
32 changes: 32 additions & 0 deletions rdkPlugins/Storage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,38 @@ It will mount "source" into container "destination" only if the source exists on
}
}
```
### Mount tunnels
Add the following section to your OCI runtime configuration `config.json` file to create a mount tunnel.

This will enable dynamic mounting of host devices/directories inside the container on devices running older linux kernels.

You need to have `rootfsPropagation` set to `slave` in the OCI runtime configuration for the tunneling to work.
Some references :
- https://lwn.net/Articles/690679/
- https://brauner.io/2023/02/28/mounting-into-mount-namespaces.html
- https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt

Please note that devices with kernel 5.4 or higher don't need the mount tunnel for dynamic mounts.

In the config example below, `/mnt/hostmnttunnel` dir will be created on the host, `/mnt/containermnttunnel` dir will be created inside the container's rootfs before the container is launched.
With propagation set to slave mode, any devices or dirs mounted under `/mnt/hostmnttunnel` directory will be visible under `/mnt/containertunnel` inside the container mount namespace allowing dynamic mount() unmount() operations.
```json
{
"rdkPlugins": {
"storage": {
"required": true,
"data": {
"mounttunnel": [
{
"destination": "/mnt/containermnttunnel",
"source": "/mnt/hostmnttunnel"
}
]
}
}
}
}
```

### Mount Owners
Add the following section to your OCI runtime configuration `config.json` file to configure mount ownership.
Expand Down
12 changes: 12 additions & 0 deletions rdkPlugins/Storage/source/MountProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,16 @@ typedef struct _MountOwnerProperties

} MountOwnerProperties;

/**
* @brief MountTunnelProperties struct used for Storage plugin
*/
typedef struct _MountTunnelProperties
{
std::string source;
std::string destination;
std::list<std::string> mountOptions;
unsigned long mountFlags;

} MountTunnelProperties;

#endif // !defined(MOUNTPROPERTIES_H)
Loading

0 comments on commit 40911e3

Please sign in to comment.