Skip to content

Commit

Permalink
Allow users access to unpriviledged zpool/zfs commands
Browse files Browse the repository at this point in the history
The following zpool/zfs commands should be runable as a normal
non-priviledged user.

  * zpool list|iostat|status|get
  * zfs list|get

Adding this functionality primarily required implementing the
secpolicy_* functions by mapping them to equivilant Linux
capabilities.

While the mapping operation is straight forward the implementation
was complicated by the fact that the kernel `capability()` function
only allows you to check your current content.  This poses an issue
for the existing ZFS code which expects to be able to check a cred
in any context.  To resolve the issue `secpolicy_zfs()` checks are
now made in the original cred context and if they pass a kcred is
provided for latter use by the sync task.

In order to verify this functionality is working as designed the
ZFS Test Suite cli_user/* tests have all been enabled.  These tests
are run as a normal user and are used to verify permissions are
enforced.

The `zpool_create_001_neg` and `zpool_add_001_neg` test cases were
slightly modified for Linux.  They now allow a normal user to run
these commands in dry-run mode since no escalated priviledges are
required.

Two minor bug fixes were required for test-running.py.  First, the
Timer() object cannot be safely created in a `try:` block when there
is an unconditional `finally` block which references it.  Second,
when running as a normal user also check for scripts using the
both the .ksh and .sh suffixes.

Signed-off-by: Brian Behlendorf <[email protected]>
Issue openzfs#362
  • Loading branch information
behlendorf committed Apr 2, 2016
1 parent 63e0828 commit 44190cf
Show file tree
Hide file tree
Showing 63 changed files with 569 additions and 178 deletions.
27 changes: 13 additions & 14 deletions cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <priv.h>
#include <pwd.h>
#include <zone.h>
#include <zfs_prop.h>
Expand Down Expand Up @@ -2252,21 +2251,21 @@ zpool_do_import(int argc, char **argv)
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}
}

/*
* Check for the SYS_CONFIG privilege. We do this explicitly
* here because otherwise any attempt to discover pools will
* silently fail.
*/
if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
(void) fprintf(stderr, gettext("cannot "
"discover pools: permission denied\n"));
if (searchdirs != NULL)
free(searchdirs);
/*
* Check for the effective uid. We do this explicitly
* here because otherwise any attempt to discover pools will
* silently fail.
*/
if (argc == 0 && geteuid() != 0) {
(void) fprintf(stderr, gettext("cannot "
"discover pools: permission denied\n"));
if (searchdirs != NULL)
free(searchdirs);

nvlist_free(policy);
return (1);
}
nvlist_free(policy);
return (1);
}

/*
Expand Down
1 change: 1 addition & 0 deletions include/sys/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ COMMON_H = \
$(top_srcdir)/include/sys/multilist.h \
$(top_srcdir)/include/sys/nvpair.h \
$(top_srcdir)/include/sys/nvpair_impl.h \
$(top_srcdir)/include/sys/policy.h \
$(top_srcdir)/include/sys/range_tree.h \
$(top_srcdir)/include/sys/refcount.h \
$(top_srcdir)/include/sys/rrwlock.h \
Expand Down
60 changes: 60 additions & 0 deletions include/sys/policy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/

/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015, Joyent, Inc. All rights reserved.
* Copyright (c) 2016, Lawrence Livermore National Security, LLC.
*/

#ifndef _SYS_POLICY_H
#define _SYS_POLICY_H

#ifdef _KERNEL

#include <sys/cred.h>
#include <sys/types.h>
#include <sys/xvattr.h>
#include <sys/zpl.h>

int secpolicy_nfs(const cred_t *);
int secpolicy_sys_config(const cred_t *, boolean_t);
int secpolicy_vnode_access2(const cred_t *, struct inode *,
uid_t, mode_t, mode_t);
int secpolicy_vnode_any_access(const cred_t *, struct inode *, uid_t);
int secpolicy_vnode_chown(const cred_t *, uid_t);
int secpolicy_vnode_create_gid(const cred_t *);
int secpolicy_vnode_remove(const cred_t *);
int secpolicy_vnode_setdac(const cred_t *, uid_t);
int secpolicy_vnode_setid_retain(const cred_t *, boolean_t);
int secpolicy_vnode_setids_setgids(const cred_t *, gid_t);
int secpolicy_zinject(const cred_t *);
int secpolicy_zfs(const cred_t *);
void secpolicy_setid_clear(vattr_t *, cred_t *);
int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *,
const vattr_t *, cred_t *);
int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t);
int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *,
const struct vattr *, int, int (void *, int, cred_t *), void *);
int secpolicy_basic_link(const cred_t *);

#endif /* _KERNEL */
#endif /* _SYS_POLICY_H */
1 change: 1 addition & 0 deletions include/sys/zfs_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr);
extern int zfs_secpolicy_rename_perms(const char *from, const char *to,
cred_t *cr);
extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
extern int secpolicy_zfs(const cred_t *cr);
extern zoneid_t getzoneid(void);

/* SID stuff */
Expand Down
1 change: 0 additions & 1 deletion lib/libspl/include/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ libspl_HEADERS = \
$(top_srcdir)/lib/libspl/include/limits.h \
$(top_srcdir)/lib/libspl/include/locale.h \
$(top_srcdir)/lib/libspl/include/note.h \
$(top_srcdir)/lib/libspl/include/priv.h \
$(top_srcdir)/lib/libspl/include/statcommon.h \
$(top_srcdir)/lib/libspl/include/stdio.h \
$(top_srcdir)/lib/libspl/include/stdlib.h \
Expand Down
46 changes: 0 additions & 46 deletions lib/libspl/include/priv.h

This file was deleted.

1 change: 0 additions & 1 deletion lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#include <fcntl.h>
#include <sys/mntent.h>
#include <sys/mount.h>
#include <priv.h>
#include <pwd.h>
#include <grp.h>
#include <stddef.h>
Expand Down
6 changes: 6 additions & 0 deletions lib/libzpool/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,12 @@ zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
return (0);
}

int
secpolicy_zfs(const cred_t *cr)
{
return (0);
}

ksiddomain_t *
ksid_lookupdomain(const char *dom)
{
Expand Down
1 change: 1 addition & 0 deletions module/zfs/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ $(MODULE)-objs += lzjb.o
$(MODULE)-objs += lz4.o
$(MODULE)-objs += metaslab.o
$(MODULE)-objs += multilist.o
$(MODULE)-objs += policy.o
$(MODULE)-objs += range_tree.o
$(MODULE)-objs += refcount.o
$(MODULE)-objs += rrwlock.o
Expand Down
15 changes: 13 additions & 2 deletions module/zfs/dmu_objset.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include <sys/zfs_onexit.h>
#include <sys/dsl_destroy.h>
#include <sys/vdev.h>
#include <sys/policy.h>

/*
* Needed to close a window in dnode_move() that allows the objset to be freed
Expand Down Expand Up @@ -880,9 +881,14 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg)
{
dmu_objset_create_arg_t doca;
int error;

error = secpolicy_zfs(CRED());
if (error)
return (SET_ERROR(error));

doca.doca_name = name;
doca.doca_cred = CRED();
doca.doca_cred = kcred;
doca.doca_flags = flags;
doca.doca_userfunc = func;
doca.doca_userarg = arg;
Expand Down Expand Up @@ -974,10 +980,15 @@ int
dmu_objset_clone(const char *clone, const char *origin)
{
dmu_objset_clone_arg_t doca;
int error;

error = secpolicy_zfs(CRED());
if (error)
return (SET_ERROR(error));

doca.doca_clone = clone;
doca.doca_origin = origin;
doca.doca_cred = CRED();
doca.doca_cred = kcred;

return (dsl_sync_task(clone,
dmu_objset_clone_check, dmu_objset_clone_sync, &doca,
Expand Down
10 changes: 8 additions & 2 deletions module/zfs/dmu_send.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <sys/zfeature.h>
#include <sys/bqueue.h>
#include <sys/zvol.h>
#include <sys/policy.h>

/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
int zfs_send_corrupt_data = B_FALSE;
Expand Down Expand Up @@ -1405,13 +1406,18 @@ dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
{
dmu_recv_begin_arg_t drba = { 0 };
dmu_replay_record_t *drr;
int error;

error = secpolicy_zfs(CRED());
if (error)
return (SET_ERROR(error));

bzero(drc, sizeof (dmu_recv_cookie_t));
drc->drc_drrb = drrb;
drc->drc_tosnap = tosnap;
drc->drc_tofs = tofs;
drc->drc_force = force;
drc->drc_cred = CRED();
drc->drc_cred = kcred;

if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
drc->drc_byteswap = B_TRUE;
Expand Down Expand Up @@ -1441,7 +1447,7 @@ dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,

drba.drba_origin = origin;
drba.drba_cookie = drc;
drba.drba_cred = CRED();
drba.drba_cred = kcred;

return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync,
&drba, 5, ZFS_SPACE_CHECK_NORMAL));
Expand Down
13 changes: 11 additions & 2 deletions module/zfs/dsl_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include <sys/dsl_destroy.h>
#include <sys/dsl_userhold.h>
#include <sys/dsl_bookmark.h>
#include <sys/policy.h>

/*
* The SPA supports block sizes up to 16MB. However, very large blocks
Expand Down Expand Up @@ -1456,6 +1457,10 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
spa_close(spa, FTAG);

error = secpolicy_zfs(CRED());
if (error)
return (SET_ERROR(error));

if (needsuspend) {
suspended = fnvlist_alloc();
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
Expand Down Expand Up @@ -1483,7 +1488,7 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
ddsa.ddsa_snaps = snaps;
ddsa.ddsa_props = props;
ddsa.ddsa_errors = errors;
ddsa.ddsa_cr = CRED();
ddsa.ddsa_cr = kcred;

if (error == 0) {
error = dsl_sync_task(firstname, dsl_dataset_snapshot_check,
Expand Down Expand Up @@ -2671,9 +2676,13 @@ dsl_dataset_promote(const char *name, char *conflsnap)
if (error != 0)
return (error);

error = secpolicy_zfs(CRED());
if (error)
return (SET_ERROR(error));

ddpa.ddpa_clonename = name;
ddpa.err_ds = conflsnap;
ddpa.cr = CRED();
ddpa.cr = kcred;

return (dsl_sync_task(name, dsl_dataset_promote_check,
dsl_dataset_promote_sync, &ddpa,
Expand Down
7 changes: 6 additions & 1 deletion module/zfs/dsl_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1923,10 +1923,15 @@ int
dsl_dir_rename(const char *oldname, const char *newname)
{
dsl_dir_rename_arg_t ddra;
int error;

error = secpolicy_zfs(CRED());
if (error)
return (SET_ERROR(error));

ddra.ddra_oldname = oldname;
ddra.ddra_newname = newname;
ddra.ddra_cred = CRED();
ddra.ddra_cred = kcred;

return (dsl_sync_task(oldname,
dsl_dir_rename_check, dsl_dir_rename_sync, &ddra,
Expand Down
Loading

0 comments on commit 44190cf

Please sign in to comment.