core: Make unprivileged case ignore ownership, add "_compose" context
I was in the process of trying to support `%post` scripts, and I wanted to use `rpm-ostree container` for convenient and safe testing. However the recent package layering changes broke it to error out on perms like `filesystem`'s `root:mail` on `/var/mail`. I decided to introduce a new `rpmostree_context_new_compose` which had the current behavior, switch `compose tree` to use it, and then change `_new_unprivileged` to *really* be unprivileged. Specifically we ignore file ownership (and fix dir owners) because we assume we'll be operating with `bare-user` repos. Closes: #327 Approved by: jlebon
This commit is contained in:
parent
5936b53812
commit
3c77c36999
@ -689,7 +689,7 @@ rpmostree_compose_builtin_tree (int argc,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
corectx = rpmostree_context_new_unprivileged (self->cachedir_dfd, cancellable, error);
|
corectx = rpmostree_context_new_compose (self->cachedir_dfd, cancellable, error);
|
||||||
if (!corectx)
|
if (!corectx)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -275,6 +275,7 @@ struct _RpmOstreeContext {
|
|||||||
RpmOstreeTreespec *spec;
|
RpmOstreeTreespec *spec;
|
||||||
HifContext *hifctx;
|
HifContext *hifctx;
|
||||||
OstreeRepo *ostreerepo;
|
OstreeRepo *ostreerepo;
|
||||||
|
gboolean unprivileged;
|
||||||
char *dummy_instroot_path;
|
char *dummy_instroot_path;
|
||||||
OstreeSePolicy *sepolicy;
|
OstreeSePolicy *sepolicy;
|
||||||
};
|
};
|
||||||
@ -356,10 +357,11 @@ rpmostree_context_new_system (GCancellable *cancellable,
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
RpmOstreeContext *
|
static RpmOstreeContext *
|
||||||
rpmostree_context_new_unprivileged (int userroot_dfd,
|
rpmostree_context_new_internal (int userroot_dfd,
|
||||||
GCancellable *cancellable,
|
gboolean unprivileged,
|
||||||
GError **error)
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
g_autoptr(RpmOstreeContext) ret = rpmostree_context_new_system (cancellable, error);
|
g_autoptr(RpmOstreeContext) ret = rpmostree_context_new_system (cancellable, error);
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
@ -367,6 +369,8 @@ rpmostree_context_new_unprivileged (int userroot_dfd,
|
|||||||
if (!ret)
|
if (!ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
ret->unprivileged = unprivileged;
|
||||||
|
|
||||||
{ g_autofree char *reposdir = glnx_fdrel_abspath (userroot_dfd, "rpmmd.repos.d");
|
{ g_autofree char *reposdir = glnx_fdrel_abspath (userroot_dfd, "rpmmd.repos.d");
|
||||||
hif_context_set_repo_dir (ret->hifctx, reposdir);
|
hif_context_set_repo_dir (ret->hifctx, reposdir);
|
||||||
}
|
}
|
||||||
@ -408,6 +412,22 @@ rpmostree_context_new_unprivileged (int userroot_dfd,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RpmOstreeContext *
|
||||||
|
rpmostree_context_new_compose (int basedir_dfd,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return rpmostree_context_new_internal (basedir_dfd, FALSE, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
RpmOstreeContext *
|
||||||
|
rpmostree_context_new_unprivileged (int basedir_dfd,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return rpmostree_context_new_internal (basedir_dfd, TRUE, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: or put this in new_system() instead? */
|
/* XXX: or put this in new_system() instead? */
|
||||||
void
|
void
|
||||||
rpmostree_context_set_repo (RpmOstreeContext *self,
|
rpmostree_context_set_repo (RpmOstreeContext *self,
|
||||||
@ -1290,7 +1310,7 @@ rpmostree_context_download (RpmOstreeContext *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
import_one_package (OstreeRepo *ostreerepo,
|
import_one_package (RpmOstreeContext *self,
|
||||||
HifContext *hifctx,
|
HifContext *hifctx,
|
||||||
HifPackage *pkg,
|
HifPackage *pkg,
|
||||||
OstreeSePolicy *sepolicy,
|
OstreeSePolicy *sepolicy,
|
||||||
@ -1298,6 +1318,7 @@ import_one_package (OstreeRepo *ostreerepo,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
OstreeRepo *ostreerepo = self->ostreerepo;
|
||||||
g_autofree char *ostree_commit = NULL;
|
g_autofree char *ostree_commit = NULL;
|
||||||
glnx_unref_object RpmOstreeUnpacker *unpacker = NULL;
|
glnx_unref_object RpmOstreeUnpacker *unpacker = NULL;
|
||||||
g_autofree char *pkg_path;
|
g_autofree char *pkg_path;
|
||||||
@ -1314,6 +1335,8 @@ import_one_package (OstreeRepo *ostreerepo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
flags = RPMOSTREE_UNPACKER_FLAGS_OSTREE_CONVENTION;
|
flags = RPMOSTREE_UNPACKER_FLAGS_OSTREE_CONVENTION;
|
||||||
|
if (self->unprivileged)
|
||||||
|
flags |= RPMOSTREE_UNPACKER_FLAGS_UNPRIVILEGED;
|
||||||
|
|
||||||
/* TODO - tweak the unpacker flags for containers */
|
/* TODO - tweak the unpacker flags for containers */
|
||||||
unpacker = rpmostree_unpacker_new_at (AT_FDCWD, pkg_path, flags, error);
|
unpacker = rpmostree_unpacker_new_at (AT_FDCWD, pkg_path, flags, error);
|
||||||
@ -1369,7 +1392,7 @@ rpmostree_context_import (RpmOstreeContext *self,
|
|||||||
for (guint i = 0; i < install->packages_to_import->len; i++)
|
for (guint i = 0; i < install->packages_to_import->len; i++)
|
||||||
{
|
{
|
||||||
HifPackage *pkg = install->packages_to_import->pdata[i];
|
HifPackage *pkg = install->packages_to_import->pdata[i];
|
||||||
if (!import_one_package (self->ostreerepo, hifctx, pkg,
|
if (!import_one_package (self, hifctx, pkg,
|
||||||
self->sepolicy, cancellable, error))
|
self->sepolicy, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
hif_state_assert_done (hifstate);
|
hif_state_assert_done (hifstate);
|
||||||
|
@ -38,6 +38,10 @@ G_DECLARE_FINAL_TYPE (RpmOstreeInstall, rpmostree_install, RPMOSTREE, INSTALL, G
|
|||||||
RpmOstreeContext *rpmostree_context_new_system (GCancellable *cancellable,
|
RpmOstreeContext *rpmostree_context_new_system (GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
RpmOstreeContext *rpmostree_context_new_compose (int basedir_dfd,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
RpmOstreeContext *rpmostree_context_new_unprivileged (int basedir_dfd,
|
RpmOstreeContext *rpmostree_context_new_unprivileged (int basedir_dfd,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -503,15 +503,15 @@ typedef struct
|
|||||||
} cb_data;
|
} cb_data;
|
||||||
|
|
||||||
static OstreeRepoCommitFilterResult
|
static OstreeRepoCommitFilterResult
|
||||||
filter_cb (OstreeRepo *repo,
|
compose_filter_cb (OstreeRepo *repo,
|
||||||
const char *path,
|
const char *path,
|
||||||
GFileInfo *file_info,
|
GFileInfo *file_info,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
RpmOstreeUnpacker *self = ((cb_data*)user_data)->self;
|
RpmOstreeUnpacker *self = ((cb_data*)user_data)->self;
|
||||||
GError **error = ((cb_data*)user_data)->error;
|
GError **error = ((cb_data*)user_data)->error;
|
||||||
|
|
||||||
/* For now we fail if an RPM requires a file to be owned by non-root. The
|
/* In the system case, fail if an RPM requires a file to be owned by non-root. The
|
||||||
* problem is that RPM provides strings, but ostree records uids/gids. Any
|
* problem is that RPM provides strings, but ostree records uids/gids. Any
|
||||||
* mapping we choose would be specific to a certain userdb and thus not
|
* mapping we choose would be specific to a certain userdb and thus not
|
||||||
* portable. To properly support this will probably require switching over to
|
* portable. To properly support this will probably require switching over to
|
||||||
@ -548,6 +548,23 @@ filter_cb (OstreeRepo *repo,
|
|||||||
return OSTREE_REPO_COMMIT_FILTER_ALLOW;
|
return OSTREE_REPO_COMMIT_FILTER_ALLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static OstreeRepoCommitFilterResult
|
||||||
|
unprivileged_filter_cb (OstreeRepo *repo,
|
||||||
|
const char *path,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
|
||||||
|
/* Fedora changed the directories to not be writable by root for bad
|
||||||
|
* reasons, which isn't useful here since we expect people to slap a
|
||||||
|
* ro bind mount on top, so let's just mark as writable by user.
|
||||||
|
*/
|
||||||
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
|
||||||
|
mode |= S_IWUSR;
|
||||||
|
g_file_info_set_attribute_uint32 (file_info, "unix::mode", mode);
|
||||||
|
return OSTREE_REPO_COMMIT_FILTER_ALLOW;
|
||||||
|
}
|
||||||
|
|
||||||
static GVariant*
|
static GVariant*
|
||||||
xattr_cb (OstreeRepo *repo,
|
xattr_cb (OstreeRepo *repo,
|
||||||
const char *path,
|
const char *path,
|
||||||
@ -596,8 +613,14 @@ import_rpm_to_repo (RpmOstreeUnpacker *self,
|
|||||||
|
|
||||||
GError *cb_error = NULL;
|
GError *cb_error = NULL;
|
||||||
cb_data fdata = { self, &cb_error };
|
cb_data fdata = { self, &cb_error };
|
||||||
|
OstreeRepoCommitFilter filter;
|
||||||
|
|
||||||
modifier = ostree_repo_commit_modifier_new (0, filter_cb, &fdata, NULL);
|
if ((self->flags & RPMOSTREE_UNPACKER_FLAGS_UNPRIVILEGED) > 0)
|
||||||
|
filter = unprivileged_filter_cb;
|
||||||
|
else
|
||||||
|
filter = compose_filter_cb;
|
||||||
|
|
||||||
|
modifier = ostree_repo_commit_modifier_new (0, filter, &fdata, NULL);
|
||||||
ostree_repo_commit_modifier_set_xattr_callback (modifier, xattr_cb,
|
ostree_repo_commit_modifier_set_xattr_callback (modifier, xattr_cb,
|
||||||
NULL, self);
|
NULL, self);
|
||||||
ostree_repo_commit_modifier_set_sepolicy (modifier, sepolicy);
|
ostree_repo_commit_modifier_set_sepolicy (modifier, sepolicy);
|
||||||
|
@ -36,9 +36,11 @@ GType rpmostree_unpacker_get_type (void);
|
|||||||
/**
|
/**
|
||||||
* RpmOstreeUnpackerFlags:
|
* RpmOstreeUnpackerFlags:
|
||||||
* @RPMOSTREE_UNPACKER_FLAGS_OSTREE_CONVENTION: Move files to follow ostree convention
|
* @RPMOSTREE_UNPACKER_FLAGS_OSTREE_CONVENTION: Move files to follow ostree convention
|
||||||
|
* @RPMOSTREE_UNPACKER_FLAGS_UNPRIVILEGED: Ignore file ownership and setuid modes
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RPMOSTREE_UNPACKER_FLAGS_OSTREE_CONVENTION = (1 << 0)
|
RPMOSTREE_UNPACKER_FLAGS_OSTREE_CONVENTION = (1 << 0),
|
||||||
|
RPMOSTREE_UNPACKER_FLAGS_UNPRIVILEGED = (1 << 1)
|
||||||
} RpmOstreeUnpackerFlags;
|
} RpmOstreeUnpackerFlags;
|
||||||
|
|
||||||
RpmOstreeUnpacker*
|
RpmOstreeUnpacker*
|
||||||
|
Loading…
Reference in New Issue
Block a user