2019-05-19 20:08:55 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2008-08-31 23:13:54 +08:00
|
|
|
/*
|
|
|
|
* Helpers for formatting and printing strings
|
|
|
|
*
|
|
|
|
* Copyright 31 August 2008 James Bottomley
|
2013-05-01 06:27:30 +08:00
|
|
|
* Copyright (C) 2013, Intel Corporation
|
2008-08-31 23:13:54 +08:00
|
|
|
*/
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
#include <linux/bug.h>
|
2008-08-31 23:13:54 +08:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/math64.h>
|
2011-11-17 10:29:17 +08:00
|
|
|
#include <linux/export.h>
|
2013-05-01 06:27:30 +08:00
|
|
|
#include <linux/ctype.h>
|
2021-11-05 20:42:25 +08:00
|
|
|
#include <linux/device.h>
|
2014-10-14 06:55:16 +08:00
|
|
|
#include <linux/errno.h>
|
2016-04-21 06:46:25 +08:00
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/limits.h>
|
2016-04-21 06:46:24 +08:00
|
|
|
#include <linux/mm.h>
|
2016-04-21 06:46:23 +08:00
|
|
|
#include <linux/slab.h>
|
2014-10-14 06:55:16 +08:00
|
|
|
#include <linux/string.h>
|
2008-08-31 23:13:54 +08:00
|
|
|
#include <linux/string_helpers.h>
|
2023-04-08 03:27:14 +08:00
|
|
|
#include <kunit/test.h>
|
|
|
|
#include <kunit/test-bug.h>
|
2008-08-31 23:13:54 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* string_get_size - get the size in the specified units
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
* @size: The size to be converted in blocks
|
|
|
|
* @blk_size: Size of the block (use 1 for size in bytes)
|
2024-03-01 04:52:30 +08:00
|
|
|
* @units: Units to use (powers of 1000 or 1024), whether to include space separator
|
2008-08-31 23:13:54 +08:00
|
|
|
* @buf: buffer to format to
|
|
|
|
* @len: length of buffer
|
|
|
|
*
|
|
|
|
* This function returns a string formatted to 3 significant figures
|
2015-02-13 07:01:50 +08:00
|
|
|
* giving the size in the required units. @buf should have room for
|
|
|
|
* at least 9 bytes and will always be zero terminated.
|
2008-08-31 23:13:54 +08:00
|
|
|
*
|
2022-04-26 03:26:28 +08:00
|
|
|
* Return value: number of characters of output that would have been written
|
|
|
|
* (which may be greater than len, if output was truncated).
|
2008-08-31 23:13:54 +08:00
|
|
|
*/
|
2022-04-26 03:26:28 +08:00
|
|
|
int string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
|
|
|
|
char *buf, int len)
|
2008-08-31 23:13:54 +08:00
|
|
|
{
|
2024-03-01 04:52:30 +08:00
|
|
|
enum string_size_units units_base = units & STRING_UNITS_MASK;
|
2014-08-07 07:09:31 +08:00
|
|
|
static const char *const units_10[] = {
|
2024-03-01 04:52:30 +08:00
|
|
|
"", "k", "M", "G", "T", "P", "E", "Z", "Y",
|
2014-08-07 07:09:31 +08:00
|
|
|
};
|
|
|
|
static const char *const units_2[] = {
|
2024-03-01 04:52:30 +08:00
|
|
|
"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi",
|
2014-08-07 07:09:31 +08:00
|
|
|
};
|
|
|
|
static const char *const *const units_str[] = {
|
|
|
|
[STRING_UNITS_10] = units_10,
|
2008-08-31 23:13:54 +08:00
|
|
|
[STRING_UNITS_2] = units_2,
|
|
|
|
};
|
2012-05-30 06:07:32 +08:00
|
|
|
static const unsigned int divisor[] = {
|
2008-08-31 23:13:54 +08:00
|
|
|
[STRING_UNITS_10] = 1000,
|
|
|
|
[STRING_UNITS_2] = 1024,
|
|
|
|
};
|
2016-01-21 06:58:29 +08:00
|
|
|
static const unsigned int rounding[] = { 500, 50, 5 };
|
|
|
|
int i = 0, j;
|
|
|
|
u32 remainder = 0, sf_cap;
|
2008-08-31 23:13:54 +08:00
|
|
|
char tmp[8];
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
const char *unit;
|
2008-08-31 23:13:54 +08:00
|
|
|
|
|
|
|
tmp[0] = '\0';
|
2016-01-21 06:58:29 +08:00
|
|
|
|
|
|
|
if (blk_size == 0)
|
|
|
|
size = 0;
|
|
|
|
if (size == 0)
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
goto out;
|
2008-08-31 23:13:54 +08:00
|
|
|
|
2016-01-21 06:58:29 +08:00
|
|
|
/* This is Napier's algorithm. Reduce the original block size to
|
|
|
|
*
|
2024-03-01 04:52:30 +08:00
|
|
|
* coefficient * divisor[units_base]^i
|
2016-01-21 06:58:29 +08:00
|
|
|
*
|
|
|
|
* we do the reduction so both coefficients are just under 32 bits so
|
|
|
|
* that multiplying them together won't overflow 64 bits and we keep
|
|
|
|
* as much precision as possible in the numbers.
|
|
|
|
*
|
|
|
|
* Note: it's safe to throw away the remainders here because all the
|
|
|
|
* precision is in the coefficients.
|
|
|
|
*/
|
|
|
|
while (blk_size >> 32) {
|
2024-03-01 04:52:30 +08:00
|
|
|
do_div(blk_size, divisor[units_base]);
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2016-01-21 06:58:29 +08:00
|
|
|
while (size >> 32) {
|
2024-03-01 04:52:30 +08:00
|
|
|
do_div(size, divisor[units_base]);
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2016-01-21 06:58:29 +08:00
|
|
|
/* now perform the actual multiplication keeping i as the sum of the
|
|
|
|
* two logarithms */
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
size *= blk_size;
|
2008-08-31 23:13:54 +08:00
|
|
|
|
2016-01-21 06:58:29 +08:00
|
|
|
/* and logarithmically reduce it until it's just under the divisor */
|
2024-03-01 04:52:30 +08:00
|
|
|
while (size >= divisor[units_base]) {
|
|
|
|
remainder = do_div(size, divisor[units_base]);
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
i++;
|
2008-08-31 23:13:54 +08:00
|
|
|
}
|
|
|
|
|
2016-01-21 06:58:29 +08:00
|
|
|
/* work out in j how many digits of precision we need from the
|
|
|
|
* remainder */
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
sf_cap = size;
|
|
|
|
for (j = 0; sf_cap*10 < 1000; j++)
|
|
|
|
sf_cap *= 10;
|
|
|
|
|
2024-03-01 04:52:30 +08:00
|
|
|
if (units_base == STRING_UNITS_2) {
|
2016-01-21 06:58:29 +08:00
|
|
|
/* express the remainder as a decimal. It's currently the
|
|
|
|
* numerator of a fraction whose denominator is
|
2024-03-01 04:52:30 +08:00
|
|
|
* divisor[units_base], which is 1 << 10 for STRING_UNITS_2 */
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
remainder *= 1000;
|
2016-01-21 06:58:29 +08:00
|
|
|
remainder >>= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add a 5 to the digit below what will be printed to ensure
|
|
|
|
* an arithmetical round up and carry it through to size */
|
|
|
|
remainder += rounding[j];
|
|
|
|
if (remainder >= 1000) {
|
|
|
|
remainder -= 1000;
|
|
|
|
size += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j) {
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
snprintf(tmp, sizeof(tmp), ".%03u", remainder);
|
|
|
|
tmp[j+1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (i >= ARRAY_SIZE(units_2))
|
|
|
|
unit = "UNK";
|
|
|
|
else
|
2024-03-01 04:52:30 +08:00
|
|
|
unit = units_str[units_base][i];
|
sd, mmc, virtio_blk, string_helpers: fix block size units
The current string_get_size() overflows when the device size goes over
2^64 bytes because the string helper routine computes the suffix from
the size in bytes. However, the entirety of Linux thinks in terms of
blocks, not bytes, so this will artificially induce an overflow on very
large devices. Fix this by making the function string_get_size() take
blocks and the block size instead of bytes. This should allow us to
keep working until the current SCSI standard overflows.
Also fix virtio_blk and mmc (both of which were also artificially
multiplying by the block size to pass a byte side to string_get_size()).
The mathematics of this is pretty simple: we're taking a product of
size in blocks (S) and block size (B) and trying to re-express this in
exponential form: S*B = R*N^E (where N, the exponent is either 1000 or
1024) and R < N. Mathematically, S = RS*N^ES and B=RB*N^EB, so if RS*RB
< N it's easy to see that S*B = RS*RB*N^(ES+EB). However, if RS*BS > N,
we can see that this can be re-expressed as RS*BS = R*N (where R =
RS*BS/N < N) so the whole exponent becomes R*N^(ES+EB+1)
[jejb: fix incorrect 32 bit do_div spotted by kbuild test robot <fengguang.wu@intel.com>]
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
2015-03-06 10:47:01 +08:00
|
|
|
|
2024-03-01 04:52:30 +08:00
|
|
|
return snprintf(buf, len, "%u%s%s%s%s", (u32)size, tmp,
|
|
|
|
(units & STRING_UNITS_NO_SPACE) ? "" : " ",
|
|
|
|
unit,
|
|
|
|
(units & STRING_UNITS_NO_BYTES) ? "" : "B");
|
2008-08-31 23:13:54 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(string_get_size);
|
2013-05-01 06:27:30 +08:00
|
|
|
|
2022-09-04 18:28:39 +08:00
|
|
|
/**
|
|
|
|
* parse_int_array_user - Split string into a sequence of integers
|
|
|
|
* @from: The user space buffer to read from
|
|
|
|
* @count: The maximum number of bytes to read
|
|
|
|
* @array: Returned pointer to sequence of integers
|
|
|
|
*
|
|
|
|
* On success @array is allocated and initialized with a sequence of
|
|
|
|
* integers extracted from the @from plus an additional element that
|
|
|
|
* begins the sequence and specifies the integers count.
|
|
|
|
*
|
|
|
|
* Caller takes responsibility for freeing @array when it is no longer
|
|
|
|
* needed.
|
|
|
|
*/
|
|
|
|
int parse_int_array_user(const char __user *from, size_t count, int **array)
|
|
|
|
{
|
|
|
|
int *ints, nints;
|
|
|
|
char *buf;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
buf = memdup_user_nul(from, count);
|
|
|
|
if (IS_ERR(buf))
|
|
|
|
return PTR_ERR(buf);
|
|
|
|
|
|
|
|
get_options(buf, 0, &nints);
|
|
|
|
if (!nints) {
|
|
|
|
ret = -ENOENT;
|
|
|
|
goto free_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
ints = kcalloc(nints + 1, sizeof(*ints), GFP_KERNEL);
|
|
|
|
if (!ints) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto free_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
get_options(buf, nints + 1, ints);
|
|
|
|
*array = ints;
|
|
|
|
|
|
|
|
free_buf:
|
|
|
|
kfree(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(parse_int_array_user);
|
|
|
|
|
2013-05-01 06:27:30 +08:00
|
|
|
static bool unescape_space(char **src, char **dst)
|
|
|
|
{
|
|
|
|
char *p = *dst, *q = *src;
|
|
|
|
|
|
|
|
switch (*q) {
|
|
|
|
case 'n':
|
|
|
|
*p = '\n';
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
*p = '\r';
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
*p = '\t';
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
*p = '\v';
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
*p = '\f';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*dst += 1;
|
|
|
|
*src += 1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool unescape_octal(char **src, char **dst)
|
|
|
|
{
|
|
|
|
char *p = *dst, *q = *src;
|
|
|
|
u8 num;
|
|
|
|
|
|
|
|
if (isodigit(*q) == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
num = (*q++) & 7;
|
|
|
|
while (num < 32 && isodigit(*q) && (q - *src < 3)) {
|
|
|
|
num <<= 3;
|
|
|
|
num += (*q++) & 7;
|
|
|
|
}
|
|
|
|
*p = num;
|
|
|
|
*dst += 1;
|
|
|
|
*src = q;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool unescape_hex(char **src, char **dst)
|
|
|
|
{
|
|
|
|
char *p = *dst, *q = *src;
|
|
|
|
int digit;
|
|
|
|
u8 num;
|
|
|
|
|
|
|
|
if (*q++ != 'x')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
num = digit = hex_to_bin(*q++);
|
|
|
|
if (digit < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
digit = hex_to_bin(*q);
|
|
|
|
if (digit >= 0) {
|
|
|
|
q++;
|
|
|
|
num = (num << 4) | digit;
|
|
|
|
}
|
|
|
|
*p = num;
|
|
|
|
*dst += 1;
|
|
|
|
*src = q;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool unescape_special(char **src, char **dst)
|
|
|
|
{
|
|
|
|
char *p = *dst, *q = *src;
|
|
|
|
|
|
|
|
switch (*q) {
|
|
|
|
case '\"':
|
|
|
|
*p = '\"';
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
*p = '\\';
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
*p = '\a';
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
*p = '\e';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*dst += 1;
|
|
|
|
*src += 1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-10-14 06:55:11 +08:00
|
|
|
/**
|
|
|
|
* string_unescape - unquote characters in the given string
|
|
|
|
* @src: source buffer (escaped)
|
|
|
|
* @dst: destination buffer (unescaped)
|
|
|
|
* @size: size of the destination buffer (0 to unlimit)
|
2019-07-17 07:27:36 +08:00
|
|
|
* @flags: combination of the flags.
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* The function unquotes characters in the given string.
|
|
|
|
*
|
|
|
|
* Because the size of the output will be the same as or less than the size of
|
|
|
|
* the input, the transformation may be performed in place.
|
|
|
|
*
|
|
|
|
* Caller must provide valid source and destination pointers. Be aware that
|
|
|
|
* destination buffer will always be NULL-terminated. Source string must be
|
|
|
|
* NULL-terminated as well. The supported flags are::
|
|
|
|
*
|
|
|
|
* UNESCAPE_SPACE:
|
2014-10-14 06:55:11 +08:00
|
|
|
* '\f' - form feed
|
|
|
|
* '\n' - new line
|
|
|
|
* '\r' - carriage return
|
|
|
|
* '\t' - horizontal tab
|
|
|
|
* '\v' - vertical tab
|
2019-07-17 07:27:36 +08:00
|
|
|
* UNESCAPE_OCTAL:
|
2014-10-14 06:55:11 +08:00
|
|
|
* '\NNN' - byte with octal value NNN (1 to 3 digits)
|
2019-07-17 07:27:36 +08:00
|
|
|
* UNESCAPE_HEX:
|
2014-10-14 06:55:11 +08:00
|
|
|
* '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
|
2019-07-17 07:27:36 +08:00
|
|
|
* UNESCAPE_SPECIAL:
|
2014-10-14 06:55:11 +08:00
|
|
|
* '\"' - double quote
|
|
|
|
* '\\' - backslash
|
|
|
|
* '\a' - alert (BEL)
|
|
|
|
* '\e' - escape
|
2019-07-17 07:27:36 +08:00
|
|
|
* UNESCAPE_ANY:
|
2014-10-14 06:55:11 +08:00
|
|
|
* all previous together
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* The amount of the characters processed to the destination buffer excluding
|
|
|
|
* trailing '\0' is returned.
|
|
|
|
*/
|
2013-05-01 06:27:30 +08:00
|
|
|
int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
|
|
|
|
{
|
|
|
|
char *out = dst;
|
|
|
|
|
|
|
|
while (*src && --size) {
|
|
|
|
if (src[0] == '\\' && src[1] != '\0' && size > 1) {
|
|
|
|
src++;
|
|
|
|
size--;
|
|
|
|
|
|
|
|
if (flags & UNESCAPE_SPACE &&
|
|
|
|
unescape_space(&src, &out))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (flags & UNESCAPE_OCTAL &&
|
|
|
|
unescape_octal(&src, &out))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (flags & UNESCAPE_HEX &&
|
|
|
|
unescape_hex(&src, &out))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (flags & UNESCAPE_SPECIAL &&
|
|
|
|
unescape_special(&src, &out))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
*out++ = '\\';
|
|
|
|
}
|
|
|
|
*out++ = *src++;
|
|
|
|
}
|
|
|
|
*out = '\0';
|
|
|
|
|
|
|
|
return out - dst;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(string_unescape);
|
2014-10-14 06:55:16 +08:00
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
static bool escape_passthrough(unsigned char c, char **dst, char *end)
|
2014-10-14 06:55:16 +08:00
|
|
|
{
|
|
|
|
char *out = *dst;
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
if (out < end)
|
|
|
|
*out = c;
|
|
|
|
*dst = out + 1;
|
|
|
|
return true;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
static bool escape_space(unsigned char c, char **dst, char *end)
|
2014-10-14 06:55:16 +08:00
|
|
|
{
|
|
|
|
char *out = *dst;
|
|
|
|
unsigned char to;
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case '\n':
|
|
|
|
to = 'n';
|
|
|
|
break;
|
|
|
|
case '\r':
|
|
|
|
to = 'r';
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
to = 't';
|
|
|
|
break;
|
|
|
|
case '\v':
|
|
|
|
to = 'v';
|
|
|
|
break;
|
|
|
|
case '\f':
|
|
|
|
to = 'f';
|
|
|
|
break;
|
|
|
|
default:
|
2015-04-16 07:17:25 +08:00
|
|
|
return false;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
if (out < end)
|
|
|
|
*out = '\\';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = to;
|
|
|
|
++out;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
*dst = out;
|
|
|
|
return true;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
static bool escape_special(unsigned char c, char **dst, char *end)
|
2014-10-14 06:55:16 +08:00
|
|
|
{
|
|
|
|
char *out = *dst;
|
|
|
|
unsigned char to;
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case '\\':
|
|
|
|
to = '\\';
|
|
|
|
break;
|
|
|
|
case '\a':
|
|
|
|
to = 'a';
|
|
|
|
break;
|
|
|
|
case '\e':
|
|
|
|
to = 'e';
|
|
|
|
break;
|
2021-06-16 00:52:45 +08:00
|
|
|
case '"':
|
|
|
|
to = '"';
|
|
|
|
break;
|
2014-10-14 06:55:16 +08:00
|
|
|
default:
|
2015-04-16 07:17:25 +08:00
|
|
|
return false;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
if (out < end)
|
|
|
|
*out = '\\';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = to;
|
|
|
|
++out;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
*dst = out;
|
|
|
|
return true;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
static bool escape_null(unsigned char c, char **dst, char *end)
|
2014-10-14 06:55:16 +08:00
|
|
|
{
|
|
|
|
char *out = *dst;
|
|
|
|
|
|
|
|
if (c)
|
2015-04-16 07:17:25 +08:00
|
|
|
return false;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
if (out < end)
|
|
|
|
*out = '\\';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = '0';
|
|
|
|
++out;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
*dst = out;
|
|
|
|
return true;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
static bool escape_octal(unsigned char c, char **dst, char *end)
|
2014-10-14 06:55:16 +08:00
|
|
|
{
|
|
|
|
char *out = *dst;
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
if (out < end)
|
|
|
|
*out = '\\';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = ((c >> 6) & 0x07) + '0';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = ((c >> 3) & 0x07) + '0';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = ((c >> 0) & 0x07) + '0';
|
|
|
|
++out;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
|
|
|
*dst = out;
|
2015-04-16 07:17:25 +08:00
|
|
|
return true;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
static bool escape_hex(unsigned char c, char **dst, char *end)
|
2014-10-14 06:55:16 +08:00
|
|
|
{
|
|
|
|
char *out = *dst;
|
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
if (out < end)
|
|
|
|
*out = '\\';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = 'x';
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = hex_asc_hi(c);
|
|
|
|
++out;
|
|
|
|
if (out < end)
|
|
|
|
*out = hex_asc_lo(c);
|
|
|
|
++out;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
|
|
|
*dst = out;
|
2015-04-16 07:17:25 +08:00
|
|
|
return true;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* string_escape_mem - quote characters in the given memory buffer
|
|
|
|
* @src: source buffer (unescaped)
|
|
|
|
* @isz: source buffer size
|
|
|
|
* @dst: destination buffer (escaped)
|
|
|
|
* @osz: destination buffer size
|
2019-07-17 07:27:36 +08:00
|
|
|
* @flags: combination of the flags
|
|
|
|
* @only: NULL-terminated string containing characters used to limit
|
|
|
|
* the selected escape class. If characters are included in @only
|
|
|
|
* that would not normally be escaped by the classes selected
|
|
|
|
* in @flags, they will be copied to @dst unescaped.
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* The process of escaping byte buffer includes several parts. They are applied
|
|
|
|
* in the following sequence.
|
|
|
|
*
|
2021-07-01 09:55:08 +08:00
|
|
|
* 1. The character is not matched to the one from @only string and thus
|
2019-07-17 07:27:36 +08:00
|
|
|
* must go as-is to the output.
|
2021-07-01 09:55:17 +08:00
|
|
|
* 2. The character is matched to the printable and ASCII classes, if asked,
|
2021-07-01 09:55:14 +08:00
|
|
|
* and in case of match it passes through to the output.
|
2021-07-01 09:55:17 +08:00
|
|
|
* 3. The character is matched to the printable or ASCII class, if asked,
|
|
|
|
* and in case of match it passes through to the output.
|
|
|
|
* 4. The character is checked if it falls into the class given by @flags.
|
2019-07-17 07:27:36 +08:00
|
|
|
* %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
|
|
|
|
* character. Note that they actually can't go together, otherwise
|
|
|
|
* %ESCAPE_HEX will be ignored.
|
|
|
|
*
|
|
|
|
* Caller must provide valid source and destination pointers. Be aware that
|
|
|
|
* destination buffer will not be NULL-terminated, thus caller have to append
|
2021-07-01 09:55:14 +08:00
|
|
|
* it if needs. The supported flags are::
|
2019-07-17 07:27:36 +08:00
|
|
|
*
|
2015-09-10 06:37:14 +08:00
|
|
|
* %ESCAPE_SPACE: (special white space, not space itself)
|
2014-10-14 06:55:16 +08:00
|
|
|
* '\f' - form feed
|
|
|
|
* '\n' - new line
|
|
|
|
* '\r' - carriage return
|
|
|
|
* '\t' - horizontal tab
|
|
|
|
* '\v' - vertical tab
|
|
|
|
* %ESCAPE_SPECIAL:
|
2021-06-16 00:52:45 +08:00
|
|
|
* '\"' - double quote
|
2014-10-14 06:55:16 +08:00
|
|
|
* '\\' - backslash
|
|
|
|
* '\a' - alert (BEL)
|
|
|
|
* '\e' - escape
|
|
|
|
* %ESCAPE_NULL:
|
|
|
|
* '\0' - null
|
|
|
|
* %ESCAPE_OCTAL:
|
|
|
|
* '\NNN' - byte with octal value NNN (3 digits)
|
|
|
|
* %ESCAPE_ANY:
|
|
|
|
* all previous together
|
|
|
|
* %ESCAPE_NP:
|
2021-07-01 09:55:14 +08:00
|
|
|
* escape only non-printable characters, checked by isprint()
|
2014-10-14 06:55:16 +08:00
|
|
|
* %ESCAPE_ANY_NP:
|
|
|
|
* all previous together
|
|
|
|
* %ESCAPE_HEX:
|
|
|
|
* '\xHH' - byte with hexadecimal value HH (2 digits)
|
2021-07-01 09:55:14 +08:00
|
|
|
* %ESCAPE_NA:
|
|
|
|
* escape only non-ascii characters, checked by isascii()
|
2021-07-01 09:55:17 +08:00
|
|
|
* %ESCAPE_NAP:
|
|
|
|
* escape only non-printable or non-ascii characters
|
2021-07-01 09:55:20 +08:00
|
|
|
* %ESCAPE_APPEND:
|
|
|
|
* append characters from @only to be escaped by the given classes
|
|
|
|
*
|
|
|
|
* %ESCAPE_APPEND would help to pass additional characters to the escaped, when
|
|
|
|
* one of %ESCAPE_NP, %ESCAPE_NA, or %ESCAPE_NAP is provided.
|
2021-07-01 09:55:14 +08:00
|
|
|
*
|
2021-07-01 09:55:17 +08:00
|
|
|
* One notable caveat, the %ESCAPE_NAP, %ESCAPE_NP and %ESCAPE_NA have the
|
|
|
|
* higher priority than the rest of the flags (%ESCAPE_NAP is the highest).
|
2021-07-01 09:55:14 +08:00
|
|
|
* It doesn't make much sense to use either of them without %ESCAPE_OCTAL
|
|
|
|
* or %ESCAPE_HEX, because they cover most of the other character classes.
|
2021-07-01 09:55:17 +08:00
|
|
|
* %ESCAPE_NAP can utilize %ESCAPE_SPACE or %ESCAPE_SPECIAL in addition to
|
|
|
|
* the above.
|
2014-10-14 06:55:16 +08:00
|
|
|
*
|
|
|
|
* Return:
|
lib/string_helpers.c: change semantics of string_escape_mem
The current semantics of string_escape_mem are inadequate for one of its
current users, vsnprintf(). If that is to honour its contract, it must
know how much space would be needed for the entire escaped buffer, and
string_escape_mem provides no way of obtaining that (short of allocating a
large enough buffer (~4 times input string) to let it play with, and
that's definitely a big no-no inside vsnprintf).
So change the semantics for string_escape_mem to be more snprintf-like:
Return the size of the output that would be generated if the destination
buffer was big enough, but of course still only write to the part of dst
it is allowed to, and (contrary to snprintf) don't do '\0'-termination.
It is then up to the caller to detect whether output was truncated and to
append a '\0' if desired. Also, we must output partial escape sequences,
otherwise a call such as snprintf(buf, 3, "%1pE", "\123") would cause
printf to write a \0 to buf[2] but leaving buf[0] and buf[1] with whatever
they previously contained.
This also fixes a bug in the escaped_string() helper function, which used
to unconditionally pass a length of "end-buf" to string_escape_mem();
since the latter doesn't check osz for being insanely large, it would
happily write to dst. For example, kasprintf(GFP_KERNEL, "something and
then %pE", ...); is an easy way to trigger an oops.
In test-string_helpers.c, the -ENOMEM test is replaced with testing for
getting the expected return value even if the buffer is too small. We
also ensure that nothing is written (by relying on a NULL pointer deref)
if the output size is 0 by passing NULL - this has to work for
kasprintf("%pE") to work.
In net/sunrpc/cache.c, I think qword_add still has the same semantics.
Someone should definitely double-check this.
In fs/proc/array.c, I made the minimum possible change, but longer-term it
should stop poking around in seq_file internals.
[andriy.shevchenko@linux.intel.com: simplify qword_add]
[andriy.shevchenko@linux.intel.com: add missed curly braces]
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-04-16 07:17:28 +08:00
|
|
|
* The total size of the escaped output that would be generated for
|
|
|
|
* the given input and flags. To check whether the output was
|
|
|
|
* truncated, compare the return value to osz. There is room left in
|
|
|
|
* dst for a '\0' terminator if and only if ret < osz.
|
2014-10-14 06:55:16 +08:00
|
|
|
*/
|
lib/string_helpers.c: change semantics of string_escape_mem
The current semantics of string_escape_mem are inadequate for one of its
current users, vsnprintf(). If that is to honour its contract, it must
know how much space would be needed for the entire escaped buffer, and
string_escape_mem provides no way of obtaining that (short of allocating a
large enough buffer (~4 times input string) to let it play with, and
that's definitely a big no-no inside vsnprintf).
So change the semantics for string_escape_mem to be more snprintf-like:
Return the size of the output that would be generated if the destination
buffer was big enough, but of course still only write to the part of dst
it is allowed to, and (contrary to snprintf) don't do '\0'-termination.
It is then up to the caller to detect whether output was truncated and to
append a '\0' if desired. Also, we must output partial escape sequences,
otherwise a call such as snprintf(buf, 3, "%1pE", "\123") would cause
printf to write a \0 to buf[2] but leaving buf[0] and buf[1] with whatever
they previously contained.
This also fixes a bug in the escaped_string() helper function, which used
to unconditionally pass a length of "end-buf" to string_escape_mem();
since the latter doesn't check osz for being insanely large, it would
happily write to dst. For example, kasprintf(GFP_KERNEL, "something and
then %pE", ...); is an easy way to trigger an oops.
In test-string_helpers.c, the -ENOMEM test is replaced with testing for
getting the expected return value even if the buffer is too small. We
also ensure that nothing is written (by relying on a NULL pointer deref)
if the output size is 0 by passing NULL - this has to work for
kasprintf("%pE") to work.
In net/sunrpc/cache.c, I think qword_add still has the same semantics.
Someone should definitely double-check this.
In fs/proc/array.c, I made the minimum possible change, but longer-term it
should stop poking around in seq_file internals.
[andriy.shevchenko@linux.intel.com: simplify qword_add]
[andriy.shevchenko@linux.intel.com: add missed curly braces]
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-04-16 07:17:28 +08:00
|
|
|
int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
|
2015-09-10 06:37:16 +08:00
|
|
|
unsigned int flags, const char *only)
|
2014-10-14 06:55:16 +08:00
|
|
|
{
|
lib/string_helpers.c: change semantics of string_escape_mem
The current semantics of string_escape_mem are inadequate for one of its
current users, vsnprintf(). If that is to honour its contract, it must
know how much space would be needed for the entire escaped buffer, and
string_escape_mem provides no way of obtaining that (short of allocating a
large enough buffer (~4 times input string) to let it play with, and
that's definitely a big no-no inside vsnprintf).
So change the semantics for string_escape_mem to be more snprintf-like:
Return the size of the output that would be generated if the destination
buffer was big enough, but of course still only write to the part of dst
it is allowed to, and (contrary to snprintf) don't do '\0'-termination.
It is then up to the caller to detect whether output was truncated and to
append a '\0' if desired. Also, we must output partial escape sequences,
otherwise a call such as snprintf(buf, 3, "%1pE", "\123") would cause
printf to write a \0 to buf[2] but leaving buf[0] and buf[1] with whatever
they previously contained.
This also fixes a bug in the escaped_string() helper function, which used
to unconditionally pass a length of "end-buf" to string_escape_mem();
since the latter doesn't check osz for being insanely large, it would
happily write to dst. For example, kasprintf(GFP_KERNEL, "something and
then %pE", ...); is an easy way to trigger an oops.
In test-string_helpers.c, the -ENOMEM test is replaced with testing for
getting the expected return value even if the buffer is too small. We
also ensure that nothing is written (by relying on a NULL pointer deref)
if the output size is 0 by passing NULL - this has to work for
kasprintf("%pE") to work.
In net/sunrpc/cache.c, I think qword_add still has the same semantics.
Someone should definitely double-check this.
In fs/proc/array.c, I made the minimum possible change, but longer-term it
should stop poking around in seq_file internals.
[andriy.shevchenko@linux.intel.com: simplify qword_add]
[andriy.shevchenko@linux.intel.com: add missed curly braces]
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-04-16 07:17:28 +08:00
|
|
|
char *p = dst;
|
2015-04-16 07:17:25 +08:00
|
|
|
char *end = p + osz;
|
2015-09-10 06:37:16 +08:00
|
|
|
bool is_dict = only && *only;
|
2021-07-01 09:55:20 +08:00
|
|
|
bool is_append = flags & ESCAPE_APPEND;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
|
|
|
while (isz--) {
|
|
|
|
unsigned char c = *src++;
|
2021-07-01 09:55:20 +08:00
|
|
|
bool in_dict = is_dict && strchr(only, c);
|
2014-10-14 06:55:16 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply rules in the following sequence:
|
2015-09-10 06:37:16 +08:00
|
|
|
* - the @only string is supplied and does not contain a
|
2014-10-14 06:55:16 +08:00
|
|
|
* character under question
|
2021-07-01 09:55:17 +08:00
|
|
|
* - the character is printable and ASCII, when @flags has
|
|
|
|
* %ESCAPE_NAP bit set
|
2021-07-01 09:55:08 +08:00
|
|
|
* - the character is printable, when @flags has
|
|
|
|
* %ESCAPE_NP bit set
|
2021-07-01 09:55:14 +08:00
|
|
|
* - the character is ASCII, when @flags has
|
|
|
|
* %ESCAPE_NA bit set
|
2014-10-14 06:55:16 +08:00
|
|
|
* - the character doesn't fall into a class of symbols
|
|
|
|
* defined by given @flags
|
|
|
|
* In these cases we just pass through a character to the
|
|
|
|
* output buffer.
|
2021-07-01 09:55:20 +08:00
|
|
|
*
|
|
|
|
* When %ESCAPE_APPEND is passed, the characters from @only
|
|
|
|
* have been excluded from the %ESCAPE_NAP, %ESCAPE_NP, and
|
|
|
|
* %ESCAPE_NA cases.
|
2014-10-14 06:55:16 +08:00
|
|
|
*/
|
2021-07-01 09:55:20 +08:00
|
|
|
if (!(is_append || in_dict) && is_dict &&
|
2021-07-01 09:55:11 +08:00
|
|
|
escape_passthrough(c, &p, end))
|
|
|
|
continue;
|
2021-07-01 09:55:08 +08:00
|
|
|
|
2021-07-01 09:55:20 +08:00
|
|
|
if (!(is_append && in_dict) && isascii(c) && isprint(c) &&
|
2021-07-01 09:55:17 +08:00
|
|
|
flags & ESCAPE_NAP && escape_passthrough(c, &p, end))
|
|
|
|
continue;
|
|
|
|
|
2021-07-01 09:55:20 +08:00
|
|
|
if (!(is_append && in_dict) && isprint(c) &&
|
2021-07-01 09:55:11 +08:00
|
|
|
flags & ESCAPE_NP && escape_passthrough(c, &p, end))
|
|
|
|
continue;
|
2015-04-16 07:17:25 +08:00
|
|
|
|
2021-07-01 09:55:20 +08:00
|
|
|
if (!(is_append && in_dict) && isascii(c) &&
|
2021-07-01 09:55:14 +08:00
|
|
|
flags & ESCAPE_NA && escape_passthrough(c, &p, end))
|
|
|
|
continue;
|
|
|
|
|
2021-07-01 09:55:11 +08:00
|
|
|
if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
|
|
|
|
continue;
|
2015-04-16 07:17:25 +08:00
|
|
|
|
2021-07-01 09:55:11 +08:00
|
|
|
if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
|
|
|
|
continue;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
2021-07-01 09:55:11 +08:00
|
|
|
if (flags & ESCAPE_NULL && escape_null(c, &p, end))
|
|
|
|
continue;
|
2015-04-16 07:17:25 +08:00
|
|
|
|
2021-07-01 09:55:11 +08:00
|
|
|
/* ESCAPE_OCTAL and ESCAPE_HEX always go last */
|
|
|
|
if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
|
|
|
|
continue;
|
2014-10-14 06:55:16 +08:00
|
|
|
|
2015-04-16 07:17:25 +08:00
|
|
|
escape_passthrough(c, &p, end);
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
lib/string_helpers.c: change semantics of string_escape_mem
The current semantics of string_escape_mem are inadequate for one of its
current users, vsnprintf(). If that is to honour its contract, it must
know how much space would be needed for the entire escaped buffer, and
string_escape_mem provides no way of obtaining that (short of allocating a
large enough buffer (~4 times input string) to let it play with, and
that's definitely a big no-no inside vsnprintf).
So change the semantics for string_escape_mem to be more snprintf-like:
Return the size of the output that would be generated if the destination
buffer was big enough, but of course still only write to the part of dst
it is allowed to, and (contrary to snprintf) don't do '\0'-termination.
It is then up to the caller to detect whether output was truncated and to
append a '\0' if desired. Also, we must output partial escape sequences,
otherwise a call such as snprintf(buf, 3, "%1pE", "\123") would cause
printf to write a \0 to buf[2] but leaving buf[0] and buf[1] with whatever
they previously contained.
This also fixes a bug in the escaped_string() helper function, which used
to unconditionally pass a length of "end-buf" to string_escape_mem();
since the latter doesn't check osz for being insanely large, it would
happily write to dst. For example, kasprintf(GFP_KERNEL, "something and
then %pE", ...); is an easy way to trigger an oops.
In test-string_helpers.c, the -ENOMEM test is replaced with testing for
getting the expected return value even if the buffer is too small. We
also ensure that nothing is written (by relying on a NULL pointer deref)
if the output size is 0 by passing NULL - this has to work for
kasprintf("%pE") to work.
In net/sunrpc/cache.c, I think qword_add still has the same semantics.
Someone should definitely double-check this.
In fs/proc/array.c, I made the minimum possible change, but longer-term it
should stop poking around in seq_file internals.
[andriy.shevchenko@linux.intel.com: simplify qword_add]
[andriy.shevchenko@linux.intel.com: add missed curly braces]
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-04-16 07:17:28 +08:00
|
|
|
return p - dst;
|
2014-10-14 06:55:16 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(string_escape_mem);
|
2016-04-21 06:46:23 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Return an allocated string that has been escaped of special characters
|
|
|
|
* and double quotes, making it safe to log in quotes.
|
|
|
|
*/
|
|
|
|
char *kstrdup_quotable(const char *src, gfp_t gfp)
|
|
|
|
{
|
|
|
|
size_t slen, dlen;
|
|
|
|
char *dst;
|
|
|
|
const int flags = ESCAPE_HEX;
|
|
|
|
const char esc[] = "\f\n\r\t\v\a\e\\\"";
|
|
|
|
|
|
|
|
if (!src)
|
|
|
|
return NULL;
|
|
|
|
slen = strlen(src);
|
|
|
|
|
|
|
|
dlen = string_escape_mem(src, slen, NULL, 0, flags, esc);
|
|
|
|
dst = kmalloc(dlen + 1, gfp);
|
|
|
|
if (!dst)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen);
|
|
|
|
dst[dlen] = '\0';
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(kstrdup_quotable);
|
2016-04-21 06:46:24 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns allocated NULL-terminated string containing process
|
|
|
|
* command line, with inter-argument NULLs replaced with spaces,
|
|
|
|
* and other special characters escaped.
|
|
|
|
*/
|
|
|
|
char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp)
|
|
|
|
{
|
|
|
|
char *buffer, *quoted;
|
|
|
|
int i, res;
|
|
|
|
|
2017-09-14 07:28:29 +08:00
|
|
|
buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
2016-04-21 06:46:24 +08:00
|
|
|
if (!buffer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
res = get_cmdline(task, buffer, PAGE_SIZE - 1);
|
|
|
|
buffer[res] = '\0';
|
|
|
|
|
|
|
|
/* Collapse trailing NULLs, leave res pointing to last non-NULL. */
|
|
|
|
while (--res >= 0 && buffer[res] == '\0')
|
|
|
|
;
|
|
|
|
|
|
|
|
/* Replace inter-argument NULLs. */
|
|
|
|
for (i = 0; i <= res; i++)
|
|
|
|
if (buffer[i] == '\0')
|
|
|
|
buffer[i] = ' ';
|
|
|
|
|
|
|
|
/* Make sure result is printable. */
|
|
|
|
quoted = kstrdup_quotable(buffer, gfp);
|
|
|
|
kfree(buffer);
|
|
|
|
return quoted;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(kstrdup_quotable_cmdline);
|
2016-04-21 06:46:25 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns allocated NULL-terminated string containing pathname,
|
|
|
|
* with special characters escaped, able to be safely logged. If
|
|
|
|
* there is an error, the leading character will be "<".
|
|
|
|
*/
|
|
|
|
char *kstrdup_quotable_file(struct file *file, gfp_t gfp)
|
|
|
|
{
|
|
|
|
char *temp, *pathname;
|
|
|
|
|
|
|
|
if (!file)
|
|
|
|
return kstrdup("<unknown>", gfp);
|
|
|
|
|
|
|
|
/* We add 11 spaces for ' (deleted)' to be appended */
|
2017-09-14 07:28:29 +08:00
|
|
|
temp = kmalloc(PATH_MAX + 11, GFP_KERNEL);
|
2016-04-21 06:46:25 +08:00
|
|
|
if (!temp)
|
|
|
|
return kstrdup("<no_memory>", gfp);
|
|
|
|
|
|
|
|
pathname = file_path(file, temp, PATH_MAX + 11);
|
|
|
|
if (IS_ERR(pathname))
|
|
|
|
pathname = kstrdup("<too_long>", gfp);
|
|
|
|
else
|
|
|
|
pathname = kstrdup_quotable(pathname, gfp);
|
|
|
|
|
|
|
|
kfree(temp);
|
|
|
|
return pathname;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(kstrdup_quotable_file);
|
2020-09-29 18:09:55 +08:00
|
|
|
|
2023-08-04 22:39:07 +08:00
|
|
|
/*
|
|
|
|
* Returns duplicate string in which the @old characters are replaced by @new.
|
|
|
|
*/
|
|
|
|
char *kstrdup_and_replace(const char *src, char old, char new, gfp_t gfp)
|
|
|
|
{
|
|
|
|
char *dst;
|
|
|
|
|
|
|
|
dst = kstrdup(src, gfp);
|
|
|
|
if (!dst)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return strreplace(dst, old, new);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(kstrdup_and_replace);
|
|
|
|
|
2021-11-05 20:42:24 +08:00
|
|
|
/**
|
|
|
|
* kasprintf_strarray - allocate and fill array of sequential strings
|
|
|
|
* @gfp: flags for the slab allocator
|
|
|
|
* @prefix: prefix to be used
|
|
|
|
* @n: amount of lines to be allocated and filled
|
|
|
|
*
|
|
|
|
* Allocates and fills @n strings using pattern "%s-%zu", where prefix
|
|
|
|
* is provided by caller. The caller is responsible to free them with
|
|
|
|
* kfree_strarray() after use.
|
|
|
|
*
|
|
|
|
* Returns array of strings or NULL when memory can't be allocated.
|
|
|
|
*/
|
|
|
|
char **kasprintf_strarray(gfp_t gfp, const char *prefix, size_t n)
|
|
|
|
{
|
|
|
|
char **names;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
names = kcalloc(n + 1, sizeof(char *), gfp);
|
|
|
|
if (!names)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
names[i] = kasprintf(gfp, "%s-%zu", prefix, i);
|
|
|
|
if (!names[i]) {
|
|
|
|
kfree_strarray(names, i);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(kasprintf_strarray);
|
|
|
|
|
2020-09-29 18:09:55 +08:00
|
|
|
/**
|
|
|
|
* kfree_strarray - free a number of dynamically allocated strings contained
|
|
|
|
* in an array and the array itself
|
|
|
|
*
|
|
|
|
* @array: Dynamically allocated array of strings to free.
|
|
|
|
* @n: Number of strings (starting from the beginning of the array) to free.
|
|
|
|
*
|
|
|
|
* Passing a non-NULL @array and @n == 0 as well as NULL @array are valid
|
|
|
|
* use-cases. If @array is NULL, the function does nothing.
|
|
|
|
*/
|
|
|
|
void kfree_strarray(char **array, size_t n)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!array)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
kfree(array[i]);
|
|
|
|
kfree(array);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(kfree_strarray);
|
2021-06-19 01:57:38 +08:00
|
|
|
|
2021-11-05 20:42:25 +08:00
|
|
|
struct strarray {
|
|
|
|
char **array;
|
|
|
|
size_t n;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void devm_kfree_strarray(struct device *dev, void *res)
|
|
|
|
{
|
|
|
|
struct strarray *array = res;
|
|
|
|
|
|
|
|
kfree_strarray(array->array, array->n);
|
|
|
|
}
|
|
|
|
|
|
|
|
char **devm_kasprintf_strarray(struct device *dev, const char *prefix, size_t n)
|
|
|
|
{
|
|
|
|
struct strarray *ptr;
|
|
|
|
|
|
|
|
ptr = devres_alloc(devm_kfree_strarray, sizeof(*ptr), GFP_KERNEL);
|
|
|
|
if (!ptr)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
ptr->array = kasprintf_strarray(GFP_KERNEL, prefix, n);
|
|
|
|
if (!ptr->array) {
|
|
|
|
devres_free(ptr);
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
}
|
|
|
|
|
2022-05-13 11:38:36 +08:00
|
|
|
ptr->n = n;
|
|
|
|
devres_add(dev, ptr);
|
|
|
|
|
2021-11-05 20:42:25 +08:00
|
|
|
return ptr->array;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devm_kasprintf_strarray);
|
|
|
|
|
2021-06-19 01:57:38 +08:00
|
|
|
/**
|
|
|
|
* skip_spaces - Removes leading whitespace from @str.
|
|
|
|
* @str: The string to be stripped.
|
|
|
|
*
|
|
|
|
* Returns a pointer to the first non-whitespace character in @str.
|
|
|
|
*/
|
|
|
|
char *skip_spaces(const char *str)
|
|
|
|
{
|
|
|
|
while (isspace(*str))
|
|
|
|
++str;
|
|
|
|
return (char *)str;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(skip_spaces);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* strim - Removes leading and trailing whitespace from @s.
|
|
|
|
* @s: The string to be stripped.
|
|
|
|
*
|
|
|
|
* Note that the first trailing whitespace is replaced with a %NUL-terminator
|
|
|
|
* in the given string @s. Returns a pointer to the first non-whitespace
|
|
|
|
* character in @s.
|
|
|
|
*/
|
|
|
|
char *strim(char *s)
|
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
size = strlen(s);
|
|
|
|
if (!size)
|
|
|
|
return s;
|
|
|
|
|
|
|
|
end = s + size - 1;
|
|
|
|
while (end >= s && isspace(*end))
|
|
|
|
end--;
|
|
|
|
*(end + 1) = '\0';
|
|
|
|
|
|
|
|
return skip_spaces(s);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(strim);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sysfs_streq - return true if strings are equal, modulo trailing newline
|
|
|
|
* @s1: one string
|
|
|
|
* @s2: another string
|
|
|
|
*
|
|
|
|
* This routine returns true iff two strings are equal, treating both
|
|
|
|
* NUL and newline-then-NUL as equivalent string terminations. It's
|
|
|
|
* geared for use with sysfs input strings, which generally terminate
|
|
|
|
* with newlines but are compared against values without newlines.
|
|
|
|
*/
|
|
|
|
bool sysfs_streq(const char *s1, const char *s2)
|
|
|
|
{
|
|
|
|
while (*s1 && *s1 == *s2) {
|
|
|
|
s1++;
|
|
|
|
s2++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*s1 == *s2)
|
|
|
|
return true;
|
|
|
|
if (!*s1 && *s2 == '\n' && !s2[1])
|
|
|
|
return true;
|
|
|
|
if (*s1 == '\n' && !s1[1] && !*s2)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(sysfs_streq);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* match_string - matches given string in an array
|
|
|
|
* @array: array of strings
|
|
|
|
* @n: number of strings in the array or -1 for NULL terminated arrays
|
|
|
|
* @string: string to match with
|
|
|
|
*
|
|
|
|
* This routine will look for a string in an array of strings up to the
|
|
|
|
* n-th element in the array or until the first NULL element.
|
|
|
|
*
|
|
|
|
* Historically the value of -1 for @n, was used to search in arrays that
|
|
|
|
* are NULL terminated. However, the function does not make a distinction
|
|
|
|
* when finishing the search: either @n elements have been compared OR
|
|
|
|
* the first NULL element was found.
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* index of a @string in the @array if matches, or %-EINVAL otherwise.
|
|
|
|
*/
|
|
|
|
int match_string(const char * const *array, size_t n, const char *string)
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
const char *item;
|
|
|
|
|
|
|
|
for (index = 0; index < n; index++) {
|
|
|
|
item = array[index];
|
|
|
|
if (!item)
|
|
|
|
break;
|
|
|
|
if (!strcmp(item, string))
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(match_string);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* __sysfs_match_string - matches given string in an array
|
|
|
|
* @array: array of strings
|
|
|
|
* @n: number of strings in the array or -1 for NULL terminated arrays
|
|
|
|
* @str: string to match with
|
|
|
|
*
|
|
|
|
* Returns index of @str in the @array or -EINVAL, just like match_string().
|
|
|
|
* Uses sysfs_streq instead of strcmp for matching.
|
|
|
|
*
|
|
|
|
* This routine will look for a string in an array of strings up to the
|
|
|
|
* n-th element in the array or until the first NULL element.
|
|
|
|
*
|
|
|
|
* Historically the value of -1 for @n, was used to search in arrays that
|
|
|
|
* are NULL terminated. However, the function does not make a distinction
|
|
|
|
* when finishing the search: either @n elements have been compared OR
|
|
|
|
* the first NULL element was found.
|
|
|
|
*/
|
|
|
|
int __sysfs_match_string(const char * const *array, size_t n, const char *str)
|
|
|
|
{
|
|
|
|
const char *item;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
for (index = 0; index < n; index++) {
|
|
|
|
item = array[index];
|
|
|
|
if (!item)
|
|
|
|
break;
|
|
|
|
if (sysfs_streq(item, str))
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__sysfs_match_string);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* strreplace - Replace all occurrences of character in string.
|
2023-06-06 01:05:52 +08:00
|
|
|
* @str: The string to operate on.
|
2021-06-19 01:57:38 +08:00
|
|
|
* @old: The character being replaced.
|
|
|
|
* @new: The character @old is replaced with.
|
|
|
|
*
|
2023-06-06 01:05:52 +08:00
|
|
|
* Replaces the each @old character with a @new one in the given string @str.
|
|
|
|
*
|
|
|
|
* Return: pointer to the string @str itself.
|
2021-06-19 01:57:38 +08:00
|
|
|
*/
|
2023-06-06 01:05:52 +08:00
|
|
|
char *strreplace(char *str, char old, char new)
|
2021-06-19 01:57:38 +08:00
|
|
|
{
|
2023-06-06 01:05:52 +08:00
|
|
|
char *s = str;
|
|
|
|
|
2021-06-19 01:57:38 +08:00
|
|
|
for (; *s; ++s)
|
|
|
|
if (*s == old)
|
|
|
|
*s = new;
|
2023-06-06 01:05:52 +08:00
|
|
|
return str;
|
2021-06-19 01:57:38 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(strreplace);
|
|
|
|
|
2021-11-02 22:24:20 +08:00
|
|
|
/**
|
|
|
|
* memcpy_and_pad - Copy one buffer to another with padding
|
|
|
|
* @dest: Where to copy to
|
|
|
|
* @dest_len: The destination buffer size
|
|
|
|
* @src: Where to copy from
|
|
|
|
* @count: The number of bytes to copy
|
|
|
|
* @pad: Character to use for padding if space is left in destination.
|
|
|
|
*/
|
|
|
|
void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
|
|
|
|
int pad)
|
|
|
|
{
|
|
|
|
if (dest_len > count) {
|
|
|
|
memcpy(dest, src, count);
|
|
|
|
memset(dest + count, pad, dest_len - count);
|
|
|
|
} else {
|
|
|
|
memcpy(dest, src, dest_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(memcpy_and_pad);
|
|
|
|
|
2021-04-15 06:45:39 +08:00
|
|
|
#ifdef CONFIG_FORTIFY_SOURCE
|
fortify: Detect struct member overflows in memcpy() at compile-time
memcpy() is dead; long live memcpy()
tl;dr: In order to eliminate a large class of common buffer overflow
flaws that continue to persist in the kernel, have memcpy() (under
CONFIG_FORTIFY_SOURCE) perform bounds checking of the destination struct
member when they have a known size. This would have caught all of the
memcpy()-related buffer write overflow flaws identified in at least the
last three years.
Background and analysis:
While stack-based buffer overflow flaws are largely mitigated by stack
canaries (and similar) features, heap-based buffer overflow flaws continue
to regularly appear in the kernel. Many classes of heap buffer overflows
are mitigated by FORTIFY_SOURCE when using the strcpy() family of
functions, but a significant number remain exposed through the memcpy()
family of functions.
At its core, FORTIFY_SOURCE uses the compiler's __builtin_object_size()
internal[0] to determine the available size at a target address based on
the compile-time known structure layout details. It operates in two
modes: outer bounds (0) and inner bounds (1). In mode 0, the size of the
enclosing structure is used. In mode 1, the size of the specific field
is used. For example:
struct object {
u16 scalar1; /* 2 bytes */
char array[6]; /* 6 bytes */
u64 scalar2; /* 8 bytes */
u32 scalar3; /* 4 bytes */
u32 scalar4; /* 4 bytes */
} instance;
__builtin_object_size(instance.array, 0) == 22, since the remaining size
of the enclosing structure starting from "array" is 22 bytes (6 + 8 +
4 + 4).
__builtin_object_size(instance.array, 1) == 6, since the remaining size
of the specific field "array" is 6 bytes.
The initial implementation of FORTIFY_SOURCE used mode 0 because there
were many cases of both strcpy() and memcpy() functions being used to
write (or read) across multiple fields in a structure. For example,
it would catch this, which is writing 2 bytes beyond the end of
"instance":
memcpy(&instance.array, data, 25);
While this didn't protect against overwriting adjacent fields in a given
structure, it would at least stop overflows from reaching beyond the
end of the structure into neighboring memory, and provided a meaningful
mitigation of a subset of buffer overflow flaws. However, many desirable
targets remain within the enclosing structure (for example function
pointers).
As it happened, there were very few cases of strcpy() family functions
intentionally writing beyond the end of a string buffer. Once all known
cases were removed from the kernel, the strcpy() family was tightened[1]
to use mode 1, providing greater mitigation coverage.
What remains is switching memcpy() to mode 1 as well, but making the
switch is much more difficult because of how frustrating it can be to
find existing "normal" uses of memcpy() that expect to write (or read)
across multiple fields. The root cause of the problem is that the C
language lacks a common pattern to indicate the intent of an author's
use of memcpy(), and is further complicated by the available compile-time
and run-time mitigation behaviors.
The FORTIFY_SOURCE mitigation comes in two halves: the compile-time half,
when both the buffer size _and_ the length of the copy is known, and the
run-time half, when only the buffer size is known. If neither size is
known, there is no bounds checking possible. At compile-time when the
compiler sees that a length will always exceed a known buffer size,
a warning can be deterministically emitted. For the run-time half,
the length is tested against the known size of the buffer, and the
overflowing operation is detected. (The performance overhead for these
tests is virtually zero.)
It is relatively easy to find compile-time false-positives since a warning
is always generated. Fixing the false positives, however, can be very
time-consuming as there are hundreds of instances. While it's possible
some over-read conditions could lead to kernel memory exposures, the bulk
of the risk comes from the run-time flaws where the length of a write
may end up being attacker-controlled and lead to an overflow.
Many of the compile-time false-positives take a form similar to this:
memcpy(&instance.scalar2, data, sizeof(instance.scalar2) +
sizeof(instance.scalar3));
and the run-time ones are similar, but lack a constant expression for the
size of the copy:
memcpy(instance.array, data, length);
The former is meant to cover multiple fields (though its style has been
frowned upon more recently), but has been technically legal. Both lack
any expressivity in the C language about the author's _intent_ in a way
that a compiler can check when the length isn't known at compile time.
A comment doesn't work well because what's needed is something a compiler
can directly reason about. Is a given memcpy() call expected to overflow
into neighbors? Is it not? By using the new struct_group() macro, this
intent can be much more easily encoded.
It is not as easy to find the run-time false-positives since the code path
to exercise a seemingly out-of-bounds condition that is actually expected
may not be trivially reachable. Tightening the restrictions to block an
operation for a false positive will either potentially create a greater
flaw (if a copy is truncated by the mitigation), or destabilize the kernel
(e.g. with a BUG()), making things completely useless for the end user.
As a result, tightening the memcpy() restriction (when there is a
reasonable level of uncertainty of the number of false positives), needs
to first WARN() with no truncation. (Though any sufficiently paranoid
end-user can always opt to set the panic_on_warn=1 sysctl.) Once enough
development time has passed, the mitigation can be further intensified.
(Note that this patch is only the compile-time checking step, which is
a prerequisite to doing run-time checking, which will come in future
patches.)
Given the potential frustrations of weeding out all the false positives
when tightening the run-time checks, it is reasonable to wonder if these
changes would actually add meaningful protection. Looking at just the
last three years, there are 23 identified flaws with a CVE that mention
"buffer overflow", and 11 are memcpy()-related buffer overflows.
(For the remaining 12: 7 are array index overflows that would be
mitigated by systems built with CONFIG_UBSAN_BOUNDS=y: CVE-2019-0145,
CVE-2019-14835, CVE-2019-14896, CVE-2019-14897, CVE-2019-14901,
CVE-2019-17666, CVE-2021-28952. 2 are miscalculated allocation
sizes which could be mitigated with memory tagging: CVE-2019-16746,
CVE-2019-2181. 1 is an iovec buffer bug maybe mitigated by memory tagging:
CVE-2020-10742. 1 is a type confusion bug mitigated by stack canaries:
CVE-2020-10942. 1 is a string handling logic bug with no mitigation I'm
aware of: CVE-2021-28972.)
At my last count on an x86_64 allmodconfig build, there are 35,294
calls to memcpy(). With callers instrumented to report all places
where the buffer size is known but the length remains unknown (i.e. a
run-time bounds check is added), we can count how many new run-time
bounds checks are added when the destination and source arguments of
memcpy() are changed to use "mode 1" bounds checking: 1,276. This means
for the future run-time checking, there is a worst-case upper bounds
of 3.6% false positives to fix. In addition, there were around 150 new
compile-time warnings to evaluate and fix (which have now been fixed).
With this instrumentation it's also possible to compare the places where
the known 11 memcpy() flaw overflows manifested against the resulting
list of potential new run-time bounds checks, as a measure of potential
efficacy of the tightened mitigation. Much to my surprise, horror, and
delight, all 11 flaws would have been detected by the newly added run-time
bounds checks, making this a distinctly clear mitigation improvement: 100%
coverage for known memcpy() flaws, with a possible 2 orders of magnitude
gain in coverage over existing but undiscovered run-time dynamic length
flaws (i.e. 1265 newly covered sites in addition to the 11 known), against
only <4% of all memcpy() callers maybe gaining a false positive run-time
check, with only about 150 new compile-time instances needing evaluation.
Specifically these would have been mitigated:
CVE-2020-24490 https://git.kernel.org/linus/a2ec905d1e160a33b2e210e45ad30445ef26ce0e
CVE-2020-12654 https://git.kernel.org/linus/3a9b153c5591548612c3955c9600a98150c81875
CVE-2020-12653 https://git.kernel.org/linus/b70261a288ea4d2f4ac7cd04be08a9f0f2de4f4d
CVE-2019-14895 https://git.kernel.org/linus/3d94a4a8373bf5f45cf5f939e88b8354dbf2311b
CVE-2019-14816 https://git.kernel.org/linus/7caac62ed598a196d6ddf8d9c121e12e082cac3a
CVE-2019-14815 https://git.kernel.org/linus/7caac62ed598a196d6ddf8d9c121e12e082cac3a
CVE-2019-14814 https://git.kernel.org/linus/7caac62ed598a196d6ddf8d9c121e12e082cac3a
CVE-2019-10126 https://git.kernel.org/linus/69ae4f6aac1578575126319d3f55550e7e440449
CVE-2019-9500 https://git.kernel.org/linus/1b5e2423164b3670e8bc9174e4762d297990deff
no-CVE-yet https://git.kernel.org/linus/130f634da1af649205f4a3dd86cbe5c126b57914
no-CVE-yet https://git.kernel.org/linus/d10a87a3535cce2b890897914f5d0d83df669c63
To accelerate the review of potential run-time false positives, it's
also worth noting that it is possible to partially automate checking
by examining the memcpy() buffer argument to check for the destination
struct member having a neighboring array member. It is reasonable to
expect that the vast majority of run-time false positives would look like
the already evaluated and fixed compile-time false positives, where the
most common pattern is neighboring arrays. (And, FWIW, many of the
compile-time fixes were actual bugs, so it is reasonable to assume we'll
have similar cases of actual bugs getting fixed for run-time checks.)
Implementation:
Tighten the memcpy() destination buffer size checking to use the actual
("mode 1") target buffer size as the bounds check instead of their
enclosing structure's ("mode 0") size. Use a common inline for memcpy()
(and memmove() in a following patch), since all the tests are the
same. All new cross-field memcpy() uses must use the struct_group() macro
or similar to target a specific range of fields, so that FORTIFY_SOURCE
can reason about the size and safety of the copy.
For now, cross-member "mode 1" _read_ detection at compile-time will be
limited to W=1 builds, since it is, unfortunately, very common. As the
priority is solving write overflows, read overflows will be part of a
future phase (and can be fixed in parallel, for anyone wanting to look
at W=1 build output).
For run-time, the "mode 0" size checking and mitigation is left unchanged,
with "mode 1" to be added in stages. In this patch, no new run-time
checks are added. Future patches will first bounds-check writes,
and only perform a WARN() for now. This way any missed run-time false
positives can be flushed out over the coming several development cycles,
but system builders who have tested their workloads to be WARN()-free
can enable the panic_on_warn=1 sysctl to immediately gain a mitigation
against this class of buffer overflows. Once that is under way, run-time
bounds-checking of reads can be similarly enabled.
Related classes of flaws that will remain unmitigated:
- memcpy() with flexible array structures, as the compiler does not
currently have visibility into the size of the trailing flexible
array. These can be fixed in the future by refactoring such cases
to use a new set of flexible array structure helpers to perform the
common serialization/deserialization code patterns doing allocation
and/or copying.
- memcpy() with raw pointers (e.g. void *, char *, etc), or otherwise
having their buffer size unknown at compile time, have no good
mitigation beyond memory tagging (and even that would only protect
against inter-object overflow, not intra-object neighboring field
overflows), or refactoring. Some kind of "fat pointer" solution is
likely needed to gain proper size-of-buffer awareness. (e.g. see
struct membuf)
- type confusion where a higher level type's allocation size does
not match the resulting cast type eventually passed to a deeper
memcpy() call where the compiler cannot see the true type. In
theory, greater static analysis could catch these, and the use
of -Warray-bounds will help find some of these.
[0] https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
[1] https://git.kernel.org/linus/6a39e62abbafd1d58d1722f40c7d26ef379c6a2f
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-04-21 14:22:52 +08:00
|
|
|
/* These are placeholders for fortify compile-time warnings. */
|
|
|
|
void __read_overflow2_field(size_t avail, size_t wanted) { }
|
|
|
|
EXPORT_SYMBOL(__read_overflow2_field);
|
|
|
|
void __write_overflow_field(size_t avail, size_t wanted) { }
|
|
|
|
EXPORT_SYMBOL(__write_overflow_field);
|
|
|
|
|
2023-04-08 03:27:13 +08:00
|
|
|
static const char * const fortify_func_name[] = {
|
|
|
|
#define MAKE_FORTIFY_FUNC_NAME(func) [MAKE_FORTIFY_FUNC(func)] = #func
|
|
|
|
EACH_FORTIFY_FUNC(MAKE_FORTIFY_FUNC_NAME)
|
|
|
|
#undef MAKE_FORTIFY_FUNC_NAME
|
|
|
|
};
|
|
|
|
|
2023-04-08 03:27:16 +08:00
|
|
|
void __fortify_report(const u8 reason, const size_t avail, const size_t size)
|
2023-04-08 03:27:13 +08:00
|
|
|
{
|
|
|
|
const u8 func = FORTIFY_REASON_FUNC(reason);
|
|
|
|
const bool write = FORTIFY_REASON_DIR(reason);
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = fortify_func_name[umin(func, FORTIFY_FUNC_UNKNOWN)];
|
2023-04-08 03:27:16 +08:00
|
|
|
WARN(1, "%s: detected buffer overflow: %zu byte %s of buffer size %zu\n",
|
|
|
|
name, size, str_read_write(!write), avail);
|
2023-04-08 03:27:13 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__fortify_report);
|
|
|
|
|
2023-04-08 03:27:16 +08:00
|
|
|
void __fortify_panic(const u8 reason, const size_t avail, const size_t size)
|
2021-06-19 01:57:38 +08:00
|
|
|
{
|
2023-04-08 03:27:16 +08:00
|
|
|
__fortify_report(reason, avail, size);
|
2021-06-19 01:57:38 +08:00
|
|
|
BUG();
|
|
|
|
}
|
2023-04-08 03:27:13 +08:00
|
|
|
EXPORT_SYMBOL(__fortify_panic);
|
2021-04-15 06:45:39 +08:00
|
|
|
#endif /* CONFIG_FORTIFY_SOURCE */
|