Restrict visibility of per-dataset kstats inside FreeBSD jails
When inside a jail, visibility on datasets not "jailed" to the jail is restricted. However, it was possible to enumerate all datasets in the pool by looking at the kstats sysctl MIB. Only the kstats corresponding to datasets that the user has visibility on are accessible now. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Richard Yao <richard.yao@alumni.stonybrook.edu> Signed-off-by: Allan Jude <allan@klarasystems.com> Closes #14254
This commit is contained in:
parent
24a6d8316a
commit
6219190d7f
|
@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/kstat.h>
|
#include <sys/kstat.h>
|
||||||
#include <sys/sbuf.h>
|
#include <sys/sbuf.h>
|
||||||
|
#include <sys/zone.h>
|
||||||
|
|
||||||
static MALLOC_DEFINE(M_KSTAT, "kstat_data", "Kernel statistics");
|
static MALLOC_DEFINE(M_KSTAT, "kstat_data", "Kernel statistics");
|
||||||
|
|
||||||
|
@ -134,6 +135,55 @@ kstat_sysctl_string(SYSCTL_HANDLER_ARGS)
|
||||||
return (sysctl_handle_string(oidp, val, len, req));
|
return (sysctl_handle_string(oidp, val, len, req));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
kstat_sysctl_dataset(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
kstat_t *ksp = arg1;
|
||||||
|
kstat_named_t *ksent;
|
||||||
|
kstat_named_t *ksent_ds;
|
||||||
|
uint64_t val;
|
||||||
|
char *ds_name;
|
||||||
|
uint32_t ds_len = 0;
|
||||||
|
|
||||||
|
ksent_ds = ksent = ksp->ks_data;
|
||||||
|
ds_name = KSTAT_NAMED_STR_PTR(ksent_ds);
|
||||||
|
ds_len = KSTAT_NAMED_STR_BUFLEN(ksent_ds);
|
||||||
|
ds_name[ds_len-1] = '\0';
|
||||||
|
|
||||||
|
if (!zone_dataset_visible(ds_name, NULL)) {
|
||||||
|
return (EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select the correct element */
|
||||||
|
ksent += arg2;
|
||||||
|
/* Update the aggsums before reading */
|
||||||
|
(void) ksp->ks_update(ksp, KSTAT_READ);
|
||||||
|
val = ksent->value.ui64;
|
||||||
|
|
||||||
|
return (sysctl_handle_64(oidp, &val, 0, req));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
kstat_sysctl_dataset_string(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
kstat_t *ksp = arg1;
|
||||||
|
kstat_named_t *ksent = ksp->ks_data;
|
||||||
|
char *val;
|
||||||
|
uint32_t len = 0;
|
||||||
|
|
||||||
|
/* Select the correct element */
|
||||||
|
ksent += arg2;
|
||||||
|
val = KSTAT_NAMED_STR_PTR(ksent);
|
||||||
|
len = KSTAT_NAMED_STR_BUFLEN(ksent);
|
||||||
|
val[len-1] = '\0';
|
||||||
|
|
||||||
|
if (!zone_dataset_visible(val, NULL)) {
|
||||||
|
return (EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (sysctl_handle_string(oidp, val, len, req));
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
kstat_sysctl_io(SYSCTL_HANDLER_ARGS)
|
kstat_sysctl_io(SYSCTL_HANDLER_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -422,11 +472,20 @@ kstat_install_named(kstat_t *ksp)
|
||||||
ksp, i, kstat_sysctl, "Q", namelast);
|
ksp, i, kstat_sysctl, "Q", namelast);
|
||||||
break;
|
break;
|
||||||
case KSTAT_DATA_UINT64:
|
case KSTAT_DATA_UINT64:
|
||||||
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
if (strcmp(ksp->ks_class, "dataset") == 0) {
|
||||||
SYSCTL_CHILDREN(ksp->ks_sysctl_root),
|
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
||||||
OID_AUTO, namelast,
|
SYSCTL_CHILDREN(ksp->ks_sysctl_root),
|
||||||
CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
|
OID_AUTO, namelast,
|
||||||
ksp, i, kstat_sysctl, "QU", namelast);
|
CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
|
||||||
|
ksp, i, kstat_sysctl_dataset, "QU",
|
||||||
|
namelast);
|
||||||
|
} else {
|
||||||
|
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
||||||
|
SYSCTL_CHILDREN(ksp->ks_sysctl_root),
|
||||||
|
OID_AUTO, namelast,
|
||||||
|
CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
|
||||||
|
ksp, i, kstat_sysctl, "QU", namelast);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case KSTAT_DATA_LONG:
|
case KSTAT_DATA_LONG:
|
||||||
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
||||||
|
@ -443,11 +502,21 @@ kstat_install_named(kstat_t *ksp)
|
||||||
ksp, i, kstat_sysctl, "LU", namelast);
|
ksp, i, kstat_sysctl, "LU", namelast);
|
||||||
break;
|
break;
|
||||||
case KSTAT_DATA_STRING:
|
case KSTAT_DATA_STRING:
|
||||||
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
if (strcmp(ksp->ks_class, "dataset") == 0) {
|
||||||
SYSCTL_CHILDREN(ksp->ks_sysctl_root),
|
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
||||||
OID_AUTO, namelast,
|
SYSCTL_CHILDREN(ksp->ks_sysctl_root),
|
||||||
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
|
OID_AUTO, namelast, CTLTYPE_STRING |
|
||||||
ksp, i, kstat_sysctl_string, "A", namelast);
|
CTLFLAG_RD | CTLFLAG_MPSAFE,
|
||||||
|
ksp, i, kstat_sysctl_dataset_string, "A",
|
||||||
|
namelast);
|
||||||
|
} else {
|
||||||
|
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
||||||
|
SYSCTL_CHILDREN(ksp->ks_sysctl_root),
|
||||||
|
OID_AUTO, namelast, CTLTYPE_STRING |
|
||||||
|
CTLFLAG_RD | CTLFLAG_MPSAFE,
|
||||||
|
ksp, i, kstat_sysctl_string, "A",
|
||||||
|
namelast);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("unsupported type: %d", typelast);
|
panic("unsupported type: %d", typelast);
|
||||||
|
|
Loading…
Reference in New Issue