From 84c5a98487d43c8b9b98c5490f23084b6bb89efd Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 6 Dec 2016 14:36:32 -0800 Subject: [PATCH] hammer - Disallow modifying ioctls when filesystem is read-only * Disallow modifying ioctls if the filesystem has been mounted read-only or gone into read-only mode due to an I/O error. * This is only a partial fix. There are still error-pathing problems in numerous procedures, particularly the node locking code, that might result in a token life-lock. Reported-by: Peter Avalos --- sys/vfs/hammer/hammer_ioctl.c | 34 +++++++++++++++++++++++++++++++++- sys/vfs/hammer/hammer_prune.c | 8 ++++++++ sys/vfs/hammer/hammer_rebalance.c | 8 ++++++++ sys/vfs/hammer/hammer_reblock.c | 8 ++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/sys/vfs/hammer/hammer_ioctl.c b/sys/vfs/hammer/hammer_ioctl.c index e570c34f88..ea54f85749 100644 --- a/sys/vfs/hammer/hammer_ioctl.c +++ b/sys/vfs/hammer/hammer_ioctl.c @@ -66,14 +66,18 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, struct ucred *cred) { struct hammer_transaction trans; + struct hammer_mount *hmp; int error; error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0); + hmp = ip->hmp; - hammer_start_transaction(&trans, ip->hmp); + hammer_start_transaction(&trans, hmp); switch(com) { case HAMMERIOC_PRUNE: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_prune(&trans, ip, (struct hammer_ioc_prune *)data); @@ -84,6 +88,8 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, (struct hammer_ioc_history *)data); break; case HAMMERIOC_REBLOCK: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_reblock(&trans, ip, (struct hammer_ioc_reblock *)data); @@ -95,6 +101,8 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, * children and children's children. Systems with very * little memory will not be able to do it. */ + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0 && nbuf < HAMMER_REBALANCE_MIN_BUFS) { hkprintf("System has insufficient buffers " "to rebalance the tree. nbuf < %d\n", @@ -115,24 +123,32 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, (struct hammer_ioc_pseudofs_rw *)data); break; case HAMMERIOC_SET_PSEUDOFS: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_set_pseudofs(&trans, ip, cred, (struct hammer_ioc_pseudofs_rw *)data); } break; case HAMMERIOC_UPG_PSEUDOFS: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_upgrade_pseudofs(&trans, ip, (struct hammer_ioc_pseudofs_rw *)data); } break; case HAMMERIOC_DGD_PSEUDOFS: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_downgrade_pseudofs(&trans, ip, (struct hammer_ioc_pseudofs_rw *)data); } break; case HAMMERIOC_RMR_PSEUDOFS: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_destroy_pseudofs(&trans, ip, (struct hammer_ioc_pseudofs_rw *)data); @@ -151,6 +167,8 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, } break; case HAMMERIOC_MIRROR_WRITE: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_mirror_write(&trans, ip, (struct hammer_ioc_mirror_rw *)data); @@ -165,12 +183,16 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, (struct hammer_ioc_info *)data); break; case HAMMERIOC_SET_VERSION: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_set_version(&trans, ip, (struct hammer_ioc_version *)data); } break; case HAMMERIOC_ADD_VOLUME: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = priv_check_cred(cred, PRIV_HAMMER_VOLUME, 0); if (error == 0) @@ -179,6 +201,8 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, } break; case HAMMERIOC_DEL_VOLUME: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = priv_check_cred(cred, PRIV_HAMMER_VOLUME, 0); if (error == 0) @@ -191,12 +215,16 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, (struct hammer_ioc_volume_list *)data); break; case HAMMERIOC_ADD_SNAPSHOT: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_add_snapshot( &trans, ip, (struct hammer_ioc_snapshot *)data); } break; case HAMMERIOC_DEL_SNAPSHOT: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_del_snapshot( &trans, ip, (struct hammer_ioc_snapshot *)data); @@ -211,12 +239,16 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, &trans, ip, (struct hammer_ioc_config *)data); break; case HAMMERIOC_SET_CONFIG: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_set_config( &trans, ip, (struct hammer_ioc_config *)data); } break; case HAMMERIOC_DEDUP: + if (error == 0 && hmp->ronly) + error = EROFS; if (error == 0) { error = hammer_ioc_dedup( &trans, ip, (struct hammer_ioc_dedup *)data); diff --git a/sys/vfs/hammer/hammer_prune.c b/sys/vfs/hammer/hammer_prune.c index ec61213be4..01f0a70a3e 100644 --- a/sys/vfs/hammer/hammer_prune.c +++ b/sys/vfs/hammer/hammer_prune.c @@ -154,6 +154,14 @@ retry: prune->key_cur = elm->base; /* + * Filesystem went read-only during rebalancing + */ + if (trans->hmp->ronly) { + error = EROFS; + break; + } + + /* * Yield to more important tasks */ if ((error = hammer_signal_check(trans->hmp)) != 0) diff --git a/sys/vfs/hammer/hammer_rebalance.c b/sys/vfs/hammer/hammer_rebalance.c index 280671e42f..f8a1283c02 100644 --- a/sys/vfs/hammer/hammer_rebalance.c +++ b/sys/vfs/hammer/hammer_rebalance.c @@ -138,6 +138,14 @@ retry: } /* + * Filesystem went read-only during rebalancing + */ + if (trans->hmp->ronly) { + error = EROFS; + break; + } + + /* * We only care about internal nodes visited for the last * time on the way up... that is, a trailing scan of the * internal node after all of its children have been recursed diff --git a/sys/vfs/hammer/hammer_reblock.c b/sys/vfs/hammer/hammer_reblock.c index b6fd5e231d..8997e9bd97 100644 --- a/sys/vfs/hammer/hammer_reblock.c +++ b/sys/vfs/hammer/hammer_reblock.c @@ -149,6 +149,14 @@ retry: reblock->key_cur.localization = elm->base.localization; /* + * Filesystem went read-only during rebalancing + */ + if (trans->hmp->ronly) { + error = EROFS; + break; + } + + /* * Yield to more important tasks */ if ((error = hammer_signal_check(trans->hmp)) != 0) -- 2.11.4.GIT