-
Notifications
You must be signed in to change notification settings - Fork 660
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change file permissions on instances #3715
base: fix-platform-specific-functions-in-abstraction
Are you sure you want to change the base?
Changes from all commits
ed77c70
16283f4
f50e4c8
4c07be2
fedfa74
0b8949b
5fa30e7
eb4407b
b935c17
686405a
be83bc0
c3b60ce
4cdf1b8
3997885
b3024f5
4a1b649
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright (C) Canonical, Ltd. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; version 3. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#ifndef MULTIPASS_PERMISSION_UTILS_H | ||
#define MULTIPASS_PERMISSION_UTILS_H | ||
|
||
#include <multipass/singleton.h> | ||
|
||
#include <QFileDevice> | ||
#include <filesystem> | ||
|
||
#define MP_PERMISSIONS multipass::PermissionUtils::instance() | ||
|
||
namespace multipass | ||
{ | ||
namespace fs = std::filesystem; | ||
|
||
class PermissionUtils : public Singleton<PermissionUtils> | ||
{ | ||
public: | ||
PermissionUtils(const PrivatePass&) noexcept; | ||
|
||
virtual void set_permissions(const fs::path& path, const fs::perms& permissions) const; | ||
virtual void take_ownership(const fs::path& path) const; | ||
|
||
// sets owner to root and sets permissions such that only owner has access. | ||
virtual void restrict_permissions(const fs::path& path) const; | ||
}; | ||
} // namespace multipass | ||
|
||
#endif // MULTIPASS_PERMISSION_UTILS_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ | |
#include <multipass/ssl_cert_provider.h> | ||
#include <multipass/standard_paths.h> | ||
#include <multipass/utils.h> | ||
#include <multipass/utils/permission_utils.h> | ||
|
||
#include <QString> | ||
#include <QSysInfo> | ||
|
@@ -108,6 +109,8 @@ std::unique_ptr<const mp::DaemonConfig> mp::DaemonConfigBuilder::build() | |
auto multiplexing_logger = std::make_shared<mpl::MultiplexingLogger>(std::move(logger)); | ||
mpl::set_logger(multiplexing_logger); | ||
|
||
MP_PLATFORM.setup_permission_inheritance(); | ||
|
||
auto storage_path = MP_PLATFORM.multipass_storage_location(); | ||
if (!storage_path.isEmpty()) | ||
MP_UTILS.make_dir(storage_path, std::filesystem::perms::owner_all); | ||
|
@@ -189,6 +192,17 @@ std::unique_ptr<const mp::DaemonConfig> mp::DaemonConfigBuilder::build() | |
std::make_unique<DefaultVMBlueprintProvider>(url_downloader.get(), cache_directory, manifest_ttl); | ||
} | ||
|
||
// restrict permissions for all existing files and folders | ||
if (!storage_path.isEmpty()) | ||
{ | ||
MP_PERMISSIONS.restrict_permissions(storage_path.toStdU16String()); | ||
} | ||
else | ||
{ | ||
MP_PERMISSIONS.restrict_permissions(data_directory.toStdU16String()); | ||
MP_PERMISSIONS.restrict_permissions(cache_directory.toStdU16String()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, |
||
} | ||
|
||
return std::unique_ptr<const DaemonConfig>(new DaemonConfig{ | ||
std::move(url_downloader), std::move(factory), std::move(image_hosts), std::move(vault), | ||
std::move(name_generator), std::move(ssh_key_provider), std::move(cert_provider), std::move(client_cert_store), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
* Copyright (C) Canonical, Ltd. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; version 3. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#include <multipass/utils/permission_utils.h> | ||
|
||
#include <multipass/file_ops.h> | ||
#include <multipass/platform.h> | ||
|
||
namespace mp = multipass; | ||
namespace fs = mp::fs; | ||
|
||
namespace | ||
{ | ||
void set_single_permissions(const fs::path& path, const fs::perms& permissions, bool try_inherit) | ||
{ | ||
if (!MP_PLATFORM.set_permissions(path, permissions, try_inherit)) | ||
throw std::runtime_error(fmt::format("Cannot set permissions for '{}'", path.string())); | ||
} | ||
|
||
void set_single_owner(const fs::path& path) | ||
{ | ||
if (!MP_PLATFORM.take_ownership(path)) | ||
throw std::runtime_error(fmt::format("Cannot set owner for '{}'", path.string())); | ||
} | ||
|
||
// only exists because MP_FILEOPS doesn't overload the throwing variaions of std::filesystem functions | ||
void throw_if_error(const fs::path& path, const std::error_code& ec) | ||
{ | ||
if (ec) | ||
throw std::system_error( | ||
ec, | ||
fmt::format("System error occurred while handling permissions for '{}'", path.string())); | ||
} | ||
|
||
// recursively iterates over all files in folder and applies a function that takes a path | ||
template <class Func> | ||
void apply_on_files(const fs::path& path, Func&& func) | ||
{ | ||
std::error_code ec{}; | ||
if (!MP_FILEOPS.exists(path, ec) || ec) | ||
throw std::runtime_error(fmt::format("Cannot handle permissions for nonexistent file '{}'", path.string())); | ||
|
||
func(path, true); | ||
|
||
// iterate over children of directory | ||
if (MP_FILEOPS.is_directory(path, ec)) | ||
{ | ||
auto dir_iterator = MP_FILEOPS.recursive_dir_iterator(path, ec); | ||
throw_if_error(path, ec); | ||
|
||
if (!dir_iterator) [[unlikely]] | ||
throw std::runtime_error(fmt::format("Cannot iterate over directory '{}'", path.string())); | ||
|
||
while (dir_iterator->hasNext()) | ||
{ | ||
const auto& entry = dir_iterator->next(); | ||
|
||
func(entry.path(), false); | ||
} | ||
} | ||
|
||
throw_if_error(path, ec); | ||
} | ||
} // namespace | ||
|
||
mp::PermissionUtils::PermissionUtils(const PrivatePass& pass) noexcept : Singleton{pass} | ||
{ | ||
} | ||
|
||
void mp::PermissionUtils::set_permissions(const fs::path& path, const fs::perms& permissions) const | ||
{ | ||
apply_on_files(path, [&](const fs::path& apply_path, bool root_dir) { | ||
set_single_permissions(apply_path, permissions, !root_dir); | ||
}); | ||
} | ||
|
||
void mp::PermissionUtils::take_ownership(const fs::path& path) const | ||
{ | ||
apply_on_files(path, [&](const fs::path& apply_path, bool) { set_single_owner(apply_path); }); | ||
} | ||
|
||
void mp::PermissionUtils::restrict_permissions(const fs::path& path) const | ||
{ | ||
apply_on_files(path, [&](const fs::path& apply_path, bool root_dir) { | ||
set_single_owner(apply_path); | ||
set_single_permissions(apply_path, fs::perms::owner_all, !root_dir); | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* Copyright (C) Canonical, Ltd. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; version 3. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#ifndef MULTIPASS_MOCK_PERMISSION_UTILS_H | ||
#define MULTIPASS_MOCK_PERMISSION_UTILS_H | ||
|
||
#include "common.h" | ||
#include "mock_singleton_helpers.h" | ||
|
||
#include <multipass/utils/permission_utils.h> | ||
|
||
namespace multipass::test | ||
{ | ||
|
||
class MockPermissionUtils : public PermissionUtils | ||
{ | ||
public: | ||
MockPermissionUtils(const PrivatePass& pass) : PermissionUtils(pass) | ||
{ | ||
} | ||
|
||
MOCK_METHOD(void, set_permissions, (const fs::path& path, const fs::perms& permissions), (const, override)); | ||
MOCK_METHOD(void, take_ownership, (const fs::path& path), (const, override)); | ||
MOCK_METHOD(void, restrict_permissions, (const fs::path& path), (const, override)); | ||
|
||
MP_MOCK_SINGLETON_BOILERPLATE(MockPermissionUtils, PermissionUtils); | ||
}; | ||
} // namespace multipass::test | ||
|
||
#endif // MULTIPASS_MOCK_PERMISSION_UTILS_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is some overlap here where the permissions on the storage path is already being set.