Skip to content

Commit b5a3ae1

Browse files
Yisheng XieZhengShunQian
authored andcommitted
mm/mempolicy: fix the check of nodemask from user
[ Upstream commit 56521e7 ] As Xiaojun reported the ltp of migrate_pages01 will fail on arm64 system which has 4 nodes[0...3], all have memory and CONFIG_NODES_SHIFT=2: migrate_pages01 0 TINFO : test_invalid_nodes migrate_pages01 14 TFAIL : migrate_pages_common.c:45: unexpected failure - returned value = 0, expected: -1 migrate_pages01 15 TFAIL : migrate_pages_common.c:55: call succeeded unexpectedly In this case the test_invalid_nodes of migrate_pages01 will call: SYSC_migrate_pages as: migrate_pages(0, , {0x0000000000000001}, 64, , {0x0000000000000010}, 64) = 0 The new nodes specifies one or more node IDs that are greater than the maximum supported node ID, however, the errno is not set to EINVAL as expected. As man pages of set_mempolicy[1], mbind[2], and migrate_pages[3] mentioned, when nodemask specifies one or more node IDs that are greater than the maximum supported node ID, the errno should set to EINVAL. However, get_nodes only check whether the part of bits [BITS_PER_LONG*BITS_TO_LONGS(MAX_NUMNODES), maxnode) is zero or not, and remain [MAX_NUMNODES, BITS_PER_LONG*BITS_TO_LONGS(MAX_NUMNODES) unchecked. This patch is to check the bits of [MAX_NUMNODES, maxnode) in get_nodes to let migrate_pages set the errno to EINVAL when nodemask specifies one or more node IDs that are greater than the maximum supported node ID, which follows the manpage's guide. [1] http://man7.org/linux/man-pages/man2/set_mempolicy.2.html [2] http://man7.org/linux/man-pages/man2/mbind.2.html [3] http://man7.org/linux/man-pages/man2/migrate_pages.2.html Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Yisheng Xie <[email protected]> Reported-by: Tan Xiaojun <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Chris Salls <[email protected]> Cc: Christopher Lameter <[email protected]> Cc: David Rientjes <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Naoya Horiguchi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 77e5348 commit b5a3ae1

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

mm/mempolicy.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12331233
unsigned long maxnode)
12341234
{
12351235
unsigned long k;
1236+
unsigned long t;
12361237
unsigned long nlongs;
12371238
unsigned long endmask;
12381239

@@ -1249,13 +1250,19 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12491250
else
12501251
endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1;
12511252

1252-
/* When the user specified more nodes than supported just check
1253-
if the non supported part is all zero. */
1253+
/*
1254+
* When the user specified more nodes than supported just check
1255+
* if the non supported part is all zero.
1256+
*
1257+
* If maxnode have more longs than MAX_NUMNODES, check
1258+
* the bits in that area first. And then go through to
1259+
* check the rest bits which equal or bigger than MAX_NUMNODES.
1260+
* Otherwise, just check bits [MAX_NUMNODES, maxnode).
1261+
*/
12541262
if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) {
12551263
if (nlongs > PAGE_SIZE/sizeof(long))
12561264
return -EINVAL;
12571265
for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) {
1258-
unsigned long t;
12591266
if (get_user(t, nmask + k))
12601267
return -EFAULT;
12611268
if (k == nlongs - 1) {
@@ -1268,6 +1275,16 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12681275
endmask = ~0UL;
12691276
}
12701277

1278+
if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) {
1279+
unsigned long valid_mask = endmask;
1280+
1281+
valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1);
1282+
if (get_user(t, nmask + nlongs - 1))
1283+
return -EFAULT;
1284+
if (t & valid_mask)
1285+
return -EINVAL;
1286+
}
1287+
12711288
if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long)))
12721289
return -EFAULT;
12731290
nodes_addr(*nodes)[nlongs-1] &= endmask;

0 commit comments

Comments
 (0)