24 Mar, 2019

3 commits

  • commit dd838821f0a29781b185cd8fb8e48d5c177bd838 upstream.

    Commit 62a063b8e7d1 "nfsd4: fix crash on writing v4_end_grace before
    nfsd startup" is trying to fix a NULL dereference issue, but it
    mistakenly checks if the nfsd server is started. So fix it.

    Fixes: 62a063b8e7d1 "nfsd4: fix crash on writing v4_end_grace before nfsd startup"
    Cc: stable@vger.kernel.org
    Reviewed-by: Joseph Qi
    Signed-off-by: Yihao Wu
    Signed-off-by: J. Bruce Fields
    Signed-off-by: Greg Kroah-Hartman

    Yihao Wu
     
  • commit b602345da6cbb135ba68cf042df8ec9a73da7981 upstream.

    If the result of an NFSv3 readdir{,plus} request results in the
    "offset" on one entry having to be split across 2 pages, and is sized
    so that the next directory entry doesn't fit in the requested size,
    then memory corruption can happen.

    When encode_entry() is called after encoding the last entry that fits,
    it notices that ->offset and ->offset1 are set, and so stores the
    offset value in the two pages as required. It clears ->offset1 but
    *does not* clear ->offset.

    Normally this omission doesn't matter as encode_entry_baggage() will
    be called, and will set ->offset to a suitable value (not on a page
    boundary).
    But in the case where cd->buflen < elen and nfserr_toosmall is
    returned, ->offset is not reset.

    This means that nfsd3proc_readdirplus will see ->offset with a value 4
    bytes before the end of a page, and ->offset1 set to NULL.
    It will try to write 8bytes to ->offset.
    If we are lucky, the next page will be read-only, and the system will
    BUG: unable to handle kernel paging request at...

    If we are unlucky, some innocent page will have the first 4 bytes
    corrupted.

    nfsd3proc_readdir() doesn't even check for ->offset1, it just blindly
    writes 8 bytes to the offset wherever it is.

    Fix this by clearing ->offset after it is used, and copying the
    ->offset handling code from nfsd3_proc_readdirplus into
    nfsd3_proc_readdir.

    (Note that the commit hash in the Fixes tag is from the 'history'
    tree - this bug predates git).

    Fixes: 0b1d57cf7654 ("[PATCH] kNFSd: Fix nfs3 dentry encoding")
    Fixes-URL: https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=0b1d57cf7654
    Cc: stable@vger.kernel.org (v2.6.12+)
    Signed-off-by: NeilBrown
    Signed-off-by: J. Bruce Fields
    Signed-off-by: Greg Kroah-Hartman

    NeilBrown
     
  • commit c54f24e338ed2a35218f117a4a1afb5f9e2b4e64 upstream.

    We're unintentionally limiting the number of slots per nfsv4.1 session
    to 10. Often more than 10 simultaneous RPCs are needed for the best
    performance.

    This calculation was meant to prevent any one client from using up more
    than a third of the limit we set for total memory use across all clients
    and sessions. Instead, it's limiting the client to a third of the
    maximum for a single session.

    Fix this.

    Reported-by: Chris Tracy
    Cc: stable@vger.kernel.org
    Fixes: de766e570413 "nfsd: give out fewer session slots as limit approaches"
    Signed-off-by: J. Bruce Fields
    Signed-off-by: Greg Kroah-Hartman

    J. Bruce Fields
     

20 Feb, 2019

1 commit

  • commit 3bf6b57ec2ec945e5a6edf5c202a754f1e852ecd upstream.

    This reverts commit d6ebf5088f09472c1136cd506bdc27034a6763f8.

    I forgot that the kernel's default lease period should never be
    decreased!

    After a kernel upgrade, the kernel has no way of knowing on its own what
    the previous lease time was. Unless userspace tells it otherwise, it
    will assume the previous lease period was the same.

    So if we decrease this value in a kernel upgrade, we end up enforcing a
    grace period that's too short, and clients will fail to reclaim state in
    time. Symptoms may include EIO and log messages like "NFS:
    nfs4_reclaim_open_state: Lock reclaim failed!"

    There was no real justification for the lease period decrease anyway.

    Reported-by: Donald Buczek
    Fixes: d6ebf5088f09 "nfsd4: return default lease period"
    Cc: stable@vger.kernel.org
    Signed-off-by: J. Bruce Fields
    Signed-off-by: Greg Kroah-Hartman

    J. Bruce Fields
     

13 Feb, 2019

1 commit

  • [ Upstream commit 62a063b8e7d1db684db3f207261a466fa3194e72 ]

    Anatoly Trosinenko reports that this:

    1) Checkout fresh master Linux branch (tested with commit e195ca6cb)
    2) Copy x84_64-config-4.14 to .config, then enable NFS server v4 and build
    3) From `kvm-xfstests shell`:

    results in NULL dereference in locks_end_grace.

    Check that nfsd has been started before trying to end the grace period.

    Reported-by: Anatoly Trosinenko
    Signed-off-by: J. Bruce Fields
    Signed-off-by: Sasha Levin

    J. Bruce Fields
     

13 Jan, 2019

1 commit

  • commit fdec6114ee1f0f43b1ad081ad8d46b23ba126d70 upstream.

    Zero-length writes are legal; from 5661 section 18.32.3: "If the count
    is zero, the WRITE will succeed and return a count of zero subject to
    permissions checking".

    This check is unnecessary and is causing zero-length reads to return
    EINVAL.

    Cc: stable@vger.kernel.org
    Fixes: 3fd9557aec91 "NFSD: Refactor the generic write vector fill helper"
    Cc: Chuck Lever
    Signed-off-by: J. Bruce Fields
    Signed-off-by: Greg Kroah-Hartman

    J. Bruce Fields
     

21 Nov, 2018

1 commit


14 Nov, 2018

1 commit

  • commit bd8d725078867cda250fe94b9c5a067b4a64ca74 upstream.

    alloc_init_deleg() both allocates an nfs4_delegation, and
    bumps the refcount on odstate. So after this point, we need to
    put_clnt_odstate() and nfs4_put_stid() to not leave the odstate
    refcount inappropriately bumped.

    Signed-off-by: Andrew Elble
    Reviewed-by: Jeff Layton
    Cc: stable@vger.kernel.org
    Signed-off-by: J. Bruce Fields
    Signed-off-by: Greg Kroah-Hartman

    Andrew Elble
     

24 Sep, 2018

1 commit

  • Commit 031a072a0b8a ("vfs: call vfs_clone_file_range() under freeze
    protection") created a wrapper do_clone_file_range() around
    vfs_clone_file_range() moving the freeze protection to former, so
    overlayfs could call the latter.

    The more common vfs practice is to call do_xxx helpers from vfs_xxx
    helpers, where freeze protecction is taken in the vfs_xxx helper, so
    this anomality could be a source of confusion.

    It seems that commit 8ede205541ff ("ovl: add reflink/copyfile/dedup
    support") may have fallen a victim to this confusion -
    ovl_clone_file_range() calls the vfs_clone_file_range() helper in the
    hope of getting freeze protection on upper fs, but in fact results in
    overlayfs allowing to bypass upper fs freeze protection.

    Swap the names of the two helpers to conform to common vfs practice
    and call the correct helpers from overlayfs and nfsd.

    Signed-off-by: Amir Goldstein
    Signed-off-by: Miklos Szeredi

    Amir Goldstein
     

24 Aug, 2018

1 commit

  • Pull nfsd updates from Bruce Fields:
    "Chuck Lever fixed a problem with NFSv4.0 callbacks over GSS from
    multi-homed servers.

    The only new feature is a minor bit of protocol (change_attr_type)
    which the client doesn't even use yet.

    Other than that, various bugfixes and cleanup"

    * tag 'nfsd-4.19-1' of git://linux-nfs.org/~bfields/linux: (27 commits)
    sunrpc: Add comment defining gssd upcall API keywords
    nfsd: Remove callback_cred
    nfsd: Use correct credential for NFSv4.0 callback with GSS
    sunrpc: Extract target name into svc_cred
    sunrpc: Enable the kernel to specify the hostname part of service principals
    sunrpc: Don't use stack buffer with scatterlist
    rpc: remove unneeded variable 'ret' in rdma_listen_handler
    nfsd: use true and false for boolean values
    nfsd: constify write_op[]
    fs/nfsd: Delete invalid assignment statements in nfsd4_decode_exchange_id
    NFSD: Handle full-length symlinks
    NFSD: Refactor the generic write vector fill helper
    svcrdma: Clean up Read chunk path
    svcrdma: Avoid releasing a page in svc_xprt_release()
    nfsd: Mark expected switch fall-through
    sunrpc: remove redundant variables 'checksumlen','blocksize' and 'data'
    nfsd: fix leaked file lock with nfs exported overlayfs
    nfsd: don't advertise a SCSI layout for an unsupported request_queue
    nfsd: fix corrupted reply to badly ordered compound
    nfsd: clarify check_op_ordering
    ...

    Linus Torvalds
     

23 Aug, 2018

3 commits

  • Clean up: The global callback_cred is no longer used, so it can be
    removed.

    Signed-off-by: Chuck Lever
    Signed-off-by: J. Bruce Fields

    Chuck Lever
     
  • I've had trouble when operating a multi-homed Linux NFS server with
    Kerberos using NFSv4.0. Lately, I've seen my clients reporting
    this (and then hanging):

    May 9 11:43:26 manet kernel: NFS: NFSv4 callback contains invalid cred

    The client-side commit f11b2a1cfbf5 ("nfs4: copy acceptor name from
    context to nfs_client") appears to be related, but I suspect this
    problem has been going on for some time before that.

    RFC 7530 Section 3.3.3 says:
    > For Kerberos V5, nfs/hostname would be a server principal in the
    > Kerberos Key Distribution Center database. This is the same
    > principal the client acquired a GSS-API context for when it issued
    > the SETCLIENTID operation ...

    In other words, an NFSv4.0 client expects that the server will use
    the same GSS principal for callback that the client used to
    establish its lease. For example, if the client used the service
    principal "nfs@server.domain" to establish its lease, the server
    is required to use "nfs@server.domain" when performing NFSv4.0
    callback operations.

    The Linux NFS server currently does not. It uses a common service
    principal for all callback connections. Sometimes this works as
    expected, and other times -- for example, when the server is
    accessible via multiple hostnames -- it won't work at all.

    This patch scrapes the target name from the client credential,
    and uses that for the NFSv4.0 callback credential. That should
    be correct much more often.

    Signed-off-by: Chuck Lever
    Signed-off-by: J. Bruce Fields

    Chuck Lever
     
  • NFSv4.0 callback needs to know the GSS target name the client used
    when it established its lease. That information is available from
    the GSS context created by gssproxy. Make it available in each
    svc_cred.

    Note this will also give us access to the real target service
    principal name (which is typically "nfs", but spec does not require
    that).

    Signed-off-by: Chuck Lever
    Signed-off-by: J. Bruce Fields

    Chuck Lever
     

10 Aug, 2018

7 commits

  • Return statements in functions returning bool should use true or false
    instead of an integer value.

    This issue was detected with the help of Coccinelle.

    Signed-off-by: Gustavo A. R. Silva
    Signed-off-by: J. Bruce Fields

    Gustavo A. R. Silva
     
  • write_op[] is never modified, so make it 'const'.

    Signed-off-by: Eric Biggers
    Signed-off-by: J. Bruce Fields

    Eric Biggers
     
  • READ_BUF(8);
    dummy = be32_to_cpup(p++);
    dummy = be32_to_cpup(p++);
    ...
    READ_BUF(4);
    dummy = be32_to_cpup(p++);

    Assigning value to "dummy" here, but that stored value
    is overwritten before it can be used.
    At the same time READ_BUF() will re-update the pointer p.

    delete invalid assignment statements

    Signed-off-by: nixiaoming
    Signed-off-by: Chuck Lever
    Signed-off-by: Trond Myklebust
    Signed-off-by: J. Bruce Fields

    nixiaoming
     
  • I've given up on the idea of zero-copy handling of SYMLINK on the
    server side. This is because the Linux VFS symlink API requires the
    symlink pathname to be in a NUL-terminated kmalloc'd buffer. The
    NUL-termination is going to be problematic (watching out for
    landing on a page boundary and dealing with a 4096-byte pathname).

    I don't believe that SYMLINK creation is on a performance path or is
    requested frequently enough that it will cause noticeable CPU cache
    pollution due to data copies.

    There will be two places where a transport callout will be necessary
    to fill in the rqstp: one will be in the svc_fill_symlink_pathname()
    helper that is used by NFSv2 and NFSv3, and the other will be in
    nfsd4_decode_create().

    Signed-off-by: Chuck Lever
    Signed-off-by: J. Bruce Fields

    Chuck Lever
     
  • fill_in_write_vector() is nearly the same logic as
    svc_fill_write_vector(), but there are a few differences so that
    the former can handle multiple WRITE payloads in a single COMPOUND.

    svc_fill_write_vector() can be adjusted so that it can be used in
    the NFSv4 WRITE code path too. Instead of assuming the pages are
    coming from rq_args.pages, have the caller pass in the page list.

    The immediate benefit is a reduction of code duplication. It also
    prevents the NFSv4 WRITE decoder from passing an empty vector
    element when the transport has provided the payload in the xdr_buf's
    page array.

    Signed-off-by: Chuck Lever
    Signed-off-by: J. Bruce Fields

    Chuck Lever
     
  • In preparation to enabling -Wimplicit-fallthrough, mark switch cases
    where we are expecting to fall through.

    Warning level 2 was used: -Wimplicit-fallthrough=2

    Signed-off-by: Gustavo A. R. Silva
    Signed-off-by: J. Bruce Fields

    Gustavo A. R. Silva
     
  • nfsd and lockd call vfs_lock_file() to lock/unlock the inode
    returned by locks_inode(file).

    Many places in nfsd/lockd code use the inode returned by
    file_inode(file) for lock manipulation. With Overlayfs, file_inode()
    (the underlying inode) is not the same object as locks_inode() (the
    overlay inode). This can result in "Leaked POSIX lock" messages
    and eventually to a kernel crash as reported by Eddie Horng:
    https://marc.info/?l=linux-unionfs&m=153086643202072&w=2

    Fix all the call sites in nfsd/lockd that should use locks_inode().
    This is a correctness bug that manifested when overlayfs gained
    NFS export support in v4.16.

    Reported-by: Eddie Horng
    Tested-by: Eddie Horng
    Cc: Jeff Layton
    Fixes: 8383f1748829 ("ovl: wire up NFS export operations")
    Cc: stable@vger.kernel.org
    Signed-off-by: Amir Goldstein
    Signed-off-by: J. Bruce Fields

    Amir Goldstein
     

12 Jul, 2018

1 commit


19 Jun, 2018

1 commit

  • Commit 30181faae37f ("nfsd: Check queue type before submitting a SCSI
    request") did the work of ensuring that we don't send SCSI requests to a
    request queue that won't support them, but that check is in the
    GETDEVICEINFO path. Let's not set the SCSI layout in fs_layout_type in the
    first place, and then we'll have less clients sending GETDEVICEINFO for
    non-SCSI request queues and less unnecessary WARN_ONs.

    While we're in here, remove some outdated comments that refer to
    "overwriting" layout seletion because commit 8a4c3926889e ("nfsd: allow
    nfsd to advertise multiple layout types") changed things to no longer
    overwrite the layout type.

    Signed-off-by: Benjamin Coddington
    Reviewed-by: Christoph Hellwig
    Signed-off-by: J. Bruce Fields

    Benjamin Coddington
     

17 Jun, 2018

9 commits


15 Jun, 2018

1 commit

  • Pull inode timestamps conversion to timespec64 from Arnd Bergmann:
    "This is a late set of changes from Deepa Dinamani doing an automated
    treewide conversion of the inode and iattr structures from 'timespec'
    to 'timespec64', to push the conversion from the VFS layer into the
    individual file systems.

    As Deepa writes:

    'The series aims to switch vfs timestamps to use struct timespec64.
    Currently vfs uses struct timespec, which is not y2038 safe.

    The series involves the following:
    1. Add vfs helper functions for supporting struct timepec64
    timestamps.
    2. Cast prints of vfs timestamps to avoid warnings after the switch.
    3. Simplify code using vfs timestamps so that the actual replacement
    becomes easy.
    4. Convert vfs timestamps to use struct timespec64 using a script.
    This is a flag day patch.

    Next steps:
    1. Convert APIs that can handle timespec64, instead of converting
    timestamps at the boundaries.
    2. Update internal data structures to avoid timestamp conversions'

    Thomas Gleixner adds:

    'I think there is no point to drag that out for the next merge
    window. The whole thing needs to be done in one go for the core
    changes which means that you're going to play that catchup game
    forever. Let's get over with it towards the end of the merge window'"

    * tag 'vfs-timespec64' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground:
    pstore: Remove bogus format string definition
    vfs: change inode times to use struct timespec64
    pstore: Convert internal records to timespec64
    udf: Simplify calls to udf_disk_stamp_to_time
    fs: nfs: get rid of memcpys for inode times
    ceph: make inode time prints to be long long
    lustre: Use long long type to print inode time
    fs: add timespec64_truncate()

    Linus Torvalds
     

14 Jun, 2018

1 commit

  • Pull the timespec64 conversion from Deepa Dinamani:
    "The series aims to switch vfs timestamps to use
    struct timespec64. Currently vfs uses struct timespec,
    which is not y2038 safe.

    The flag patch applies cleanly. I've not seen the timestamps
    update logic change often. The series applies cleanly on 4.17-rc6
    and linux-next tip (top commit: next-20180517).

    I'm not sure how to merge this kind of a series with a flag patch.
    We are targeting 4.18 for this.
    Let me know if you have other suggestions.

    The series involves the following:
    1. Add vfs helper functions for supporting struct timepec64 timestamps.
    2. Cast prints of vfs timestamps to avoid warnings after the switch.
    3. Simplify code using vfs timestamps so that the actual
    replacement becomes easy.
    4. Convert vfs timestamps to use struct timespec64 using a script.
    This is a flag day patch.

    I've tried to keep the conversions with the script simple, to
    aid in the reviews. I've kept all the internal filesystem data
    structures and function signatures the same.

    Next steps:
    1. Convert APIs that can handle timespec64, instead of converting
    timestamps at the boundaries.
    2. Update internal data structures to avoid timestamp conversions."

    I've pulled it into a branch based on top of the NFS changes that
    are now in mainline, so I could resolve the non-obvious conflict
    between the two while merging.

    Signed-off-by: Arnd Bergmann

    Arnd Bergmann
     

13 Jun, 2018

5 commits

  • Pull more overflow updates from Kees Cook:
    "The rest of the overflow changes for v4.18-rc1.

    This includes the explicit overflow fixes from Silvio, further
    struct_size() conversions from Matthew, and a bug fix from Dan.

    But the bulk of it is the treewide conversions to use either the
    2-factor argument allocators (e.g. kmalloc(a * b, ...) into
    kmalloc_array(a, b, ...) or the array_size() macros (e.g. vmalloc(a *
    b) into vmalloc(array_size(a, b)).

    Coccinelle was fighting me on several fronts, so I've done a bunch of
    manual whitespace updates in the patches as well.

    Summary:

    - Error path bug fix for overflow tests (Dan)

    - Additional struct_size() conversions (Matthew, Kees)

    - Explicitly reported overflow fixes (Silvio, Kees)

    - Add missing kvcalloc() function (Kees)

    - Treewide conversions of allocators to use either 2-factor argument
    variant when available, or array_size() and array3_size() as needed
    (Kees)"

    * tag 'overflow-v4.18-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: (26 commits)
    treewide: Use array_size in f2fs_kvzalloc()
    treewide: Use array_size() in f2fs_kzalloc()
    treewide: Use array_size() in f2fs_kmalloc()
    treewide: Use array_size() in sock_kmalloc()
    treewide: Use array_size() in kvzalloc_node()
    treewide: Use array_size() in vzalloc_node()
    treewide: Use array_size() in vzalloc()
    treewide: Use array_size() in vmalloc()
    treewide: devm_kzalloc() -> devm_kcalloc()
    treewide: devm_kmalloc() -> devm_kmalloc_array()
    treewide: kvzalloc() -> kvcalloc()
    treewide: kvmalloc() -> kvmalloc_array()
    treewide: kzalloc_node() -> kcalloc_node()
    treewide: kzalloc() -> kcalloc()
    treewide: kmalloc() -> kmalloc_array()
    mm: Introduce kvcalloc()
    video: uvesafb: Fix integer overflow in allocation
    UBIFS: Fix potential integer overflow in allocation
    leds: Use struct_size() in allocation
    Convert intel uncore to struct_size
    ...

    Linus Torvalds
     
  • The vzalloc() function has no 2-factor argument form, so multiplication
    factors need to be wrapped in array_size(). This patch replaces cases of:

    vzalloc(a * b)

    with:
    vzalloc(array_size(a, b))

    as well as handling cases of:

    vzalloc(a * b * c)

    with:

    vzalloc(array3_size(a, b, c))

    This does, however, attempt to ignore constant size factors like:

    vzalloc(4 * 1024)

    though any constants defined via macros get caught up in the conversion.

    Any factors with a sizeof() of "unsigned char", "char", and "u8" were
    dropped, since they're redundant.

    The Coccinelle script used for this was:

    // Fix redundant parens around sizeof().
    @@
    type TYPE;
    expression THING, E;
    @@

    (
    vzalloc(
    - (sizeof(TYPE)) * E
    + sizeof(TYPE) * E
    , ...)
    |
    vzalloc(
    - (sizeof(THING)) * E
    + sizeof(THING) * E
    , ...)
    )

    // Drop single-byte sizes and redundant parens.
    @@
    expression COUNT;
    typedef u8;
    typedef __u8;
    @@

    (
    vzalloc(
    - sizeof(u8) * (COUNT)
    + COUNT
    , ...)
    |
    vzalloc(
    - sizeof(__u8) * (COUNT)
    + COUNT
    , ...)
    |
    vzalloc(
    - sizeof(char) * (COUNT)
    + COUNT
    , ...)
    |
    vzalloc(
    - sizeof(unsigned char) * (COUNT)
    + COUNT
    , ...)
    |
    vzalloc(
    - sizeof(u8) * COUNT
    + COUNT
    , ...)
    |
    vzalloc(
    - sizeof(__u8) * COUNT
    + COUNT
    , ...)
    |
    vzalloc(
    - sizeof(char) * COUNT
    + COUNT
    , ...)
    |
    vzalloc(
    - sizeof(unsigned char) * COUNT
    + COUNT
    , ...)
    )

    // 2-factor product with sizeof(type/expression) and identifier or constant.
    @@
    type TYPE;
    expression THING;
    identifier COUNT_ID;
    constant COUNT_CONST;
    @@

    (
    vzalloc(
    - sizeof(TYPE) * (COUNT_ID)
    + array_size(COUNT_ID, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE) * COUNT_ID
    + array_size(COUNT_ID, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE) * (COUNT_CONST)
    + array_size(COUNT_CONST, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE) * COUNT_CONST
    + array_size(COUNT_CONST, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * (COUNT_ID)
    + array_size(COUNT_ID, sizeof(THING))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * COUNT_ID
    + array_size(COUNT_ID, sizeof(THING))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * (COUNT_CONST)
    + array_size(COUNT_CONST, sizeof(THING))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * COUNT_CONST
    + array_size(COUNT_CONST, sizeof(THING))
    , ...)
    )

    // 2-factor product, only identifiers.
    @@
    identifier SIZE, COUNT;
    @@

    vzalloc(
    - SIZE * COUNT
    + array_size(COUNT, SIZE)
    , ...)

    // 3-factor product with 1 sizeof(type) or sizeof(expression), with
    // redundant parens removed.
    @@
    expression THING;
    identifier STRIDE, COUNT;
    type TYPE;
    @@

    (
    vzalloc(
    - sizeof(TYPE) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    vzalloc(
    - sizeof(THING) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    )

    // 3-factor product with 2 sizeof(variable), with redundant parens removed.
    @@
    expression THING1, THING2;
    identifier COUNT;
    type TYPE1, TYPE2;
    @@

    (
    vzalloc(
    - sizeof(TYPE1) * sizeof(TYPE2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    vzalloc(
    - sizeof(THING1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    vzalloc(
    - sizeof(THING1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    |
    vzalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    )

    // 3-factor product, only identifiers, with redundant parens removed.
    @@
    identifier STRIDE, SIZE, COUNT;
    @@

    (
    vzalloc(
    - (COUNT) * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vzalloc(
    - COUNT * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vzalloc(
    - COUNT * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vzalloc(
    - (COUNT) * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vzalloc(
    - COUNT * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vzalloc(
    - (COUNT) * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vzalloc(
    - (COUNT) * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vzalloc(
    - COUNT * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    )

    // Any remaining multi-factor products, first at least 3-factor products
    // when they're not all constants...
    @@
    expression E1, E2, E3;
    constant C1, C2, C3;
    @@

    (
    vzalloc(C1 * C2 * C3, ...)
    |
    vzalloc(
    - E1 * E2 * E3
    + array3_size(E1, E2, E3)
    , ...)
    )

    // And then all remaining 2 factors products when they're not all constants.
    @@
    expression E1, E2;
    constant C1, C2;
    @@

    (
    vzalloc(C1 * C2, ...)
    |
    vzalloc(
    - E1 * E2
    + array_size(E1, E2)
    , ...)
    )

    Signed-off-by: Kees Cook

    Kees Cook
     
  • The kzalloc() function has a 2-factor argument form, kcalloc(). This
    patch replaces cases of:

    kzalloc(a * b, gfp)

    with:
    kcalloc(a * b, gfp)

    as well as handling cases of:

    kzalloc(a * b * c, gfp)

    with:

    kzalloc(array3_size(a, b, c), gfp)

    as it's slightly less ugly than:

    kzalloc_array(array_size(a, b), c, gfp)

    This does, however, attempt to ignore constant size factors like:

    kzalloc(4 * 1024, gfp)

    though any constants defined via macros get caught up in the conversion.

    Any factors with a sizeof() of "unsigned char", "char", and "u8" were
    dropped, since they're redundant.

    The Coccinelle script used for this was:

    // Fix redundant parens around sizeof().
    @@
    type TYPE;
    expression THING, E;
    @@

    (
    kzalloc(
    - (sizeof(TYPE)) * E
    + sizeof(TYPE) * E
    , ...)
    |
    kzalloc(
    - (sizeof(THING)) * E
    + sizeof(THING) * E
    , ...)
    )

    // Drop single-byte sizes and redundant parens.
    @@
    expression COUNT;
    typedef u8;
    typedef __u8;
    @@

    (
    kzalloc(
    - sizeof(u8) * (COUNT)
    + COUNT
    , ...)
    |
    kzalloc(
    - sizeof(__u8) * (COUNT)
    + COUNT
    , ...)
    |
    kzalloc(
    - sizeof(char) * (COUNT)
    + COUNT
    , ...)
    |
    kzalloc(
    - sizeof(unsigned char) * (COUNT)
    + COUNT
    , ...)
    |
    kzalloc(
    - sizeof(u8) * COUNT
    + COUNT
    , ...)
    |
    kzalloc(
    - sizeof(__u8) * COUNT
    + COUNT
    , ...)
    |
    kzalloc(
    - sizeof(char) * COUNT
    + COUNT
    , ...)
    |
    kzalloc(
    - sizeof(unsigned char) * COUNT
    + COUNT
    , ...)
    )

    // 2-factor product with sizeof(type/expression) and identifier or constant.
    @@
    type TYPE;
    expression THING;
    identifier COUNT_ID;
    constant COUNT_CONST;
    @@

    (
    - kzalloc
    + kcalloc
    (
    - sizeof(TYPE) * (COUNT_ID)
    + COUNT_ID, sizeof(TYPE)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(TYPE) * COUNT_ID
    + COUNT_ID, sizeof(TYPE)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(TYPE) * (COUNT_CONST)
    + COUNT_CONST, sizeof(TYPE)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(TYPE) * COUNT_CONST
    + COUNT_CONST, sizeof(TYPE)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(THING) * (COUNT_ID)
    + COUNT_ID, sizeof(THING)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(THING) * COUNT_ID
    + COUNT_ID, sizeof(THING)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(THING) * (COUNT_CONST)
    + COUNT_CONST, sizeof(THING)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(THING) * COUNT_CONST
    + COUNT_CONST, sizeof(THING)
    , ...)
    )

    // 2-factor product, only identifiers.
    @@
    identifier SIZE, COUNT;
    @@

    - kzalloc
    + kcalloc
    (
    - SIZE * COUNT
    + COUNT, SIZE
    , ...)

    // 3-factor product with 1 sizeof(type) or sizeof(expression), with
    // redundant parens removed.
    @@
    expression THING;
    identifier STRIDE, COUNT;
    type TYPE;
    @@

    (
    kzalloc(
    - sizeof(TYPE) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kzalloc(
    - sizeof(TYPE) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kzalloc(
    - sizeof(TYPE) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kzalloc(
    - sizeof(TYPE) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kzalloc(
    - sizeof(THING) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    kzalloc(
    - sizeof(THING) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    kzalloc(
    - sizeof(THING) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    kzalloc(
    - sizeof(THING) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    )

    // 3-factor product with 2 sizeof(variable), with redundant parens removed.
    @@
    expression THING1, THING2;
    identifier COUNT;
    type TYPE1, TYPE2;
    @@

    (
    kzalloc(
    - sizeof(TYPE1) * sizeof(TYPE2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    kzalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    kzalloc(
    - sizeof(THING1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    kzalloc(
    - sizeof(THING1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    kzalloc(
    - sizeof(TYPE1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    |
    kzalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    )

    // 3-factor product, only identifiers, with redundant parens removed.
    @@
    identifier STRIDE, SIZE, COUNT;
    @@

    (
    kzalloc(
    - (COUNT) * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kzalloc(
    - COUNT * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kzalloc(
    - COUNT * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kzalloc(
    - (COUNT) * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kzalloc(
    - COUNT * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kzalloc(
    - (COUNT) * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kzalloc(
    - (COUNT) * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kzalloc(
    - COUNT * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    )

    // Any remaining multi-factor products, first at least 3-factor products,
    // when they're not all constants...
    @@
    expression E1, E2, E3;
    constant C1, C2, C3;
    @@

    (
    kzalloc(C1 * C2 * C3, ...)
    |
    kzalloc(
    - (E1) * E2 * E3
    + array3_size(E1, E2, E3)
    , ...)
    |
    kzalloc(
    - (E1) * (E2) * E3
    + array3_size(E1, E2, E3)
    , ...)
    |
    kzalloc(
    - (E1) * (E2) * (E3)
    + array3_size(E1, E2, E3)
    , ...)
    |
    kzalloc(
    - E1 * E2 * E3
    + array3_size(E1, E2, E3)
    , ...)
    )

    // And then all remaining 2 factors products when they're not all constants,
    // keeping sizeof() as the second factor argument.
    @@
    expression THING, E1, E2;
    type TYPE;
    constant C1, C2, C3;
    @@

    (
    kzalloc(sizeof(THING) * C2, ...)
    |
    kzalloc(sizeof(TYPE) * C2, ...)
    |
    kzalloc(C1 * C2 * C3, ...)
    |
    kzalloc(C1 * C2, ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(TYPE) * (E2)
    + E2, sizeof(TYPE)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(TYPE) * E2
    + E2, sizeof(TYPE)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(THING) * (E2)
    + E2, sizeof(THING)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - sizeof(THING) * E2
    + E2, sizeof(THING)
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - (E1) * E2
    + E1, E2
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - (E1) * (E2)
    + E1, E2
    , ...)
    |
    - kzalloc
    + kcalloc
    (
    - E1 * E2
    + E1, E2
    , ...)
    )

    Signed-off-by: Kees Cook

    Kees Cook
     
  • The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
    patch replaces cases of:

    kmalloc(a * b, gfp)

    with:
    kmalloc_array(a * b, gfp)

    as well as handling cases of:

    kmalloc(a * b * c, gfp)

    with:

    kmalloc(array3_size(a, b, c), gfp)

    as it's slightly less ugly than:

    kmalloc_array(array_size(a, b), c, gfp)

    This does, however, attempt to ignore constant size factors like:

    kmalloc(4 * 1024, gfp)

    though any constants defined via macros get caught up in the conversion.

    Any factors with a sizeof() of "unsigned char", "char", and "u8" were
    dropped, since they're redundant.

    The tools/ directory was manually excluded, since it has its own
    implementation of kmalloc().

    The Coccinelle script used for this was:

    // Fix redundant parens around sizeof().
    @@
    type TYPE;
    expression THING, E;
    @@

    (
    kmalloc(
    - (sizeof(TYPE)) * E
    + sizeof(TYPE) * E
    , ...)
    |
    kmalloc(
    - (sizeof(THING)) * E
    + sizeof(THING) * E
    , ...)
    )

    // Drop single-byte sizes and redundant parens.
    @@
    expression COUNT;
    typedef u8;
    typedef __u8;
    @@

    (
    kmalloc(
    - sizeof(u8) * (COUNT)
    + COUNT
    , ...)
    |
    kmalloc(
    - sizeof(__u8) * (COUNT)
    + COUNT
    , ...)
    |
    kmalloc(
    - sizeof(char) * (COUNT)
    + COUNT
    , ...)
    |
    kmalloc(
    - sizeof(unsigned char) * (COUNT)
    + COUNT
    , ...)
    |
    kmalloc(
    - sizeof(u8) * COUNT
    + COUNT
    , ...)
    |
    kmalloc(
    - sizeof(__u8) * COUNT
    + COUNT
    , ...)
    |
    kmalloc(
    - sizeof(char) * COUNT
    + COUNT
    , ...)
    |
    kmalloc(
    - sizeof(unsigned char) * COUNT
    + COUNT
    , ...)
    )

    // 2-factor product with sizeof(type/expression) and identifier or constant.
    @@
    type TYPE;
    expression THING;
    identifier COUNT_ID;
    constant COUNT_CONST;
    @@

    (
    - kmalloc
    + kmalloc_array
    (
    - sizeof(TYPE) * (COUNT_ID)
    + COUNT_ID, sizeof(TYPE)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(TYPE) * COUNT_ID
    + COUNT_ID, sizeof(TYPE)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(TYPE) * (COUNT_CONST)
    + COUNT_CONST, sizeof(TYPE)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(TYPE) * COUNT_CONST
    + COUNT_CONST, sizeof(TYPE)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(THING) * (COUNT_ID)
    + COUNT_ID, sizeof(THING)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(THING) * COUNT_ID
    + COUNT_ID, sizeof(THING)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(THING) * (COUNT_CONST)
    + COUNT_CONST, sizeof(THING)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(THING) * COUNT_CONST
    + COUNT_CONST, sizeof(THING)
    , ...)
    )

    // 2-factor product, only identifiers.
    @@
    identifier SIZE, COUNT;
    @@

    - kmalloc
    + kmalloc_array
    (
    - SIZE * COUNT
    + COUNT, SIZE
    , ...)

    // 3-factor product with 1 sizeof(type) or sizeof(expression), with
    // redundant parens removed.
    @@
    expression THING;
    identifier STRIDE, COUNT;
    type TYPE;
    @@

    (
    kmalloc(
    - sizeof(TYPE) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kmalloc(
    - sizeof(TYPE) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kmalloc(
    - sizeof(TYPE) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kmalloc(
    - sizeof(TYPE) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    kmalloc(
    - sizeof(THING) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    kmalloc(
    - sizeof(THING) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    kmalloc(
    - sizeof(THING) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    kmalloc(
    - sizeof(THING) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    )

    // 3-factor product with 2 sizeof(variable), with redundant parens removed.
    @@
    expression THING1, THING2;
    identifier COUNT;
    type TYPE1, TYPE2;
    @@

    (
    kmalloc(
    - sizeof(TYPE1) * sizeof(TYPE2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    kmalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    kmalloc(
    - sizeof(THING1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    kmalloc(
    - sizeof(THING1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    kmalloc(
    - sizeof(TYPE1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    |
    kmalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    )

    // 3-factor product, only identifiers, with redundant parens removed.
    @@
    identifier STRIDE, SIZE, COUNT;
    @@

    (
    kmalloc(
    - (COUNT) * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kmalloc(
    - COUNT * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kmalloc(
    - COUNT * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kmalloc(
    - (COUNT) * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kmalloc(
    - COUNT * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kmalloc(
    - (COUNT) * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kmalloc(
    - (COUNT) * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    kmalloc(
    - COUNT * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    )

    // Any remaining multi-factor products, first at least 3-factor products,
    // when they're not all constants...
    @@
    expression E1, E2, E3;
    constant C1, C2, C3;
    @@

    (
    kmalloc(C1 * C2 * C3, ...)
    |
    kmalloc(
    - (E1) * E2 * E3
    + array3_size(E1, E2, E3)
    , ...)
    |
    kmalloc(
    - (E1) * (E2) * E3
    + array3_size(E1, E2, E3)
    , ...)
    |
    kmalloc(
    - (E1) * (E2) * (E3)
    + array3_size(E1, E2, E3)
    , ...)
    |
    kmalloc(
    - E1 * E2 * E3
    + array3_size(E1, E2, E3)
    , ...)
    )

    // And then all remaining 2 factors products when they're not all constants,
    // keeping sizeof() as the second factor argument.
    @@
    expression THING, E1, E2;
    type TYPE;
    constant C1, C2, C3;
    @@

    (
    kmalloc(sizeof(THING) * C2, ...)
    |
    kmalloc(sizeof(TYPE) * C2, ...)
    |
    kmalloc(C1 * C2 * C3, ...)
    |
    kmalloc(C1 * C2, ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(TYPE) * (E2)
    + E2, sizeof(TYPE)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(TYPE) * E2
    + E2, sizeof(TYPE)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(THING) * (E2)
    + E2, sizeof(THING)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - sizeof(THING) * E2
    + E2, sizeof(THING)
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - (E1) * E2
    + E1, E2
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - (E1) * (E2)
    + E1, E2
    , ...)
    |
    - kmalloc
    + kmalloc_array
    (
    - E1 * E2
    + E1, E2
    , ...)
    )

    Signed-off-by: Kees Cook

    Kees Cook
     
  • Pull nfsd updates from Bruce Fields:
    "A relatively quiet cycle for nfsd.

    The largest piece is an RDMA update from Chuck Lever with new trace
    points, miscellaneous cleanups, and streamlining of the send and
    receive paths.

    Other than that, some miscellaneous bugfixes"

    * tag 'nfsd-4.18' of git://linux-nfs.org/~bfields/linux: (26 commits)
    nfsd: fix error handling in nfs4_set_delegation()
    nfsd: fix potential use-after-free in nfsd4_decode_getdeviceinfo
    Fix 16-byte memory leak in gssp_accept_sec_context_upcall
    svcrdma: Fix incorrect return value/type in svc_rdma_post_recvs
    svcrdma: Remove unused svc_rdma_op_ctxt
    svcrdma: Persistently allocate and DMA-map Send buffers
    svcrdma: Simplify svc_rdma_send()
    svcrdma: Remove post_send_wr
    svcrdma: Don't overrun the SGE array in svc_rdma_send_ctxt
    svcrdma: Introduce svc_rdma_send_ctxt
    svcrdma: Clean up Send SGE accounting
    svcrdma: Refactor svc_rdma_dma_map_buf
    svcrdma: Allocate recv_ctxt's on CPU handling Receives
    svcrdma: Persistently allocate and DMA-map Receive buffers
    svcrdma: Preserve Receive buffer until svc_rdma_sendto
    svcrdma: Simplify svc_rdma_recv_ctxt_put
    svcrdma: Remove sc_rq_depth
    svcrdma: Introduce svc_rdma_recv_ctxt
    svcrdma: Trace key RDMA API events
    svcrdma: Trace key RPC/RDMA protocol events
    ...

    Linus Torvalds
     

09 Jun, 2018

2 commits

  • I noticed a memory corruption crash in nfsd in
    4.17-rc1. This patch corrects the issue.

    Fix to return error if the delegation couldn't be hashed or there was
    a recall in progress. Use the existing error path instead of
    destroy_delegation() for readability.

    Signed-off-by: Andrew Elble
    Fixes: 353601e7d323c ("nfsd: create a separate lease for each delegation")
    Signed-off-by: J. Bruce Fields

    Andrew Elble
     
  • When running a fuzz tester against a KASAN-enabled kernel, the following
    splat periodically occurs.

    The problem occurs when the test sends a GETDEVICEINFO request with a
    malformed xdr array (size but no data) for gdia_notify_types and the
    array size is > 0x3fffffff, which results in an overflow in the value of
    nbytes which is passed to read_buf().

    If the array size is 0x40000000, 0x80000000, or 0xc0000000, then after
    the overflow occurs, the value of nbytes 0, and when that happens the
    pointer returned by read_buf() points to the end of the xdr data (i.e.
    argp->end) when really it should be returning NULL.

    Fix this by returning NFS4ERR_BAD_XDR if the array size is > 1000 (this
    value is arbitrary, but it's the same threshold used by
    nfsd4_decode_bitmap()... in could really be any value >= 1 since it's
    expected to get at most a single bitmap in gdia_notify_types).

    [ 119.256854] ==================================================================
    [ 119.257611] BUG: KASAN: use-after-free in nfsd4_decode_getdeviceinfo+0x5a4/0x5b0 [nfsd]
    [ 119.258422] Read of size 4 at addr ffff880113ada000 by task nfsd/538

    [ 119.259146] CPU: 0 PID: 538 Comm: nfsd Not tainted 4.17.0+ #1
    [ 119.259662] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.9.3-1.fc25 04/01/2014
    [ 119.261202] Call Trace:
    [ 119.262265] dump_stack+0x71/0xab
    [ 119.263371] print_address_description+0x6a/0x270
    [ 119.264609] kasan_report+0x258/0x380
    [ 119.265854] ? nfsd4_decode_getdeviceinfo+0x5a4/0x5b0 [nfsd]
    [ 119.267291] nfsd4_decode_getdeviceinfo+0x5a4/0x5b0 [nfsd]
    [ 119.268549] ? nfs4svc_decode_compoundargs+0xa5b/0x13c0 [nfsd]
    [ 119.269873] ? nfsd4_decode_sequence+0x490/0x490 [nfsd]
    [ 119.271095] nfs4svc_decode_compoundargs+0xa5b/0x13c0 [nfsd]
    [ 119.272393] ? nfsd4_release_compoundargs+0x1b0/0x1b0 [nfsd]
    [ 119.273658] nfsd_dispatch+0x183/0x850 [nfsd]
    [ 119.274918] svc_process+0x161c/0x31a0 [sunrpc]
    [ 119.276172] ? svc_printk+0x190/0x190 [sunrpc]
    [ 119.277386] ? svc_xprt_release+0x451/0x680 [sunrpc]
    [ 119.278622] nfsd+0x2b9/0x430 [nfsd]
    [ 119.279771] ? nfsd_destroy+0x1c0/0x1c0 [nfsd]
    [ 119.281157] kthread+0x2db/0x390
    [ 119.282347] ? kthread_create_worker_on_cpu+0xc0/0xc0
    [ 119.283756] ret_from_fork+0x35/0x40

    [ 119.286041] Allocated by task 436:
    [ 119.287525] kasan_kmalloc+0xa0/0xd0
    [ 119.288685] kmem_cache_alloc+0xe9/0x1f0
    [ 119.289900] get_empty_filp+0x7b/0x410
    [ 119.291037] path_openat+0xca/0x4220
    [ 119.292242] do_filp_open+0x182/0x280
    [ 119.293411] do_sys_open+0x216/0x360
    [ 119.294555] do_syscall_64+0xa0/0x2f0
    [ 119.295721] entry_SYSCALL_64_after_hwframe+0x44/0xa9

    [ 119.298068] Freed by task 436:
    [ 119.299271] __kasan_slab_free+0x130/0x180
    [ 119.300557] kmem_cache_free+0x78/0x210
    [ 119.301823] rcu_process_callbacks+0x35b/0xbd0
    [ 119.303162] __do_softirq+0x192/0x5ea

    [ 119.305443] The buggy address belongs to the object at ffff880113ada000
    which belongs to the cache filp of size 256
    [ 119.308556] The buggy address is located 0 bytes inside of
    256-byte region [ffff880113ada000, ffff880113ada100)
    [ 119.311376] The buggy address belongs to the page:
    [ 119.312728] page:ffffea00044eb680 count:1 mapcount:0 mapping:0000000000000000 index:0xffff880113ada780
    [ 119.314428] flags: 0x17ffe000000100(slab)
    [ 119.315740] raw: 0017ffe000000100 0000000000000000 ffff880113ada780 00000001000c0001
    [ 119.317379] raw: ffffea0004553c60 ffffea00045c11e0 ffff88011b167e00 0000000000000000
    [ 119.319050] page dumped because: kasan: bad access detected

    [ 119.321652] Memory state around the buggy address:
    [ 119.322993] ffff880113ad9f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    [ 119.324515] ffff880113ad9f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    [ 119.326087] >ffff880113ada000: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
    [ 119.327547] ^
    [ 119.328730] ffff880113ada080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
    [ 119.330218] ffff880113ada100: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
    [ 119.331740] ==================================================================

    Signed-off-by: Scott Mayhew
    Signed-off-by: J. Bruce Fields

    Scott Mayhew