[linux-lvm] [PATCH] fix LVM device permissions
Andreas Dilger
adilger at turbolinux.com
Sat Dec 23 01:39:58 UTC 2000
Included here is a patch for LVM 0.9 (from 2.2.18 patch) which fixes the
permission checking in the kernel. The goal is that any user who has
read access to the /dev/lvm /dev/<vg>/* devices can check the status,
and users with write permission can change the LVM devices. This allows
delegation of storage admin to non-root users, if desired, and allows
you to check the LVM status as a regular user.
Unfortunately, the patch is not tested, as I'm currently having compiler
problems with my kernel, which prevent me from booting :-(. However, it
is relatively safe (obvious changes) as long as you are not running a
full-LVM system. You also need to define the SUSER_CHECK in lvm_user.h as
#define SUSER_CHECK
(obvious patch at bottom). If this works OK, then the SUSER_CHECK calls
in all of the tools should be removed. Testing _should_ show that root
and users in the "disk" group (or whatever group is set for the files)
can do everything, and others can do things like "pvdisplay /dev/hda1"
or whatever. If not, "strace <command>" would help figure out what is
wrong.
Cheers, Andreas
============================================================================
--- drivers/block/lvm.c.orig Mon Dec 18 17:46:40 2000
+++ drivers/block/lvm.c Fri Dec 22 16:17:50 2000
@@ -647,9 +647,6 @@
lvm_name, minor, VG_CHR(minor), file->f_mode, lock);
#endif
- /* super user validation */
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-
/* Group special file open */
if (VG_CHR(minor) > MAX_VG) return -ENXIO;
@@ -696,6 +693,8 @@
switch (command) {
case LVM_LOCK_LVM:
/* lock the LVM */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_lock_lvm();
case LVM_GET_IOP_VERSION:
@@ -708,6 +707,8 @@
#ifdef LVM_TOTAL_RESET
case LVM_RESET:
/* lock reset function */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
lvm_reset_spindown = 1;
for (v = 0; v < ABS_MAX_VG; v++) {
if (vg[v] != NULL) lvm_do_vg_remove(v);
@@ -727,36 +728,52 @@
case LE_REMAP:
/* remap a logical extent (after moving the physical extent) */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_le_remap(vg_ptr,arg);
case PE_LOCK_UNLOCK:
/* lock/unlock i/o to a physical extent to move it to another
physical volume (move's done in user space's pvmove) */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_pe_lock_unlock(vg_ptr,arg);
case VG_CREATE:
/* create a VGDA */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_vg_create(minor, arg);
case VG_EXTEND:
/* extend a volume group */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_vg_extend(vg_ptr, arg);
case VG_REDUCE:
/* reduce a volume group */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_vg_reduce(vg_ptr, arg);
case VG_RENAME:
/* rename a volume group */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_vg_rename(vg_ptr, arg);
case VG_REMOVE:
/* remove an inactive VGDA */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_vg_remove(minor);
case VG_SET_EXTENDABLE:
/* set/clear extendability flag of volume group */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
if (vg_ptr == NULL) return -ENXIO;
if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0)
return -EFAULT;
@@ -773,6 +790,8 @@
case VG_STATUS:
/* get volume group data (only the vg_t struct) */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
if (vg_ptr == NULL) return -ENXIO;
if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0)
return -EFAULT;
@@ -781,6 +800,8 @@
case VG_STATUS_GET_COUNT:
/* get volume group count */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0)
return -EFAULT;
return 0;
@@ -788,6 +809,8 @@
case VG_STATUS_GET_NAMELIST:
/* get volume group count */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
for (l = v = 0; v < ABS_MAX_VG; v++) {
if (vg[v] != NULL) {
if (copy_to_user(arg + l * NAME_LEN,
@@ -806,6 +829,8 @@
case LV_REMOVE:
case LV_RENAME:
/* create, extend, reduce, remove or rename a logical volume */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
if (vg_ptr == NULL) return -ENXIO;
if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0)
return -EFAULT;
@@ -833,30 +858,43 @@
case LV_STATUS_BYNAME:
/* get status of a logical volume by name */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_lv_status_byname(vg_ptr, arg);
case LV_STATUS_BYINDEX:
/* get status of a logical volume by index */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_lv_status_byindex(vg_ptr, arg);
case LV_STATUS_BYDEV:
+ /* get status of a logical volume by device */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_lv_status_bydev(vg_ptr, arg);
case PV_CHANGE:
/* change a physical volume */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_pv_change(vg_ptr,arg);
case PV_STATUS:
/* get physical volume data (pv_t structure only) */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_do_pv_status(vg_ptr,arg);
case PV_FLUSH:
/* physical volume buffer flush/invalidate */
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
if (copy_from_user(&pv_flush_req, arg,
sizeof(pv_flush_req)) != 0)
return -EFAULT;
@@ -994,6 +1034,8 @@
switch (command) {
case BLKGETSIZE:
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
/* return device size */
#ifdef DEBUG_IOCTL
printk(KERN_DEBUG
@@ -1007,7 +1049,8 @@
case BLKFLSBUF:
/* flush buffer cache */
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
#ifdef DEBUG_IOCTL
printk(KERN_DEBUG
@@ -1019,7 +1062,8 @@
case BLKRASET:
/* set read ahead for block device */
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
#ifdef DEBUG_IOCTL
printk(KERN_DEBUG
@@ -1035,6 +1079,8 @@
case BLKRAGET:
/* get current read ahead setting */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
#ifdef DEBUG_IOCTL
printk(KERN_DEBUG
"%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
@@ -1046,6 +1092,8 @@
case HDIO_GETGEO:
/* get disk geometry */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
#ifdef DEBUG_IOCTL
printk(KERN_DEBUG
"%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
@@ -1079,7 +1127,8 @@
case LV_SET_ACCESS:
/* set access flags of a logical volume */
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
lv_ptr->lv_access = (ulong) arg;
if ( lv_ptr->lv_access & LV_WRITE)
set_device_ro(lv_ptr->lv_dev, 0);
@@ -1090,7 +1139,8 @@
case LV_SET_STATUS:
/* set status flags of a logical volume */
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
return -EPERM;
lv_ptr->lv_status = (ulong) arg;
@@ -1098,16 +1148,21 @@
case LV_BMAP:
/* turn logical block into (dev_t, block). non privileged. */
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
return lvm_user_bmap(inode, (struct lv_bmap *) arg);
break;
case LV_SET_ALLOCATION:
/* set allocation flags of a logical volume */
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (!(file->f_mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
lv_ptr->lv_allocation = (ulong) arg;
break;
case LV_SNAPSHOT_USE_RATE:
+ if (!(file->f_mode & FMODE_READ) && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
if (!(lv_ptr->lv_access & LV_SNAPSHOT)) return -EPERM;
{
lv_snapshot_use_rate_req_t lv_snapshot_use_rate_req;
==============================================================================
--- tools/lvm_user.h.orig Wed Nov 15 02:26:59 2000
+++ tools/lvm_user.h Fri Dec 22 18:32:59 2000
@@ -58,12 +58,7 @@
#include <getopt.h>
#include <lvm.h>
-#define SUSER_CHECK { \
- if ( ! ( getuid () == 0 && geteuid () == 0)) { \
- fprintf ( stderr, "%s -- this command is for root only\n\n", cmd); \
- return 1; \
- } \
-}
+#define SUSER_CHECK
#define LVMFILE_CHECK( chkfile) { \
int file = -1; \
--
Andreas Dilger \ "If a man ate a pound of pasta and a pound of antipasto,
\ would they cancel out, leaving him still hungry?"
http://www-mddsp.enel.ucalgary.ca/People/adilger/ -- Dogbert
More information about the linux-lvm
mailing list