26 May, 2019

2 commits

  • Convert the pipe filesystem to the new internal mount API as the old
    one will be obsoleted and removed. This allows greater flexibility in
    communication of mount parameters between userspace, the VFS and the
    filesystem.

    See Documentation/filesystems/mount_api.txt for more information.

    Signed-off-by: David Howells
    cc: linux-fsdevel@vger.kernel.org
    Signed-off-by: Al Viro

    David Howells
     
  • Once upon a time we used to set ->d_name of e.g. pipefs root
    so that d_path() on pipes would work. These days it's
    completely pointless - dentries of pipes are not even connected
    to pipefs root. However, mount_pseudo() had set the root
    dentry name (passed as the second argument) and callers
    kept inventing names to pass to it. Including those that
    didn't *have* any non-root dentries to start with...

    All of that had been pointless for about 8 years now; it's
    time to get rid of that cargo-culting...

    Signed-off-by: Al Viro

    Al Viro
     

15 Apr, 2019

2 commits

  • Merge page ref overflow branch.

    Jann Horn reported that he can overflow the page ref count with
    sufficient memory (and a filesystem that is intentionally extremely
    slow).

    Admittedly it's not exactly easy. To have more than four billion
    references to a page requires a minimum of 32GB of kernel memory just
    for the pointers to the pages, much less any metadata to keep track of
    those pointers. Jann needed a total of 140GB of memory and a specially
    crafted filesystem that leaves all reads pending (in order to not ever
    free the page references and just keep adding more).

    Still, we have a fairly straightforward way to limit the two obvious
    user-controllable sources of page references: direct-IO like page
    references gotten through get_user_pages(), and the splice pipe page
    duplication. So let's just do that.

    * branch page-refs:
    fs: prevent page refcount overflow in pipe_buf_get
    mm: prevent get_user_pages() from overflowing page refcount
    mm: add 'try_get_page()' helper function
    mm: make page ref count overflow check tighter and more explicit

    Linus Torvalds
     
  • Change pipe_buf_get() to return a bool indicating whether it succeeded
    in raising the refcount of the page (if the thing in the pipe is a page).
    This removes another mechanism for overflowing the page refcount. All
    callers converted to handle a failure.

    Reported-by: Jann Horn
    Signed-off-by: Matthew Wilcox
    Cc: stable@kernel.org
    Signed-off-by: Linus Torvalds

    Matthew Wilcox
     

13 Mar, 2019

1 commit

  • Pull misc vfs updates from Al Viro:
    "Assorted fixes (really no common topic here)"

    * 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
    vfs: Make __vfs_write() static
    vfs: fix preadv64v2 and pwritev64v2 compat syscalls with offset == -1
    pipe: stop using ->can_merge
    splice: don't merge into linked buffers
    fs: move generic stat response attr handling to vfs_getattr_nosec
    orangefs: don't reinitialize result_mask in ->getattr
    fs/devpts: always delete dcache dentry-s in dput()

    Linus Torvalds
     

06 Mar, 2019

1 commit

  • Move the memcg_kmem_enabled() checks into memcg kmem charge/uncharge
    functions, so, the users don't have to explicitly check that condition.

    This is purely code cleanup patch without any functional change. Only
    the order of checks in memcg_charge_slab() can potentially be changed
    but the functionally it will be same. This should not matter as
    memcg_charge_slab() is not in the hot path.

    Link: http://lkml.kernel.org/r/20190103161203.162375-1-shakeelb@google.com
    Signed-off-by: Shakeel Butt
    Acked-by: Michal Hocko
    Cc: Johannes Weiner
    Cc: Vladimir Davydov
    Cc: Roman Gushchin
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Shakeel Butt
     

01 Feb, 2019

2 commits

  • Al Viro pointed out that since there is only one pipe buffer type to which
    new data can be appended, it isn't necessary to have a ->can_merge field in
    struct pipe_buf_operations, we can just check for a magic type.

    Suggested-by: Al Viro
    Signed-off-by: Jann Horn
    Signed-off-by: Al Viro

    Jann Horn
     
  • Before this patch, it was possible for two pipes to affect each other after
    data had been transferred between them with tee():

    ============
    $ cat tee_test.c

    int main(void) {
    int pipe_a[2];
    if (pipe(pipe_a)) err(1, "pipe");
    int pipe_b[2];
    if (pipe(pipe_b)) err(1, "pipe");
    if (write(pipe_a[1], "abcd", 4) != 4) err(1, "write");
    if (tee(pipe_a[0], pipe_b[1], 2, 0) != 2) err(1, "tee");
    if (write(pipe_b[1], "xx", 2) != 2) err(1, "write");

    char buf[5];
    if (read(pipe_a[0], buf, 4) != 4) err(1, "read");
    buf[4] = 0;
    printf("got back: '%s'\n", buf);
    }
    $ gcc -o tee_test tee_test.c
    $ ./tee_test
    got back: 'abxx'
    $
    ============

    As suggested by Al Viro, fix it by creating a separate type for
    non-mergeable pipe buffers, then changing the types of buffers in
    splice_pipe_to_pipe() and link_pipe().

    Cc:
    Fixes: 7c77f0b3f920 ("splice: implement pipe to pipe splicing")
    Fixes: 70524490ee2e ("[PATCH] splice: add support for sys_tee()")
    Suggested-by: Al Viro
    Signed-off-by: Jann Horn
    Signed-off-by: Al Viro

    Jann Horn
     

14 Aug, 2018

1 commit

  • Pull vfs open-related updates from Al Viro:

    - "do we need fput() or put_filp()" rules are gone - it's always fput()
    now. We keep track of that state where it belongs - in ->f_mode.

    - int *opened mess killed - in finish_open(), in ->atomic_open()
    instances and in fs/namei.c code around do_last()/lookup_open()/atomic_open().

    - alloc_file() wrappers with saner calling conventions are introduced
    (alloc_file_clone() and alloc_file_pseudo()); callers converted, with
    much simplification.

    - while we are at it, saner calling conventions for path_init() and
    link_path_walk(), simplifying things inside fs/namei.c (both on
    open-related paths and elsewhere).

    * 'work.open3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits)
    few more cleanups of link_path_walk() callers
    allow link_path_walk() to take ERR_PTR()
    make path_init() unconditionally paired with terminate_walk()
    document alloc_file() changes
    make alloc_file() static
    do_shmat(): grab shp->shm_file earlier, switch to alloc_file_clone()
    new helper: alloc_file_clone()
    create_pipe_files(): switch the first allocation to alloc_file_pseudo()
    anon_inode_getfile(): switch to alloc_file_pseudo()
    hugetlb_file_setup(): switch to alloc_file_pseudo()
    ocxlflash_getfile(): switch to alloc_file_pseudo()
    cxl_getfile(): switch to alloc_file_pseudo()
    ... and switch shmem_file_setup() to alloc_file_pseudo()
    __shmem_file_setup(): reorder allocations
    new wrapper: alloc_file_pseudo()
    kill FILE_{CREATED,OPENED}
    switch atomic_open() and lookup_open() to returning 0 in all success cases
    document ->atomic_open() changes
    ->atomic_open(): return 0 in all success cases
    get rid of 'opened' in path_openat() and the helpers downstream
    ...

    Linus Torvalds
     

12 Jul, 2018

3 commits


11 Jul, 2018

1 commit


29 Jun, 2018

1 commit

  • The poll() changes were not well thought out, and completely
    unexplained. They also caused a huge performance regression, because
    "->poll()" was no longer a trivial file operation that just called down
    to the underlying file operations, but instead did at least two indirect
    calls.

    Indirect calls are sadly slow now with the Spectre mitigation, but the
    performance problem could at least be largely mitigated by changing the
    "->get_poll_head()" operation to just have a per-file-descriptor pointer
    to the poll head instead. That gets rid of one of the new indirections.

    But that doesn't fix the new complexity that is completely unwarranted
    for the regular case. The (undocumented) reason for the poll() changes
    was some alleged AIO poll race fixing, but we don't make the common case
    slower and more complex for some uncommon special case, so this all
    really needs way more explanations and most likely a fundamental
    redesign.

    [ This revert is a revert of about 30 different commits, not reverted
    individually because that would just be unnecessarily messy - Linus ]

    Cc: Al Viro
    Cc: Christoph Hellwig
    Signed-off-by: Linus Torvalds

    Linus Torvalds
     

26 May, 2018

1 commit


03 Apr, 2018

1 commit


12 Feb, 2018

1 commit

  • This is the mindless scripted replacement of kernel use of POLL*
    variables as described by Al, done by this script:

    for V in IN OUT PRI ERR RDNORM RDBAND WRNORM WRBAND HUP RDHUP NVAL MSG; do
    L=`git grep -l -w POLL$V | grep -v '^t' | grep -v /um/ | grep -v '^sa' | grep -v '/poll.h$'|grep -v '^D'`
    for f in $L; do sed -i "-es/^\([^\"]*\)\(\\)/\\1E\\2/" $f; done
    done

    with de-mangling cleanups yet to come.

    NOTE! On almost all architectures, the EPOLL* constants have the same
    values as the POLL* constants do. But they keyword here is "almost".
    For various bad reasons they aren't the same, and epoll() doesn't
    actually work quite correctly in some cases due to this on Sparc et al.

    The next patch from Al will sort out the final differences, and we
    should be all done.

    Scripted-by: Al Viro
    Signed-off-by: Linus Torvalds

    Linus Torvalds
     

07 Feb, 2018

7 commits

  • The pipe buffer limits are accessed without any locking, and may be
    changed at any time by the sysctl handlers. In theory this could cause
    problems for expressions like the following:

    pipe_user_pages_hard && user_bufs > pipe_user_pages_hard

    ... since the assembly code might reference the 'pipe_user_pages_hard'
    memory location multiple times, and if the admin removes the limit by
    setting it to 0, there is a very brief window where processes could
    incorrectly observe the limit to be exceeded.

    Fix this by loading the limits with READ_ONCE() prior to use.

    Link: http://lkml.kernel.org/r/20180111052902.14409-8-ebiggers3@gmail.com
    Signed-off-by: Eric Biggers
    Acked-by: Kees Cook
    Acked-by: Joe Lawrence
    Cc: Alexander Viro
    Cc: Michael Kerrisk
    Cc: Willy Tarreau
    Cc: Mikulas Patocka
    Cc: "Luis R . Rodriguez"
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Biggers
     
  • round_pipe_size() calculates the number of pages the requested size
    corresponds to, then rounds the page count up to the next power of 2.

    However, it also rounds everything < PAGE_SIZE up to PAGE_SIZE.
    Therefore, there's no need to actually translate the size into a page
    count; we just need to round the size up to the next power of 2.

    We do need to verify the size isn't greater than (1 << 31), since on
    32-bit systems roundup_pow_of_two() would be undefined in that case. But
    that can just be combined with the UINT_MAX check which we need anyway
    now.

    Finally, update pipe_set_size() to not redundantly check the return value
    of round_pipe_size() for the "invalid size" case twice.

    Link: http://lkml.kernel.org/r/20180111052902.14409-7-ebiggers3@gmail.com
    Signed-off-by: Eric Biggers
    Acked-by: Kees Cook
    Acked-by: Joe Lawrence
    Cc: Alexander Viro
    Cc: "Luis R . Rodriguez"
    Cc: Michael Kerrisk
    Cc: Mikulas Patocka
    Cc: Willy Tarreau
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Biggers
     
  • A pipe's size is represented as an 'unsigned int'. As expected, writing a
    value greater than UINT_MAX to /proc/sys/fs/pipe-max-size fails with
    EINVAL. However, the F_SETPIPE_SZ fcntl silently truncates such values to
    32 bits, rather than failing with EINVAL as expected. (It *does* fail
    with EINVAL for values above (1 << 31) but
    Acked-by: Kees Cook
    Acked-by: Joe Lawrence
    Cc: Alexander Viro
    Cc: "Luis R . Rodriguez"
    Cc: Michael Kerrisk
    Cc: Mikulas Patocka
    Cc: Willy Tarreau
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Biggers
     
  • With pipe-user-pages-hard set to 'N', users were actually only allowed up
    to 'N - 1' buffers; and likewise for pipe-user-pages-soft.

    Fix this to allow up to 'N' buffers, as would be expected.

    Link: http://lkml.kernel.org/r/20180111052902.14409-5-ebiggers3@gmail.com
    Fixes: b0b91d18e2e9 ("pipe: fix limit checking in pipe_set_size()")
    Signed-off-by: Eric Biggers
    Acked-by: Willy Tarreau
    Acked-by: Kees Cook
    Acked-by: Joe Lawrence
    Cc: Alexander Viro
    Cc: "Luis R . Rodriguez"
    Cc: Michael Kerrisk
    Cc: Mikulas Patocka
    Cc:
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Biggers
     
  • pipe-user-pages-hard and pipe-user-pages-soft are only supposed to apply
    to unprivileged users, as documented in both Documentation/sysctl/fs.txt
    and the pipe(7) man page.

    However, the capabilities are actually only checked when increasing a
    pipe's size using F_SETPIPE_SZ, not when creating a new pipe. Therefore,
    if pipe-user-pages-hard has been set, the root user can run into it and be
    unable to create pipes. Similarly, if pipe-user-pages-soft has been set,
    the root user can run into it and have their pipes limited to 1 page each.

    Fix this by allowing the privileged override in both cases.

    Link: http://lkml.kernel.org/r/20180111052902.14409-4-ebiggers3@gmail.com
    Fixes: 759c01142a5d ("pipe: limit the per-user amount of pages allocated in pipes")
    Signed-off-by: Eric Biggers
    Acked-by: Kees Cook
    Acked-by: Joe Lawrence
    Cc: Alexander Viro
    Cc: "Luis R . Rodriguez"
    Cc: Michael Kerrisk
    Cc: Mikulas Patocka
    Cc: Willy Tarreau
    Cc:
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Biggers
     
  • pipe_proc_fn() is no longer needed, as it only calls through to
    proc_dopipe_max_size(). Just put proc_dopipe_max_size() in the ctl_table
    entry directly, and remove the unneeded EXPORT_SYMBOL() and the ENOSYS
    stub for it.

    (The reason the ENOSYS stub isn't needed is that the pipe-max-size
    ctl_table entry is located directly in 'kern_table' rather than being
    registered separately. Therefore, the entry is already only defined when
    the kernel is built with sysctl support.)

    Link: http://lkml.kernel.org/r/20180111052902.14409-3-ebiggers3@gmail.com
    Signed-off-by: Eric Biggers
    Acked-by: Kees Cook
    Acked-by: Joe Lawrence
    Cc: Alexander Viro
    Cc: "Luis R . Rodriguez"
    Cc: Michael Kerrisk
    Cc: Mikulas Patocka
    Cc: Willy Tarreau
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Biggers
     
  • Patch series "pipe: buffer limits fixes and cleanups", v2.

    This series simplifies the sysctl handler for pipe-max-size and fixes
    another set of bugs related to the pipe buffer limits:

    - The root user wasn't allowed to exceed the limits when creating new
    pipes.

    - There was an off-by-one error when checking the limits, so a limit of
    N was actually treated as N - 1.

    - F_SETPIPE_SZ accepted values over UINT_MAX.

    - Reading the pipe buffer limits could be racy.

    This patch (of 7):

    Before validating the given value against pipe_min_size,
    do_proc_dopipe_max_size_conv() calls round_pipe_size(), which rounds the
    value up to pipe_min_size. Therefore, the second check against
    pipe_min_size is redundant. Remove it.

    Link: http://lkml.kernel.org/r/20180111052902.14409-2-ebiggers3@gmail.com
    Signed-off-by: Eric Biggers
    Acked-by: Kees Cook
    Acked-by: Joe Lawrence
    Cc: Alexander Viro
    Cc: "Luis R . Rodriguez"
    Cc: Michael Kerrisk
    Cc: Mikulas Patocka
    Cc: Willy Tarreau
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Biggers
     

28 Nov, 2017

1 commit


18 Nov, 2017

3 commits

  • pipe_max_size is assigned directly via procfs sysctl:

    static struct ctl_table fs_table[] = {
    ...
    {
    .procname = "pipe-max-size",
    .data = &pipe_max_size,
    .maxlen = sizeof(int),
    .mode = 0644,
    .proc_handler = &pipe_proc_fn,
    .extra1 = &pipe_min_size,
    },
    ...

    int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
    size_t *lenp, loff_t *ppos)
    {
    ...
    ret = proc_dointvec_minmax(table, write, buf, lenp, ppos)
    ...

    and then later rounded in-place a few statements later:

    ...
    pipe_max_size = round_pipe_size(pipe_max_size);
    ...

    This leaves a window of time between initial assignment and rounding
    that may be visible to other threads. (For example, one thread sets a
    non-rounded value to pipe_max_size while another reads its value.)

    Similar reads of pipe_max_size are potentially racy:

    pipe.c :: alloc_pipe_info()
    pipe.c :: pipe_set_size()

    Add a new proc_dopipe_max_size() that consolidates reading the new value
    from the user buffer, verifying bounds, and calling round_pipe_size()
    with a single assignment to pipe_max_size.

    Link: http://lkml.kernel.org/r/1507658689-11669-4-git-send-email-joe.lawrence@redhat.com
    Signed-off-by: Joe Lawrence
    Reported-by: Mikulas Patocka
    Reviewed-by: Mikulas Patocka
    Cc: Al Viro
    Cc: Jens Axboe
    Cc: Michael Kerrisk
    Cc: Randy Dunlap
    Cc: Josh Poimboeuf
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Joe Lawrence
     
  • round_pipe_size() contains a right-bit-shift expression which may
    overflow, which would cause undefined results in a subsequent
    roundup_pow_of_two() call.

    static inline unsigned int round_pipe_size(unsigned int size)
    {
    unsigned long nr_pages;

    nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
    return roundup_pow_of_two(nr_pages) << PAGE_SHIFT;
    }

    PAGE_SIZE is defined as (1UL << PAGE_SHIFT), so:
    - 4 bytes wide on 32-bit (0 to 0xffffffff)
    - 8 bytes wide on 64-bit (0 to 0xffffffffffffffff)

    That means that 32-bit round_pipe_size(), nr_pages may overflow to 0:

    size=0x00000000 nr_pages=0x0
    size=0x00000001 nr_pages=0x1
    size=0xfffff000 nr_pages=0xfffff
    size=0xfffff001 nr_pages=0x0 << !
    size=0xffffffff nr_pages=0x0 << !

    This is bad because roundup_pow_of_two(n) is undefined when n == 0!

    64-bit is not a problem as the unsigned int size is 4 bytes wide
    (similar to 32-bit) and the larger, 8 byte wide unsigned long, is
    sufficient to handle the largest value of the bit shift expression:

    size=0xffffffff nr_pages=100000

    Modify round_pipe_size() to return 0 if n == 0 and updates its callers to
    handle accordingly.

    Link: http://lkml.kernel.org/r/1507658689-11669-3-git-send-email-joe.lawrence@redhat.com
    Signed-off-by: Joe Lawrence
    Reported-by: Mikulas Patocka
    Reviewed-by: Mikulas Patocka
    Cc: Al Viro
    Cc: Jens Axboe
    Cc: Michael Kerrisk
    Cc: Randy Dunlap
    Cc: Josh Poimboeuf
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Joe Lawrence
     
  • Patch series "A few round_pipe_size() and pipe-max-size fixups", v3.

    While backporting Michael's "pipe: fix limit handling" patchset to a
    distro-kernel, Mikulas noticed that current upstream pipe limit handling
    contains a few problems:

    1 - procfs signed wrap: echo'ing a large number into
    /proc/sys/fs/pipe-max-size and then cat'ing it back out shows a
    negative value.

    2 - round_pipe_size() nr_pages overflow on 32bit: this would
    subsequently try roundup_pow_of_two(0), which is undefined.

    3 - visible non-rounded pipe-max-size value: there is no mutual
    exclusion or protection between the time pipe_max_size is assigned
    a raw value from proc_dointvec_minmax() and when it is rounded.

    4 - unsigned long -> unsigned int conversion makes for potential odd
    return errors from do_proc_douintvec_minmax_conv() and
    do_proc_dopipe_max_size_conv().

    This version underwent the same testing as v1:
    https://marc.info/?l=linux-kernel&m=150643571406022&w=2

    This patch (of 4):

    pipe_max_size is defined as an unsigned int:

    unsigned int pipe_max_size = 1048576;

    but its procfs/sysctl representation is an integer:

    static struct ctl_table fs_table[] = {
    ...
    {
    .procname = "pipe-max-size",
    .data = &pipe_max_size,
    .maxlen = sizeof(int),
    .mode = 0644,
    .proc_handler = &pipe_proc_fn,
    .extra1 = &pipe_min_size,
    },
    ...

    that is signed:

    int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
    size_t *lenp, loff_t *ppos)
    {
    ...
    ret = proc_dointvec_minmax(table, write, buf, lenp, ppos)

    This leads to signed results via procfs for large values of pipe_max_size:

    % echo 2147483647 >/proc/sys/fs/pipe-max-size
    % cat /proc/sys/fs/pipe-max-size
    -2147483648

    Use unsigned operations on this variable to avoid such negative values.

    Link: http://lkml.kernel.org/r/1507658689-11669-2-git-send-email-joe.lawrence@redhat.com
    Signed-off-by: Joe Lawrence
    Reported-by: Mikulas Patocka
    Reviewed-by: Mikulas Patocka
    Cc: Michael Kerrisk
    Cc: Randy Dunlap
    Cc: Al Viro
    Cc: Jens Axboe
    Cc: Josh Poimboeuf
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Joe Lawrence
     

02 Nov, 2017

1 commit

  • Many source files in the tree are missing licensing information, which
    makes it harder for compliance tools to determine the correct license.

    By default all files without license information are under the default
    license of the kernel, which is GPL version 2.

    Update the files which contain no license information with the 'GPL-2.0'
    SPDX license identifier. The SPDX identifier is a legally binding
    shorthand, which can be used instead of the full boiler plate text.

    This patch is based on work done by Thomas Gleixner and Kate Stewart and
    Philippe Ombredanne.

    How this work was done:

    Patches were generated and checked against linux-4.14-rc6 for a subset of
    the use cases:
    - file had no licensing information it it.
    - file was a */uapi/* one with no licensing information in it,
    - file was a */uapi/* one with existing licensing information,

    Further patches will be generated in subsequent months to fix up cases
    where non-standard license headers were used, and references to license
    had to be inferred by heuristics based on keywords.

    The analysis to determine which SPDX License Identifier to be applied to
    a file was done in a spreadsheet of side by side results from of the
    output of two independent scanners (ScanCode & Windriver) producing SPDX
    tag:value files created by Philippe Ombredanne. Philippe prepared the
    base worksheet, and did an initial spot review of a few 1000 files.

    The 4.13 kernel was the starting point of the analysis with 60,537 files
    assessed. Kate Stewart did a file by file comparison of the scanner
    results in the spreadsheet to determine which SPDX license identifier(s)
    to be applied to the file. She confirmed any determination that was not
    immediately clear with lawyers working with the Linux Foundation.

    Criteria used to select files for SPDX license identifier tagging was:
    - Files considered eligible had to be source code files.
    - Make and config files were included as candidates if they contained >5
    lines of source
    - File already had some variant of a license header in it (even if
    Reviewed-by: Philippe Ombredanne
    Reviewed-by: Thomas Gleixner
    Signed-off-by: Greg Kroah-Hartman

    Greg Kroah-Hartman
     

06 Jul, 2017

1 commit


25 Dec, 2016

1 commit


12 Oct, 2016

8 commits

  • This is a patch that provides behavior that is more consistent, and
    probably less surprising to users. I consider the change optional, and
    welcome opinions about whether it should be applied.

    By default, pipes are created with a capacity of 64 kiB. However,
    /proc/sys/fs/pipe-max-size may be set smaller than this value. In this
    scenario, an unprivileged user could thus create a pipe whose initial
    capacity exceeds the limit. Therefore, it seems logical to cap the
    initial pipe capacity according to the value of pipe-max-size.

    The test program shown earlier in this patch series can be used to
    demonstrate the effect of the change brought about with this patch:

    # cat /proc/sys/fs/pipe-max-size
    1048576
    # sudo -u mtk ./test_F_SETPIPE_SZ 1
    Initial pipe capacity: 65536
    # echo 10000 > /proc/sys/fs/pipe-max-size
    # cat /proc/sys/fs/pipe-max-size
    16384
    # sudo -u mtk ./test_F_SETPIPE_SZ 1
    Initial pipe capacity: 16384
    # ./test_F_SETPIPE_SZ 1
    Initial pipe capacity: 65536

    The last two executions of 'test_F_SETPIPE_SZ' show that pipe-max-size
    caps the initial allocation for a new pipe for unprivileged users, but
    not for privileged users.

    Link: http://lkml.kernel.org/r/31dc7064-2a17-9c5b-1df1-4e3012ee992c@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     
  • This is an optional patch, to provide a small performance
    improvement. Alter account_pipe_buffers() so that it returns the
    new value in user->pipe_bufs. This means that we can refactor
    too_many_pipe_buffers_soft() and too_many_pipe_buffers_hard() to
    avoid the costs of repeated use of atomic_long_read() to get the
    value user->pipe_bufs.

    Link: http://lkml.kernel.org/r/93e5f193-1e5e-3e1f-3a20-eae79b7e1310@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     
  • The limit checking in alloc_pipe_info() (used by pipe(2) and when
    opening a FIFO) has the following problems:

    (1) When checking capacity required for the new pipe, the checks against
    the limit in /proc/sys/fs/pipe-user-pages-{soft,hard} are made
    against existing consumption, and exclude the memory required for
    the new pipe capacity. As a consequence: (1) the memory allocation
    throttling provided by the soft limit does not kick in quite as
    early as it should, and (2) the user can overrun the hard limit.

    (2) As currently implemented, accounting and checking against the limits
    is done as follows:

    (a) Test whether the user has exceeded the limit.
    (b) Make new pipe buffer allocation.
    (c) Account new allocation against the limits.

    This is racey. Multiple processes may pass point (a) simultaneously,
    and then allocate pipe buffers that are accounted for only in step
    (c). The race means that the user's pipe buffer allocation could be
    pushed over the limit (by an arbitrary amount, depending on how
    unlucky we were in the race). [Thanks to Vegard Nossum for spotting
    this point, which I had missed.]

    This patch addresses the above problems as follows:

    * Alter the checks against limits to include the memory required for the
    new pipe.
    * Re-order the accounting step so that it precedes the buffer allocation.
    If the accounting step determines that a limit has been reached, revert
    the accounting and cause the operation to fail.

    Link: http://lkml.kernel.org/r/8ff3e9f9-23f6-510c-644f-8e70cd1c0bd9@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     
  • Replace an 'if' block that covers most of the code in this function
    with a 'goto'. This makes the code a little simpler to read, and also
    simplifies the next patch (fix limit checking in alloc_pipe_info())

    Link: http://lkml.kernel.org/r/aef030c1-0257-98a9-4988-186efa48530c@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     
  • The limit checking in pipe_set_size() (used by fcntl(F_SETPIPE_SZ))
    has the following problems:

    (1) When increasing the pipe capacity, the checks against the limits in
    /proc/sys/fs/pipe-user-pages-{soft,hard} are made against existing
    consumption, and exclude the memory required for the increased pipe
    capacity. The new increase in pipe capacity can then push the total
    memory used by the user for pipes (possibly far) over a limit. This
    can also trigger the problem described next.

    (2) The limit checks are performed even when the new pipe capacity is
    less than the existing pipe capacity. This can lead to problems if a
    user sets a large pipe capacity, and then the limits are lowered,
    with the result that the user will no longer be able to decrease the
    pipe capacity.

    (3) As currently implemented, accounting and checking against the
    limits is done as follows:

    (a) Test whether the user has exceeded the limit.
    (b) Make new pipe buffer allocation.
    (c) Account new allocation against the limits.

    This is racey. Multiple processes may pass point (a)
    simultaneously, and then allocate pipe buffers that are accounted
    for only in step (c). The race means that the user's pipe buffer
    allocation could be pushed over the limit (by an arbitrary amount,
    depending on how unlucky we were in the race). [Thanks to Vegard
    Nossum for spotting this point, which I had missed.]

    This patch addresses the above problems as follows:

    * Perform checks against the limits only when increasing a pipe's
    capacity; an unprivileged user can always decrease a pipe's capacity.
    * Alter the checks against limits to include the memory required for
    the new pipe capacity.
    * Re-order the accounting step so that it precedes the buffer
    allocation. If the accounting step determines that a limit has
    been reached, revert the accounting and cause the operation to fail.

    The program below can be used to demonstrate problems 1 and 2, and the
    effect of the fix. The program takes one or more command-line arguments.
    The first argument specifies the number of pipes that the program should
    create. The remaining arguments are, alternately, pipe capacities that
    should be set using fcntl(F_SETPIPE_SZ), and sleep intervals (in
    seconds) between the fcntl() operations. (The sleep intervals allow the
    possibility to change the limits between fcntl() operations.)

    Problem 1
    =========

    Using the test program on an unpatched kernel, we first set some
    limits:

    # echo 0 > /proc/sys/fs/pipe-user-pages-soft
    # echo 1000000000 > /proc/sys/fs/pipe-max-size
    # echo 10000 > /proc/sys/fs/pipe-user-pages-hard # 40.96 MB

    Then show that we can set a pipe with capacity (100MB) that is
    over the hard limit

    # sudo -u mtk ./test_F_SETPIPE_SZ 1 100000000
    Initial pipe capacity: 65536
    Loop 1: set pipe capacity to 100000000 bytes
    F_SETPIPE_SZ returned 134217728

    Now set the capacity to 100MB twice. The second call fails (which is
    probably surprising to most users, since it seems like a no-op):

    # sudo -u mtk ./test_F_SETPIPE_SZ 1 100000000 0 100000000
    Initial pipe capacity: 65536
    Loop 1: set pipe capacity to 100000000 bytes
    F_SETPIPE_SZ returned 134217728
    Loop 2: set pipe capacity to 100000000 bytes
    Loop 2, pipe 0: F_SETPIPE_SZ failed: fcntl: Operation not permitted

    With a patched kernel, setting a capacity over the limit fails at the
    first attempt:

    # echo 0 > /proc/sys/fs/pipe-user-pages-soft
    # echo 1000000000 > /proc/sys/fs/pipe-max-size
    # echo 10000 > /proc/sys/fs/pipe-user-pages-hard
    # sudo -u mtk ./test_F_SETPIPE_SZ 1 100000000
    Initial pipe capacity: 65536
    Loop 1: set pipe capacity to 100000000 bytes
    Loop 1, pipe 0: F_SETPIPE_SZ failed: fcntl: Operation not permitted

    There is a small chance that the change to fix this problem could
    break user-space, since there are cases where fcntl(F_SETPIPE_SZ)
    calls that previously succeeded might fail. However, the chances are
    small, since (a) the pipe-user-pages-{soft,hard} limits are new (in
    4.5), and the default soft/hard limits are high/unlimited. Therefore,
    it seems warranted to make these limits operate more precisely (and
    behave more like what users probably expect).

    Problem 2
    =========

    Running the test program on an unpatched kernel, we first set some limits:

    # getconf PAGESIZE
    4096
    # echo 0 > /proc/sys/fs/pipe-user-pages-soft
    # echo 1000000000 > /proc/sys/fs/pipe-max-size
    # echo 10000 > /proc/sys/fs/pipe-user-pages-hard # 40.96 MB

    Now perform two fcntl(F_SETPIPE_SZ) operations on a single pipe,
    first setting a pipe capacity (10MB), sleeping for a few seconds,
    during which time the hard limit is lowered, and then set pipe
    capacity to a smaller amount (5MB):

    # sudo -u mtk ./test_F_SETPIPE_SZ 1 10000000 15 5000000 &
    [1] 748
    # Initial pipe capacity: 65536
    Loop 1: set pipe capacity to 10000000 bytes
    F_SETPIPE_SZ returned 16777216
    Sleeping 15 seconds

    # echo 1000 > /proc/sys/fs/pipe-user-pages-hard # 4.096 MB
    # Loop 2: set pipe capacity to 5000000 bytes
    Loop 2, pipe 0: F_SETPIPE_SZ failed: fcntl: Operation not permitted

    In this case, the user should be able to lower the limit.

    With a kernel that has the patch below, the second fcntl()
    succeeds:

    # echo 0 > /proc/sys/fs/pipe-user-pages-soft
    # echo 1000000000 > /proc/sys/fs/pipe-max-size
    # echo 10000 > /proc/sys/fs/pipe-user-pages-hard
    # sudo -u mtk ./test_F_SETPIPE_SZ 1 10000000 15 5000000 &
    [1] 3215
    # Initial pipe capacity: 65536
    # Loop 1: set pipe capacity to 10000000 bytes
    F_SETPIPE_SZ returned 16777216
    Sleeping 15 seconds

    # echo 1000 > /proc/sys/fs/pipe-user-pages-hard

    # Loop 2: set pipe capacity to 5000000 bytes
    F_SETPIPE_SZ returned 8388608

    8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---

    /* test_F_SETPIPE_SZ.c

    (C) 2016, Michael Kerrisk; licensed under GNU GPL version 2 or later

    Test operation of fcntl(F_SETPIPE_SZ) for setting pipe capacity
    and interactions with limits defined by /proc/sys/fs/pipe-* files.
    */

    #define _GNU_SOURCE
    #include
    #include
    #include
    #include

    int
    main(int argc, char *argv[])
    {
    int (*pfd)[2];
    int npipes;
    int pcap, rcap;
    int j, p, s, stime, loop;

    if (argc < 2) {
    fprintf(stderr, "Usage: %s num-pipes "
    "[pipe-capacity sleep-time]...\n", argv[0]);
    exit(EXIT_FAILURE);
    }

    npipes = atoi(argv[1]);

    pfd = calloc(npipes, sizeof (int [2]));
    if (pfd == NULL) {
    perror("calloc");
    exit(EXIT_FAILURE);
    }

    for (j = 0; j < npipes; j++) {
    if (pipe(pfd[j]) == -1) {
    fprintf(stderr, "Loop %d: pipe() failed: ", j);
    perror("pipe");
    exit(EXIT_FAILURE);
    }
    }

    printf("Initial pipe capacity: %d\n", fcntl(pfd[0][0], F_GETPIPE_SZ));

    for (j = 2; j < argc; j += 2 ) {
    loop = j / 2;
    pcap = atoi(argv[j]);
    printf(" Loop %d: set pipe capacity to %d bytes\n", loop, pcap);

    for (p = 0; p < npipes; p++) {
    s = fcntl(pfd[p][0], F_SETPIPE_SZ, pcap);
    if (s == -1) {
    fprintf(stderr, " Loop %d, pipe %d: F_SETPIPE_SZ "
    "failed: ", loop, p);
    perror("fcntl");
    exit(EXIT_FAILURE);
    }

    if (p == 0) {
    printf(" F_SETPIPE_SZ returned %d\n", s);
    rcap = s;
    } else {
    if (s != rcap) {
    fprintf(stderr, " Loop %d, pipe %d: F_SETPIPE_SZ "
    "unexpected return: %d\n", loop, p, s);
    exit(EXIT_FAILURE);
    }
    }

    stime = (j + 1 < argc) ? atoi(argv[j + 1]) : 0;
    if (stime > 0) {
    printf(" Sleeping %d seconds\n", stime);
    sleep(stime);
    }
    }
    }

    exit(EXIT_SUCCESS);
    }

    8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---8x---

    Patch history:

    v2
    * Switch order of test in 'if' statement to avoid function call
    (to capability()) in normal path. [This is a fix to a preexisting
    wart in the code. Thanks to Willy Tarreau]
    * Perform (size > pipe_max_size) check before calling
    account_pipe_buffers(). [Thanks to Vegard Nossum]
    Quoting Vegard:

    The potential problem happens if the user passes a very large number
    which will overflow pipe->user->pipe_bufs.

    On 32-bit, sizeof(int) == sizeof(long), so if they pass arg = INT_MAX
    then round_pipe_size() returns INT_MAX. Although it's true that the
    accounting is done in terms of pages and not bytes, so you'd need on
    the order of (1 << 13) = 8192 processes hitting the limit at the same
    time in order to make it overflow, which seems a bit unlikely.

    (See https://lkml.org/lkml/2016/8/12/215 for another discussion on the
    limit checking)

    Link: http://lkml.kernel.org/r/1e464945-536b-2420-798b-e77b9c7e8593@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     
  • This is a preparatory patch for following work. account_pipe_buffers()
    performs accounting in the 'user_struct'. There is no need to pass a
    pointer to a 'pipe_inode_info' struct (which is then dereferenced to
    obtain a pointer to the 'user' field). Instead, pass a pointer directly
    to the 'user_struct'. This change is needed in preparation for a
    subsequent patch that the fixes the limit checking in alloc_pipe_info()
    (and the resulting code is a little more logical).

    Link: http://lkml.kernel.org/r/7277bf8c-a6fc-4a7d-659c-f5b145c981ab@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     
  • This is a preparatory patch for following work. Move the F_SETPIPE_SZ
    limit-checking logic from pipe_fcntl() into pipe_set_size(). This
    simplifies the code a little, and allows for reworking required in
    a later patch that fixes the limit checking in pipe_set_size()

    Link: http://lkml.kernel.org/r/3701b2c5-2c52-2c3e-226d-29b9deb29b50@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     
  • Patch series "pipe: fix limit handling", v2.

    When changing a pipe's capacity with fcntl(F_SETPIPE_SZ), various limits
    defined by /proc/sys/fs/pipe-* files are checked to see if unprivileged
    users are exceeding limits on memory consumption.

    While documenting and testing the operation of these limits I noticed
    that, as currently implemented, these checks have a number of problems:

    (1) When increasing the pipe capacity, the checks against the limits
    in /proc/sys/fs/pipe-user-pages-{soft,hard} are made against
    existing consumption, and exclude the memory required for the
    increased pipe capacity. The new increase in pipe capacity can then
    push the total memory used by the user for pipes (possibly far) over
    a limit. This can also trigger the problem described next.

    (2) The limit checks are performed even when the new pipe capacity
    is less than the existing pipe capacity. This can lead to problems
    if a user sets a large pipe capacity, and then the limits are
    lowered, with the result that the user will no longer be able to
    decrease the pipe capacity.

    (3) As currently implemented, accounting and checking against the
    limits is done as follows:

    (a) Test whether the user has exceeded the limit.
    (b) Make new pipe buffer allocation.
    (c) Account new allocation against the limits.

    This is racey. Multiple processes may pass point (a) simultaneously,
    and then allocate pipe buffers that are accounted for only in step
    (c). The race means that the user's pipe buffer allocation could be
    pushed over the limit (by an arbitrary amount, depending on how
    unlucky we were in the race). [Thanks to Vegard Nossum for spotting
    this point, which I had missed.]

    This patch series addresses these three problems.

    This patch (of 8):

    This is a minor preparatory patch. After subsequent patches,
    round_pipe_size() will be called from pipe_set_size(), so place
    round_pipe_size() above pipe_set_size().

    Link: http://lkml.kernel.org/r/91a91fdb-a959-ba7f-b551-b62477cc98a1@gmail.com
    Signed-off-by: Michael Kerrisk
    Reviewed-by: Vegard Nossum
    Cc: Willy Tarreau
    Cc:
    Cc: Tetsuo Handa
    Cc: Jens Axboe
    Cc: Al Viro
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Michael Kerrisk (man-pages)
     

11 Oct, 2016

1 commit

  • Pull more vfs updates from Al Viro:
    ">rename2() work from Miklos + current_time() from Deepa"

    * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
    fs: Replace current_fs_time() with current_time()
    fs: Replace CURRENT_TIME_SEC with current_time() for inode timestamps
    fs: Replace CURRENT_TIME with current_time() for inode timestamps
    fs: proc: Delete inode time initializations in proc_alloc_inode()
    vfs: Add current_time() api
    vfs: add note about i_op->rename changes to porting
    fs: rename "rename2" i_op to "rename"
    vfs: remove unused i_op->rename
    fs: make remaining filesystems use .rename2
    libfs: support RENAME_NOREPLACE in simple_rename()
    fs: support RENAME_NOREPLACE for local filesystems
    ncpfs: fix unused variable warning

    Linus Torvalds