diff --git a/man/portablectl.xml b/man/portablectl.xml
index d7366376d9..190fefa97b 100644
--- a/man/portablectl.xml
+++ b/man/portablectl.xml
@@ -320,7 +320,8 @@
When attaching an image, select the profile to use. By default, the default
- profile is used. For details about profiles, see below.
+ profile is used. Attaching fails if the selected profile does not exist. For details about profiles, see
+ below.
diff --git a/src/portable/portable.c b/src/portable/portable.c
index 8f1e7f22cf..98f15a7be4 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -41,6 +41,7 @@
#include "nsresource.h"
#include "os-util.h"
#include "path-lookup.h"
+#include "path-util.h"
#include "pidref.h"
#include "portable.h"
#include "portable-util.h"
@@ -2055,6 +2056,10 @@ int portable_attach(
assert(scope < _RUNTIME_SCOPE_MAX);
+ r = portable_profile_validate(scope, profile, error);
+ if (r < 0)
+ return r;
+
r = extract_image_and_extensions(
scope,
name_or_path,
@@ -2660,6 +2665,36 @@ int portable_get_profiles(RuntimeScope scope, char ***ret) {
return conf_files_list_strv(ret, NULL, NULL, CONF_FILES_DIRECTORY|CONF_FILES_BASENAME|CONF_FILES_FILTER_MASKED, (const char* const*) dirs);
}
+int portable_profile_validate(RuntimeScope scope, const char *profile, sd_bus_error *reterr_error) {
+ _cleanup_strv_free_ char **profiles = NULL;
+ int r;
+
+ assert(scope < _RUNTIME_SCOPE_MAX);
+
+ if (!filename_is_valid(profile))
+ return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Profile name '%s' is not valid.", profile);
+
+ r = portable_get_profiles(scope, &profiles);
+ if (r < 0)
+ return sd_bus_error_set_errnof(reterr_error, r, "Failed to enumerate portable profiles: %m");
+
+ if (strv_contains(profiles, profile))
+ return 0;
+
+ _cleanup_free_ char *joined = strv_join(profiles, ", ");
+ if (!joined)
+ return -ENOMEM;
+
+ return sd_bus_error_setf(
+ reterr_error,
+ SD_BUS_ERROR_INVALID_ARGS,
+ "Profile '%s' does not exist, refusing.%s%s%s",
+ profile,
+ isempty(joined) ? "" : " (Available profiles are: ",
+ strempty(joined),
+ isempty(joined) ? "" : ")");
+}
+
static const char* const portable_change_type_table[_PORTABLE_CHANGE_TYPE_MAX] = {
[PORTABLE_COPY] = "copy",
[PORTABLE_MKDIR] = "mkdir",
diff --git a/src/portable/portable.h b/src/portable/portable.h
index 597f0f1468..1711618f42 100644
--- a/src/portable/portable.h
+++ b/src/portable/portable.h
@@ -111,6 +111,7 @@ int portable_get_state(
sd_bus_error *error);
int portable_get_profiles(RuntimeScope scope, char ***ret);
+int portable_profile_validate(RuntimeScope scope, const char *profile, sd_bus_error *reterr_error);
void portable_changes_free(PortableChange *array, size_t n);
diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c
index 5517ea10a1..5a5393e986 100644
--- a/src/portable/portabled-image-bus.c
+++ b/src/portable/portabled-image-bus.c
@@ -714,6 +714,11 @@ int bus_image_common_reattach(
if (r == 0) /* Will call us back */
return 1;
+ /* portable_attach() checks this too, but by then the image is detached already. */
+ r = portable_profile_validate(m->runtime_scope, profile, error);
+ if (r < 0)
+ return r;
+
r = portable_detach(
m->runtime_scope,
sd_bus_message_get_bus(message),