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:
Colin Walters 2016-06-16 08:52:29 -04:00 committed by Atomic Bot
parent 5936b53812
commit 3c77c36999
5 changed files with 66 additions and 14 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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*