-
Notifications
You must be signed in to change notification settings - Fork 654
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
d46ce1a
fa51635
18ace88
3cb65f2
04bb354
6ee71ea
81f0a32
345b38e
d88b055
bc08d4b
36e630f
73f969e
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 QFileDevice::Permissions& 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> | ||
|
@@ -189,6 +190,16 @@ std::unique_ptr<const mp::DaemonConfig> mp::DaemonConfigBuilder::build() | |
std::make_unique<DefaultVMBlueprintProvider>(url_downloader.get(), cache_directory, manifest_ttl); | ||
} | ||
|
||
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,104 @@ | ||
/* | ||
* 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 QFileDevice::Permissions& permissions) | ||
{ | ||
QString qpath = QString::fromUtf8(path.u8string()); | ||
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. There's some funny conversion going on here. 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. yeah, |
||
|
||
if (!MP_PLATFORM.set_permissions(qpath, permissions)) | ||
throw std::runtime_error(fmt::format("Cannot set permissions for '{}'", path.string())); | ||
} | ||
|
||
void set_single_owner(const fs::path& path) | ||
{ | ||
QString qpath = QString::fromUtf8(path.u8string()); | ||
|
||
if (!MP_PLATFORM.take_ownership(qpath)) | ||
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); | ||
|
||
// iterate over children if 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()); | ||
} | ||
} | ||
|
||
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 QFileDevice::Permissions& permissions) const | ||
{ | ||
apply_on_files(path, [&](const fs::path& apply_path) { set_single_permissions(apply_path, permissions); }); | ||
} | ||
|
||
void mp::PermissionUtils::take_ownership(const fs::path& path) const | ||
{ | ||
apply_on_files(path, [&](const fs::path& apply_path) { set_single_owner(apply_path); }); | ||
} | ||
|
||
void mp::PermissionUtils::restrict_permissions(const fs::path& path) const | ||
{ | ||
apply_on_files(path, [&](const fs::path& apply_path) { | ||
set_single_owner(apply_path); | ||
set_single_permissions(apply_path, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
#include "tests/common.h" | ||
#include "tests/mock_image_host.h" | ||
#include "tests/mock_logger.h" | ||
#include "tests/mock_permission_utils.h" | ||
#include "tests/mock_process_factory.h" | ||
#include "tests/stub_url_downloader.h" | ||
#include "tests/temp_dir.h" | ||
|
@@ -60,6 +61,9 @@ struct LXDImageVault : public Test | |
|
||
mpt::MockLogger::Scope logger_scope = mpt::MockLogger::inject(); | ||
std::unique_ptr<NiceMock<mpt::MockNetworkAccessManager>> mock_network_access_manager; | ||
const mpt::MockPermissionUtils::GuardedMock mock_permission_utils_injection = | ||
mpt::MockPermissionUtils::inject<NiceMock>(); | ||
mpt::MockPermissionUtils& mock_permission_utils = *mock_permission_utils_injection.first; | ||
std::vector<mp::VMImageHost*> hosts; | ||
NiceMock<mpt::MockImageHost> host; | ||
QUrl base_url{"unix:///[email protected]"}; | ||
|
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.