Skip to content

Commit e96d9a9

Browse files
kvaneeshdavejiang
authored andcommitted
nvdimm/pfn_dev: Prevent the creation of zero-sized namespaces
On architectures that have different page size values used for kernel direct mapping and userspace mappings, the user can end up creating zero-sized namespaces as shown below :/sys/bus/nd/devices/region1# cat align 0x1000000 /sys/bus/nd/devices/region1# echo 0x200000 > align /sys/bus/nd/devices/region1/dax1.0# cat supported_alignments 65536 16777216 $ ndctl create-namespace -r region1 -m devdax -s 18M --align 64K { "dev":"namespace1.0", "mode":"devdax", "map":"dev", "size":0, "uuid":"3094329a-0c66-4905-847e-357223e56ab0", "daxregion":{ "id":1, "size":0, "align":65536 }, "align":65536 } similarily for fsdax $ ndctl create-namespace -r region1 -m fsdax -s 18M --align 64K { "dev":"namespace1.0", "mode":"fsdax", "map":"dev", "size":0, "uuid":"45538a6f-dec7-405d-b1da-2a4075e06232", "sector_size":512, "align":65536, "blockdev":"pmem1" } In commit 9ffc1d1 ("mm/memremap_pages: Introduce memremap_compat_align()") memremap_compat_align was added to make sure the kernel always creates namespaces with 16MB alignment. But the user can still override the region alignment and no input validation is done in the region alignment values to retain the flexibility user had before. However, the kernel ensures that only part of the namespace that can be mapped via kernel direct mapping page size is enabled. This is achieved by tracking the unmapped part of the namespace in pfn_sb->end_trunc. The kernel also ensures that the start address of the namespace is also aligned to the kernel direct mapping page size. Depending on the user request, the kernel implements userspace mapping alignment by updating pfn device alignment attribute and this value is used to adjust the start address for userspace mappings. This is tracked in pfn_sb->dataoff. Hence the available size for userspace mapping is: usermapping_size = size of the namespace - pfn_sb->end_trun - pfn_sb->dataoff If the kernel finds the user mapping size zero then don't allow the creation of namespace. After fix: $ ndctl create-namespace -f -r region1 -m devdax -s 18M --align 64K libndctl: ndctl_dax_enable: dax1.1: failed to enable Error: namespace1.2: failed to enable failed to create namespace: No such device or address And existing zero sized namespace will be marked disabled. root@ltczz75-lp2:/home/kvaneesh# ndctl list -N -r region1 -i [ { "dev":"namespace1.0", "mode":"raw", "size":18874368, "uuid":"94a90fb0-8e78-4fb6-a759-ffc62f9fa181", "sector_size":512, "state":"disabled" }, Signed-off-by: Aneesh Kumar K.V <[email protected]> Reviewed-by: Jeff Moyer <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dave Jiang <[email protected]>
1 parent fd774e3 commit e96d9a9

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

drivers/nvdimm/pfn_devs.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,9 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
452452
u64 checksum, offset;
453453
struct resource *res;
454454
enum nd_pfn_mode mode;
455+
resource_size_t res_size;
455456
struct nd_namespace_io *nsio;
456-
unsigned long align, start_pad;
457+
unsigned long align, start_pad, end_trunc;
457458
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
458459
struct nd_namespace_common *ndns = nd_pfn->ndns;
459460
const uuid_t *parent_uuid = nd_dev_to_uuid(&ndns->dev);
@@ -503,6 +504,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
503504
align = le32_to_cpu(pfn_sb->align);
504505
offset = le64_to_cpu(pfn_sb->dataoff);
505506
start_pad = le32_to_cpu(pfn_sb->start_pad);
507+
end_trunc = le32_to_cpu(pfn_sb->end_trunc);
506508
if (align == 0)
507509
align = 1UL << ilog2(offset);
508510
mode = le32_to_cpu(pfn_sb->mode);
@@ -584,7 +586,8 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
584586
*/
585587
nsio = to_nd_namespace_io(&ndns->dev);
586588
res = &nsio->res;
587-
if (offset >= resource_size(res)) {
589+
res_size = resource_size(res);
590+
if (offset >= res_size) {
588591
dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n",
589592
dev_name(&ndns->dev));
590593
return -EOPNOTSUPP;
@@ -610,6 +613,10 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
610613
return -EOPNOTSUPP;
611614
}
612615

616+
if (offset >= (res_size - start_pad - end_trunc)) {
617+
dev_err(&nd_pfn->dev, "bad offset with small namespace\n");
618+
return -EOPNOTSUPP;
619+
}
613620
return 0;
614621
}
615622
EXPORT_SYMBOL(nd_pfn_validate);
@@ -810,7 +817,8 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
810817
else
811818
return -ENXIO;
812819

813-
if (offset >= size) {
820+
if (offset >= (size - end_trunc)) {
821+
/* This results in zero size devices */
814822
dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
815823
dev_name(&ndns->dev));
816824
return -ENXIO;

0 commit comments

Comments
 (0)