From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE, SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D16AAC433E7 for ; Fri, 16 Oct 2020 18:30:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5F9BF2084C for ; Fri, 16 Oct 2020 18:30:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DMcDY/PO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391628AbgJPS3t (ORCPT ); Fri, 16 Oct 2020 14:29:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35154 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391614AbgJPS3t (ORCPT ); Fri, 16 Oct 2020 14:29:49 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BEE59C061755; Fri, 16 Oct 2020 11:29:48 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id l15so2093180wmh.1; Fri, 16 Oct 2020 11:29:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=cc:subject:to:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=fjhHDgtGKDkmsE20A5S1tjDqj2OZ2lKXPJVT44zEZks=; b=DMcDY/POrwCWToO1l+vt2aYtvCqBZ+bDBgDpl6Vr/KSsB+v9sQFJbvp6bGKfKjQbfW vmjKxo4/brSd8YtEqA9Vdoo8+4nt9rd+Q5k3bZ2pCo3jU0U9xinrSM9maWAGtrYfFqbI Iv8cpLLrSykzhWnaCTTs/msRSKZkDMR5alHczeCnU/EVoKxMEOphFbEKa1fBjQyo8D8f C3ilrTmeMxdxUJjpqdX/U1BzF5dIm/zIV471o11IX5s7mlbH2tYsdxeEuGlnwrHGq3MM X9OqWF+qk2OmXBCLvYHD78JD0dIKPDh0hPLLSSkWNOrCxF8emqEuW1R0EegFKe27d+6H ujeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:cc:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=fjhHDgtGKDkmsE20A5S1tjDqj2OZ2lKXPJVT44zEZks=; b=j7exbiYg15v7JWNES6eFRkhq6CAlKq1hLIX7DkGbEYxYnWF2KHdtJMkGSekZrBU0qB IDLqMM1Y7SnNm842OK1ddDDU1tBpKn5OyWAqq8MSIlm+YvGOB0/DovDY/FDTds70wl4v 5NcZ5Hn/RqJ0pVcEa883PXnz7crPC+Y99Csl6Io8WCmNUczKrG5TQ3qI1YvD8LcAmrfP 7TPzakHr1rpliXgr0WcenBOWaxr4urjTQ8L9UTP9v+TuNyVwcaIe1DvN6mJFgBRW8oaR HgsNMzO075FLxTGZ13sJAqX6VznovvBnDYloq3+kMVUhgIAObcqlraD6vg97y52gpV7M 6BuA== X-Gm-Message-State: AOAM531XIhgeQvFQOPrFmGTb+2un8DBI3iYwEVBZBS6Mtsi7cClLYfNV xyaAfecvc688bYmRNqjU2bo= X-Google-Smtp-Source: ABdhPJxOF3C8sqMEN9L7YEsWf8K/+WqPtZUGkqlk40squt01sAQGCxe/bxB+CvZjdnWLrHb9aNCCmQ== X-Received: by 2002:a7b:c401:: with SMTP id k1mr4954728wmi.120.1602872987057; Fri, 16 Oct 2020 11:29:47 -0700 (PDT) Received: from [192.168.1.10] (static-176-175-73-29.ftth.abo.bbox.fr. [176.175.73.29]) by smtp.gmail.com with ESMTPSA id d20sm4769846wra.38.2020.10.16.11.29.45 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 16 Oct 2020 11:29:46 -0700 (PDT) Cc: mtk.manpages@gmail.com, Tycho Andersen , Sargun Dhillon , Kees Cook , Christian Brauner , linux-man , lkml , Aleksa Sarai , Alexei Starovoitov , Will Drewry , bpf , Song Liu , Daniel Borkmann , Andy Lutomirski , Linux Containers , Giuseppe Scrivano , Robert Sesek Subject: Re: For review: seccomp_user_notif(2) manual page To: Jann Horn References: <45f07f17-18b6-d187-0914-6f341fe90857@gmail.com> <5647b94a-4693-dad0-6e0d-ed178b495d65@gmail.com> From: "Michael Kerrisk (man-pages)" Message-ID: <0f41f776-9379-9ee6-df4b-e7538f69313e@gmail.com> Date: Fri, 16 Oct 2020 20:29:44 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.11.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org Hello Jann, Thanks for your reply! On 10/15/20 10:32 PM, Jann Horn wrote: > On Thu, Oct 15, 2020 at 1:24 PM Michael Kerrisk (man-pages) > wrote: >> On 9/30/20 5:53 PM, Jann Horn wrote: >>> On Wed, Sep 30, 2020 at 1:07 PM Michael Kerrisk (man-pages) >>> wrote: >>>> I knew it would be a big ask, but below is kind of the manual page >>>> I was hoping you might write [1] for the seccomp user-space notification >>>> mechanism. Since you didn't (and because 5.9 adds various new pieces >>>> such as SECCOMP_ADDFD_FLAG_SETFD and SECCOMP_IOCTL_NOTIF_ADDFD >>>> that also will need documenting [2]), I did :-). But of course I may >>>> have made mistakes... > [...] >>>> 3. The supervisor process will receive notification events on the >>>> listening file descriptor. These events are returned as >>>> structures of type seccomp_notif. Because this structure and >>>> its size may evolve over kernel versions, the supervisor must >>>> first determine the size of this structure using the sec‐ >>>> comp(2) SECCOMP_GET_NOTIF_SIZES operation, which returns a >>>> structure of type seccomp_notif_sizes. The supervisor allo‐ >>>> cates a buffer of size seccomp_notif_sizes.seccomp_notif bytes >>>> to receive notification events. In addition,the supervisor >>>> allocates another buffer of size seccomp_notif_sizes.sec‐ >>>> comp_notif_resp bytes for the response (a struct sec‐ >>>> comp_notif_resp structure) that it will provide to the kernel >>>> (and thus the target process). >>>> >>>> 4. The target process then performs its workload, which includes >>>> system calls that will be controlled by the seccomp filter. >>>> Whenever one of these system calls causes the filter to return >>>> the SECCOMP_RET_USER_NOTIF action value, the kernel does not >>>> execute the system call; instead, execution of the target >>>> process is temporarily blocked inside the kernel and a notifi‐ >>> >>> where "blocked" refers to the interruptible, restartable kind - if the >>> child receives a signal with an SA_RESTART signal handler in the >>> meantime, it'll leave the syscall, go through the signal handler, then >>> restart the syscall again and send the same request to the supervisor >>> again. so the supervisor may see duplicate syscalls. >> >> So, I partially demonstrated what you describe here, for two example >> system calls (epoll_wait() and pause()). But I could not exactly >> demonstrate things as I understand you to be describing them. (So, >> I'm not sure whether I have not understood you correctly, or >> if things are not exactly as you describe them.) >> >> Here's a scenario (A) that I tested: >> >> 1. Target installs seccomp filters for a blocking syscall >> (epoll_wait() or pause(), both of which should never restart, >> regardless of SA_RESTART) >> 2. Target installs SIGINT handler with SA_RESTART >> 3. Supervisor is sleeping (i.e., is not blocked in >> SECCOMP_IOCTL_NOTIF_RECV operation). >> 4. Target makes a blocking system call (epoll_wait() or pause()). >> 5. SIGINT gets delivered to target; handler gets called; >> ***and syscall gets restarted by the kernel*** >> >> That last should never happen, of course, and is a result of the >> combination of both the user-notify filter and the SA_RESTART flag. >> If one or other is not present, then the system call is not >> restarted. >> >> So, as you note below, the UAPI gets broken a little. >> >> However, from your description above I had understood that >> something like the following scenario (B) could occur: >> >> 1. Target installs seccomp filters for a blocking syscall >> (epoll_wait() or pause(), both of which should never restart, >> regardless of SA_RESTART) >> 2. Target installs SIGINT handler with SA_RESTART >> 3. Supervisor performs SECCOMP_IOCTL_NOTIF_RECV operation (which >> blocks). >> 4. Target makes a blocking system call (epoll_wait() or pause()). >> 5. Supervisor gets seccomp user-space notification (i.e., >> SECCOMP_IOCTL_NOTIF_RECV ioctl() returns >> 6. SIGINT gets delivered to target; handler gets called; >> and syscall gets restarted by the kernel >> 7. Supervisor performs another SECCOMP_IOCTL_NOTIF_RECV operation >> which gets another notification for the restarted system call. >> >> However, I don't observe such behavior. In step 6, the syscall >> does not get restarted by the kernel, but instead returns -1/EINTR. >> Perhaps I have misconstructed my experiment in the second case, or >> perhaps I've misunderstood what you meant, or is it possibly the >> case that things are not quite as you said? Thanks for the code, Jann (including the demo of the CLONE_FILES technique to pass the notification FD to the supervisor). But I think your code just demonstrates what I described in scenario A. So, it seems that I both understood what you meant (because my code demonstrates the same thing) and also misunderstood what you said (because I thought you were meaning something more like scenario B). I'm not sure if I should write anything about this small UAPI breakage in BUGS, or not. Your thoughts? > user@vm:~/test/seccomp-notify-interrupt$ cat seccomp-notify-interrupt.c > #define _GNU_SOURCE > #include > #include > #include > #include > #include > #include > #include > #include > #include > #include > #include > #include > #include > #include > #include > > struct { > int seccomp_fd; > } *shared; > > static void handle_signal(int sig, siginfo_t *info, void *uctx) { > printf("signal handler invoked\n"); > } > > int main(void) { > setbuf(stdout, NULL); > > shared = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, > MAP_ANONYMOUS|MAP_SHARED, -1, 0); > if (shared == MAP_FAILED) > err(1, "mmap"); > shared->seccomp_fd = -1; > > /* glibc's clone() wrapper doesn't support fork()-style usage */ > pid_t child = syscall(__NR_clone, CLONE_FILES|SIGCHLD, > NULL, NULL, NULL, 0); > if (child == -1) err(1, "clone"); > if (child == 0) { > /* don't outlive the parent */ > prctl(PR_SET_PDEATHSIG, SIGKILL); > if (getppid() == 1) exit(0); > > prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); > struct sock_filter insns[] = { > BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)), > BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_pause, 0, 1), > BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_USER_NOTIF), > BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW) > }; > struct sock_fprog prog = { > .len = sizeof(insns)/sizeof(insns[0]), > .filter = insns > }; > int seccomp_ret = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, > SECCOMP_FILTER_FLAG_NEW_LISTENER, &prog); > if (seccomp_ret < 0) > err(1, "install"); > printf("installed seccomp: fd %d\n", seccomp_ret); > > __atomic_store(&shared->seccomp_fd, &seccomp_ret, __ATOMIC_RELEASE); > int futex_ret = syscall(__NR_futex, &shared->seccomp_fd, FUTEX_WAKE, > INT_MAX, NULL, NULL, 0); > printf("woke %d waiters\n", futex_ret); > > struct sigaction act = { > .sa_sigaction = handle_signal, > .sa_flags = SA_RESTART|SA_SIGINFO > }; > if (sigaction(SIGUSR1, &act, NULL)) > err(1, "sigaction"); > > pause(); > perror("pause returned"); > exit(0); > } > > int futex_ret = syscall(__NR_futex, &shared->seccomp_fd, FUTEX_WAIT, > -1, NULL, NULL, 0); > if (futex_ret == -1 && errno != EAGAIN) > err(1, "futex wait"); > int fd = __atomic_load_n(&shared->seccomp_fd, __ATOMIC_ACQUIRE); > printf("child installed seccomp fd %d\n", fd); > > sleep(1); > printf("going to send SIGUSR1...\n"); > kill(child, SIGUSR1); > sleep(1); > > exit(0); > } > user@vm:~/test/seccomp-notify-interrupt$ gcc -o > seccomp-notify-interrupt seccomp-notify-interrupt.c -Wall > user@vm:~/test/seccomp-notify-interrupt$ strace -f > ./seccomp-notify-interrupt >/dev/null > execve("./seccomp-notify-interrupt", ["./seccomp-notify-interrupt"], > 0x7ffcb31a0d08 /* 42 vars */) = 0 > brk(NULL) = 0x5565864b2000 > access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) > openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 > fstat(3, {st_mode=S_IFREG|0644, st_size=89296, ...}) = 0 > mmap(NULL, 89296, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7e688e7000 > close(3) = 0 > openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 > read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260A\2\0\0\0\0\0"..., > 832) = 832 > fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0 > mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, > 0) = 0x7f7e688e5000 > mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7e68724000 > mprotect(0x7f7e68746000, 1658880, PROT_NONE) = 0 > mmap(0x7f7e68746000, 1343488, PROT_READ|PROT_EXEC, > MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f7e68746000 > mmap(0x7f7e6888e000, 311296, PROT_READ, > MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f7e6888e000 > mmap(0x7f7e688db000, 24576, PROT_READ|PROT_WRITE, > MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f7e688db000 > mmap(0x7f7e688e1000, 14336, PROT_READ|PROT_WRITE, > MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7e688e1000 > close(3) = 0 > arch_prctl(ARCH_SET_FS, 0x7f7e688e6500) = 0 > mprotect(0x7f7e688db000, 16384, PROT_READ) = 0 > mprotect(0x556585183000, 4096, PROT_READ) = 0 > mprotect(0x7f7e68924000, 4096, PROT_READ) = 0 > munmap(0x7f7e688e7000, 89296) = 0 > mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, > 0) = 0x7f7e688fc000 > clone(child_stack=NULL, flags=CLONE_FILES|SIGCHLD) = 2558 > futex(0x7f7e688fc000, FUTEX_WAIT, 4294967295, NULLstrace: Process 2558 attached > > [pid 2558] prctl(PR_SET_PDEATHSIG, SIGKILL) = 0 > [pid 2558] getppid() = 2557 > [pid 2558] prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) = 0 > [pid 2558] seccomp(SECCOMP_SET_MODE_FILTER, 0x8 /* > SECCOMP_FILTER_FLAG_??? */, {len=4, filter=0x7ffdf7cc9b50}) = 3 > [pid 2558] write(1, "installed seccomp: fd 3\n", 24) = 24 > [pid 2558] futex(0x7f7e688fc000, FUTEX_WAKE, 2147483647 > [pid 2557] <... futex resumed> ) = 0 > [pid 2558] <... futex resumed> ) = 1 > [pid 2558] write(1, "woke 1 waiters\n", 15) = 15 > [pid 2557] write(1, "child installed seccomp fd 3\n", 29) = 29 > [pid 2558] rt_sigaction(SIGUSR1, {sa_handler=0x556585181215, > sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, > sa_restorer=0x7f7e6875b840}, NULL, 8) = 0 > [pid 2557] nanosleep({tv_sec=1, tv_nsec=0}, > [pid 2558] pause( > [pid 2557] <... nanosleep resumed> 0x7ffdf7cc9b10) = 0 > [pid 2557] write(1, "going to send SIGUSR1...", 24) = 24 > [pid 2557] write(1, "\n", 1) = 1 > [pid 2557] kill(2558, SIGUSR1) = 0 > [pid 2557] nanosleep({tv_sec=1, tv_nsec=0}, > [pid 2558] <... pause resumed> ) = ? ERESTARTSYS (To be > restarted if SA_RESTART is set) > [pid 2558] --- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_USER, > si_pid=2557, si_uid=1000} --- > [pid 2558] write(1, "signal handler invoked", 22) = 22 > [pid 2558] write(1, "\n", 1) = 1 > [pid 2558] rt_sigreturn({mask=[]}) = 34 > [pid 2558] pause( > [pid 2557] <... nanosleep resumed> 0x7ffdf7cc9b10) = 0 > [pid 2557] exit_group(0) = ? > [pid 2557] +++ exited with 0 +++ > <... pause resumed>) = ? > +++ killed by SIGKILL +++ > user@vm:~/test/seccomp-notify-interrupt$ [...] >>>> In the above scenario, the risk is that the supervisor may >>>> try to access the memory of a process other than the tar‐ >>>> get. This race can be avoided by following the call to >>>> open with a SECCOMP_IOCTL_NOTIF_ID_VALID operation to ver‐ >>>> ify that the process that generated the notification is >>>> still alive. (Note that if the target process subse‐ >>>> quently terminates, its PID won't be reused because there >>> >>> That's wrong, the PID can be reused, but the /proc/$pid directory is >>> internally not associated with the numeric PID, but, conceptually >>> speaking, with a specific incarnation of the PID, or something like >>> that. (Actually, it is associated with the "struct pid", which is not >>> reused, instead of the numeric PID.) >> >> Thanks. I simplified the last sentence of the paragraph: >> >> In the above scenario, the risk is that the supervisor may >> try to access the memory of a process other than the tar‐ >> get. This race can be avoided by following the call to >> open(2) with a SECCOMP_IOCTL_NOTIF_ID_VALID operation to >> verify that the process that generated the notification is >> still alive. (Note that if the target terminates after the >> latter step, a subsequent read(2) from the file descriptor >> will return 0, indicating end of file.) >> >> I think that's probably enough detail. > > Maybe make that "may return 0" instead of "will return 0" - reading > from /proc/$pid/mem can only return 0 in the following cases AFAICS: > > 1. task->mm was already gone at open() time > 2. mm->mm_users has dropped to zero (the mm only has lazytlb users; > page tables and VMAs are being blown away or have been blown away) > 3. the syscall was called with length 0 > > When a process has gone away, normally mm->mm_users will drop to zero, > but someone else could theoretically still be holding a reference to > the mm (e.g. someone else in the middle of accessing /proc/$pid/mem). > (Such references should normally not be very long-lived though.) > > Additionally, in the unlikely case that the OOM killer just chomped > through the page tables of the target process, I think the read will > return -EIO (same error as if the address was simply unmapped) if the > address is within a non-shared mapping. (Maybe that's something procfs > could do better...) Thanks for all the detail! I changed the text to say "may" instead of "will". > [...] >>>> NOTES >>>> The file descriptor returned when seccomp(2) is employed with the >>>> SECCOMP_FILTER_FLAG_NEW_LISTENER flag can be monitored using >>>> poll(2), epoll(7), and select(2). When a notification is pend‐ >>>> ing, these interfaces indicate that the file descriptor is read‐ >>>> able. >>> >>> We should probably also point out somewhere that, as >>> include/uapi/linux/seccomp.h says: >>> >>> * Similar precautions should be applied when stacking SECCOMP_RET_USER_NOTIF >>> * or SECCOMP_RET_TRACE. For SECCOMP_RET_USER_NOTIF filters acting on the >>> * same syscall, the most recently added filter takes precedence. This means >>> * that the new SECCOMP_RET_USER_NOTIF filter can override any >>> * SECCOMP_IOCTL_NOTIF_SEND from earlier filters, essentially allowing all >> >> My takeaway from Chritian's comments is that this comment in the kernel >> source is partially wrong, since it is not possible to install multiple >> filters with SECCOMP_RET_USER_NOTIF, right? > > Yeah. (Well, AFAICS technically, you can add more filters that return > SECCOMP_RET_USER_NOTIF, but when a filter returns that without having > a notifier fd attached, seccomp blocks the syscall with -ENOSYS; it > won't use the notifier fd attached to a different filter in the > chain.) Ah yes. I misspoke. I meant to say that only one filter can be installed with SECCOMP_FILTER_FLAG_NEW_LISTENER (and that's what seccomp(2) currently says). Also, I just checked, and I have already added the detail about ENOSYS in seccomp(2). SECCOMP_RET_USER_NOTIF (since Linux 5.0) ... If there is no attached supervisor (either because the filter was not installed with the SECCOMP_FIL‐ TER_FLAG_NEW_LISTENER flag or because the file descriptor was closed), the filter returns ENOSYS (similar to what happens when a filter returns SECCOMP_RET_TRACE and there is no tracer). See seccomp_user_notif(2) for further details. [...] >>>> if (s == 0) { >>>> fprintf(stderr, "\tS: read() of /proc/PID/mem " >>>> "returned 0 (EOF)\n"); >>>> exit(EXIT_FAILURE); >>>> } >>>> >>>> if (close(procMemFd) == -1) >>>> errExit("close-/proc/PID/mem"); >>> >>> We should probably make sure here that the value we read is actually >>> NUL-terminated? >> >> So, I was curious about that point also. But, (why) are we not >> guaranteed that it will be NUL-terminated? > > Because it's random memory filled by another process, which we don't > necessarily trust. While seccomp notifiers aren't usable for applying > *extra* security restrictions, the supervisor will still often be more > privileged than the supervised process. D'oh! Yes, I see that I failed my Security Engineering 101 exam. How about: /* We have no guarantees about what was in the memory of the target process. Therefore, we ensure that 'path' is null-terminated. Such precautions are particularly important in cases where (as is common) the surpervisor is running at a higher privilege level than the target. */ // 'len' is size of buffer; 's' is return value from pread() int zeroIdx = len - 1; if (s < zeroIdx) zeroIdx = s; path[zeroIdx] = '\0'; Or just simply: path[len - 1] = '\0'; ? >>>> /* Discover the sizes of the structures that are used to receive >>>> notifications and send notification responses, and allocate >>>> buffers of those sizes. */ >>>> >>>> if (seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes) == -1) >>>> errExit("\tS: seccomp-SECCOMP_GET_NOTIF_SIZES"); >>>> >>>> struct seccomp_notif *req = malloc(sizes.seccomp_notif); >>>> if (req == NULL) >>>> errExit("\tS: malloc"); >>>> >>>> struct seccomp_notif_resp *resp = malloc(sizes.seccomp_notif_resp); >>> >>> This should probably do something like max(sizes.seccomp_notif_resp, >>> sizeof(struct seccomp_notif_resp)) in case the program was built >>> against new UAPI headers that make struct seccomp_notif_resp big, but >>> is running under an old kernel where that struct is still smaller? >> >> I'm confused. Why? I mean, if the running kernel says that it expects >> a buffer of a certain size, and we allocate a buffer of that size, >> what's the problem? > > Because in userspace, we cast the result of malloc() to a "struct > seccomp_notif_resp *". If the kernel tells us that it expects a size > smaller than sizeof(struct seccomp_notif_resp), then we end up with a > pointer to a struct that consists partly of allocated memory, partly > of out-of-bounds memory, which is generally a bad idea - I'm not sure > whether the C standard permits that. And if userspace then e.g. > decides to access some member of that struct that is beyond what the > kernel thinks is the struct size, we get actual OOB memory accesses. Thanks. Got it. (But gosh, this seems like a fragile API mess.) I added the following to the code: /* When allocating the response buffer, we must allow for the fact that the user-space binary may have been built with user-space headers where 'struct seccomp_notif_resp' is bigger than the response buffer expected by the (older) kernel. Therefore, we allocate a buffer that is the maximum of the two sizes. This ensures that if the supervisor places bytes into the response structure that are past the response size that the kernel expects, then the supervisor is not touching an invalid memory location. */ size_t resp_size = sizes.seccomp_notif_resp; if (sizeof(struct seccomp_notif_resp) > resp_size) resp_size = sizeof(struct seccomp_notif_resp); struct seccomp_notif_resp *resp = malloc(resp_size); Okay? Thanks, Michael -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=3.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE, SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B13B6C433DF for ; Fri, 16 Oct 2020 18:29:56 +0000 (UTC) Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D637A2084C for ; Fri, 16 Oct 2020 18:29:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DMcDY/PO" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D637A2084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=containers-bounces@lists.linux-foundation.org Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 583FA88797; Fri, 16 Oct 2020 18:29:55 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id O6jaR5idohZG; Fri, 16 Oct 2020 18:29:52 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id CC4E2886D4; Fri, 16 Oct 2020 18:29:52 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A7F77C07FF; Fri, 16 Oct 2020 18:29:52 +0000 (UTC) Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1F76EC0051 for ; Fri, 16 Oct 2020 18:29:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 0D954885A6 for ; Fri, 16 Oct 2020 18:29:51 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id K_LOKrbBaPnI for ; Fri, 16 Oct 2020 18:29:49 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) by fraxinus.osuosl.org (Postfix) with ESMTPS id F1C37886D4 for ; Fri, 16 Oct 2020 18:29:48 +0000 (UTC) Received: by mail-wm1-f66.google.com with SMTP id z22so2094539wmi.0 for ; Fri, 16 Oct 2020 11:29:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=cc:subject:to:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=fjhHDgtGKDkmsE20A5S1tjDqj2OZ2lKXPJVT44zEZks=; b=DMcDY/POrwCWToO1l+vt2aYtvCqBZ+bDBgDpl6Vr/KSsB+v9sQFJbvp6bGKfKjQbfW vmjKxo4/brSd8YtEqA9Vdoo8+4nt9rd+Q5k3bZ2pCo3jU0U9xinrSM9maWAGtrYfFqbI Iv8cpLLrSykzhWnaCTTs/msRSKZkDMR5alHczeCnU/EVoKxMEOphFbEKa1fBjQyo8D8f C3ilrTmeMxdxUJjpqdX/U1BzF5dIm/zIV471o11IX5s7mlbH2tYsdxeEuGlnwrHGq3MM X9OqWF+qk2OmXBCLvYHD78JD0dIKPDh0hPLLSSkWNOrCxF8emqEuW1R0EegFKe27d+6H ujeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:cc:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=fjhHDgtGKDkmsE20A5S1tjDqj2OZ2lKXPJVT44zEZks=; b=fhZLk+pv76VmA1HpGAHjWlcqSFuGMQz9D5Kd+0VjBUMgurCrejNbEnAxfhUZVZaHX0 CIOCDkGzv4c0VYQGW9miWcaBKEiDOTw7DFKBVSrSu7zllpvBzpvmutHRom4V+CKdXIVR lXpWtqVRb/d+HWLW6YPdJ7G3uCSSB3dcNzZu/JyQMiQ6HvgSu1XB65/45W13WFvK9O3+ Tv125n+Uk1x71NUYx9zA4OudbdGFIa17K34CceyPtp1GRHea6iBLohc1K2cPrt+3oQ4w nmHZZz5piypQceRL8OyIsiXqa1YpaD1Z71MKnw1VwVQzZ6nZZD/CrcdQ88ThY9RP4jz1 RXXQ== X-Gm-Message-State: AOAM533MTSsdgx+3Jr/96GYanaWL39aML2S4AfCoc0dZFMMb/6C4cvUd mDr2Ht92n52IOI23XhIRdGw= X-Google-Smtp-Source: ABdhPJxOF3C8sqMEN9L7YEsWf8K/+WqPtZUGkqlk40squt01sAQGCxe/bxB+CvZjdnWLrHb9aNCCmQ== X-Received: by 2002:a7b:c401:: with SMTP id k1mr4954728wmi.120.1602872987057; Fri, 16 Oct 2020 11:29:47 -0700 (PDT) Received: from [192.168.1.10] (static-176-175-73-29.ftth.abo.bbox.fr. [176.175.73.29]) by smtp.gmail.com with ESMTPSA id d20sm4769846wra.38.2020.10.16.11.29.45 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 16 Oct 2020 11:29:46 -0700 (PDT) Subject: Re: For review: seccomp_user_notif(2) manual page To: Jann Horn References: <45f07f17-18b6-d187-0914-6f341fe90857@gmail.com> <5647b94a-4693-dad0-6e0d-ed178b495d65@gmail.com> From: "Michael Kerrisk (man-pages)" Message-ID: <0f41f776-9379-9ee6-df4b-e7538f69313e@gmail.com> Date: Fri, 16 Oct 2020 20:29:44 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.11.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-US Cc: linux-man , Song Liu , Will Drewry , Kees Cook , Daniel Borkmann , Giuseppe Scrivano , Robert Sesek , Linux Containers , lkml , Alexei Starovoitov , mtk.manpages@gmail.com, bpf , Andy Lutomirski , Christian Brauner X-BeenThere: containers@lists.linux-foundation.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux Containers List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: containers-bounces@lists.linux-foundation.org Sender: "Containers" SGVsbG8gSmFubiwKClRoYW5rcyBmb3IgeW91ciByZXBseSEKCk9uIDEwLzE1LzIwIDEwOjMyIFBN LCBKYW5uIEhvcm4gd3JvdGU6Cj4gT24gVGh1LCBPY3QgMTUsIDIwMjAgYXQgMToyNCBQTSBNaWNo YWVsIEtlcnJpc2sgKG1hbi1wYWdlcykKPiA8bXRrLm1hbnBhZ2VzQGdtYWlsLmNvbT4gd3JvdGU6 Cj4+IE9uIDkvMzAvMjAgNTo1MyBQTSwgSmFubiBIb3JuIHdyb3RlOgo+Pj4gT24gV2VkLCBTZXAg MzAsIDIwMjAgYXQgMTowNyBQTSBNaWNoYWVsIEtlcnJpc2sgKG1hbi1wYWdlcykKPj4+IDxtdGsu bWFucGFnZXNAZ21haWwuY29tPiB3cm90ZToKPj4+PiBJIGtuZXcgaXQgd291bGQgYmUgYSBiaWcg YXNrLCBidXQgYmVsb3cgaXMga2luZCBvZiB0aGUgbWFudWFsIHBhZ2UKPj4+PiBJIHdhcyBob3Bp bmcgeW91IG1pZ2h0IHdyaXRlIFsxXSBmb3IgdGhlIHNlY2NvbXAgdXNlci1zcGFjZSBub3RpZmlj YXRpb24KPj4+PiBtZWNoYW5pc20uIFNpbmNlIHlvdSBkaWRuJ3QgKGFuZCBiZWNhdXNlIDUuOSBh ZGRzIHZhcmlvdXMgbmV3IHBpZWNlcwo+Pj4+IHN1Y2ggYXMgU0VDQ09NUF9BRERGRF9GTEFHX1NF VEZEIGFuZCBTRUNDT01QX0lPQ1RMX05PVElGX0FEREZECj4+Pj4gdGhhdCBhbHNvIHdpbGwgbmVl ZCBkb2N1bWVudGluZyBbMl0pLCBJIGRpZCA6LSkuIEJ1dCBvZiBjb3Vyc2UgSSBtYXkKPj4+PiBo YXZlIG1hZGUgbWlzdGFrZXMuLi4KPiBbLi4uXQo+Pj4+ICAgICAgICAzLiBUaGUgc3VwZXJ2aXNv ciBwcm9jZXNzIHdpbGwgcmVjZWl2ZSBub3RpZmljYXRpb24gZXZlbnRzIG9uIHRoZQo+Pj4+ICAg ICAgICAgICBsaXN0ZW5pbmcgIGZpbGUgIGRlc2NyaXB0b3IuICAgVGhlc2UgIGV2ZW50cyAgYXJl ICByZXR1cm5lZCBhcwo+Pj4+ICAgICAgICAgICBzdHJ1Y3R1cmVzIG9mIHR5cGUgc2VjY29tcF9u b3RpZi4gIEJlY2F1c2UgdGhpcyBzdHJ1Y3R1cmUgIGFuZAo+Pj4+ICAgICAgICAgICBpdHMgIHNp emUgbWF5IGV2b2x2ZSBvdmVyIGtlcm5lbCB2ZXJzaW9ucywgdGhlIHN1cGVydmlzb3IgbXVzdAo+ Pj4+ICAgICAgICAgICBmaXJzdCBkZXRlcm1pbmUgdGhlIHNpemUgb2YgIHRoaXMgIHN0cnVjdHVy ZSAgdXNpbmcgIHRoZSAgc2Vj4oCQCj4+Pj4gICAgICAgICAgIGNvbXAoMikgIFNFQ0NPTVBfR0VU X05PVElGX1NJWkVTICBvcGVyYXRpb24sICB3aGljaCAgcmV0dXJucyBhCj4+Pj4gICAgICAgICAg IHN0cnVjdHVyZSBvZiB0eXBlIHNlY2NvbXBfbm90aWZfc2l6ZXMuICBUaGUgIHN1cGVydmlzb3Ig IGFsbG/igJAKPj4+PiAgICAgICAgICAgY2F0ZXMgYSBidWZmZXIgb2Ygc2l6ZSBzZWNjb21wX25v dGlmX3NpemVzLnNlY2NvbXBfbm90aWYgYnl0ZXMKPj4+PiAgICAgICAgICAgdG8gcmVjZWl2ZSBu b3RpZmljYXRpb24gZXZlbnRzLiAgIEluICBhZGRpdGlvbix0aGUgIHN1cGVydmlzb3IKPj4+PiAg ICAgICAgICAgYWxsb2NhdGVzICBhbm90aGVyICBidWZmZXIgIG9mICBzaXplICBzZWNjb21wX25v dGlmX3NpemVzLnNlY+KAkAo+Pj4+ICAgICAgICAgICBjb21wX25vdGlmX3Jlc3AgIGJ5dGVzICBm b3IgIHRoZSAgcmVzcG9uc2UgIChhICAgc3RydWN0ICAgc2Vj4oCQCj4+Pj4gICAgICAgICAgIGNv bXBfbm90aWZfcmVzcCAgc3RydWN0dXJlKSB0aGF0IGl0IHdpbGwgcHJvdmlkZSB0byB0aGUga2Vy bmVsCj4+Pj4gICAgICAgICAgIChhbmQgdGh1cyB0aGUgdGFyZ2V0IHByb2Nlc3MpLgo+Pj4+Cj4+ Pj4gICAgICAgIDQuIFRoZSB0YXJnZXQgcHJvY2VzcyB0aGVuIHBlcmZvcm1zIGl0cyB3b3JrbG9h ZCwgd2hpY2ggIGluY2x1ZGVzCj4+Pj4gICAgICAgICAgIHN5c3RlbSAgY2FsbHMgIHRoYXQgIHdp bGwgYmUgY29udHJvbGxlZCBieSB0aGUgc2VjY29tcCBmaWx0ZXIuCj4+Pj4gICAgICAgICAgIFdo ZW5ldmVyIG9uZSBvZiB0aGVzZSBzeXN0ZW0gY2FsbHMgY2F1c2VzIHRoZSBmaWx0ZXIgdG8gcmV0 dXJuCj4+Pj4gICAgICAgICAgIHRoZSAgU0VDQ09NUF9SRVRfVVNFUl9OT1RJRiAgYWN0aW9uIHZh bHVlLCB0aGUga2VybmVsIGRvZXMgbm90Cj4+Pj4gICAgICAgICAgIGV4ZWN1dGUgdGhlIHN5c3Rl bSBjYWxsOyAgaW5zdGVhZCwgIGV4ZWN1dGlvbiAgb2YgIHRoZSAgdGFyZ2V0Cj4+Pj4gICAgICAg ICAgIHByb2Nlc3MgaXMgdGVtcG9yYXJpbHkgYmxvY2tlZCBpbnNpZGUgdGhlIGtlcm5lbCBhbmQg YSBub3RpZmnigJAKPj4+Cj4+PiB3aGVyZSAiYmxvY2tlZCIgcmVmZXJzIHRvIHRoZSBpbnRlcnJ1 cHRpYmxlLCByZXN0YXJ0YWJsZSBraW5kIC0gaWYgdGhlCj4+PiBjaGlsZCByZWNlaXZlcyBhIHNp Z25hbCB3aXRoIGFuIFNBX1JFU1RBUlQgc2lnbmFsIGhhbmRsZXIgaW4gdGhlCj4+PiBtZWFudGlt ZSwgaXQnbGwgbGVhdmUgdGhlIHN5c2NhbGwsIGdvIHRocm91Z2ggdGhlIHNpZ25hbCBoYW5kbGVy LCB0aGVuCj4+PiByZXN0YXJ0IHRoZSBzeXNjYWxsIGFnYWluIGFuZCBzZW5kIHRoZSBzYW1lIHJl cXVlc3QgdG8gdGhlIHN1cGVydmlzb3IKPj4+IGFnYWluLiBzbyB0aGUgc3VwZXJ2aXNvciBtYXkg c2VlIGR1cGxpY2F0ZSBzeXNjYWxscy4KPj4KPj4gU28sIEkgcGFydGlhbGx5IGRlbW9uc3RyYXRl ZCB3aGF0IHlvdSBkZXNjcmliZSBoZXJlLCBmb3IgdHdvIGV4YW1wbGUKPj4gc3lzdGVtIGNhbGxz IChlcG9sbF93YWl0KCkgYW5kIHBhdXNlKCkpLiBCdXQgSSBjb3VsZCBub3QgZXhhY3RseQo+PiBk ZW1vbnN0cmF0ZSB0aGluZ3MgYXMgSSB1bmRlcnN0YW5kIHlvdSB0byBiZSBkZXNjcmliaW5nIHRo ZW0uIChTbywKPj4gSSdtIG5vdCBzdXJlIHdoZXRoZXIgSSBoYXZlIG5vdCB1bmRlcnN0b29kIHlv dSBjb3JyZWN0bHksIG9yCj4+IGlmIHRoaW5ncyBhcmUgbm90IGV4YWN0bHkgYXMgeW91IGRlc2Ny aWJlIHRoZW0uKQo+Pgo+PiBIZXJlJ3MgYSBzY2VuYXJpbyAoQSkgdGhhdCBJIHRlc3RlZDoKPj4K Pj4gMS4gVGFyZ2V0IGluc3RhbGxzIHNlY2NvbXAgZmlsdGVycyBmb3IgYSBibG9ja2luZyBzeXNj YWxsCj4+ICAgIChlcG9sbF93YWl0KCkgb3IgcGF1c2UoKSwgYm90aCBvZiB3aGljaCBzaG91bGQg bmV2ZXIgcmVzdGFydCwKPj4gICAgcmVnYXJkbGVzcyBvZiBTQV9SRVNUQVJUKQo+PiAyLiBUYXJn ZXQgaW5zdGFsbHMgU0lHSU5UIGhhbmRsZXIgd2l0aCBTQV9SRVNUQVJUCj4+IDMuIFN1cGVydmlz b3IgaXMgc2xlZXBpbmcgKGkuZS4sIGlzIG5vdCBibG9ja2VkIGluCj4+ICAgIFNFQ0NPTVBfSU9D VExfTk9USUZfUkVDViBvcGVyYXRpb24pLgo+PiA0LiBUYXJnZXQgbWFrZXMgYSBibG9ja2luZyBz eXN0ZW0gY2FsbCAoZXBvbGxfd2FpdCgpIG9yIHBhdXNlKCkpLgo+PiA1LiBTSUdJTlQgZ2V0cyBk ZWxpdmVyZWQgdG8gdGFyZ2V0OyBoYW5kbGVyIGdldHMgY2FsbGVkOwo+PiAgICAqKiphbmQgc3lz Y2FsbCBnZXRzIHJlc3RhcnRlZCBieSB0aGUga2VybmVsKioqCj4+Cj4+IFRoYXQgbGFzdCBzaG91 bGQgbmV2ZXIgaGFwcGVuLCBvZiBjb3Vyc2UsIGFuZCBpcyBhIHJlc3VsdCBvZiB0aGUKPj4gY29t YmluYXRpb24gb2YgYm90aCB0aGUgdXNlci1ub3RpZnkgZmlsdGVyIGFuZCB0aGUgU0FfUkVTVEFS VCBmbGFnLgo+PiBJZiBvbmUgb3Igb3RoZXIgaXMgbm90IHByZXNlbnQsIHRoZW4gdGhlIHN5c3Rl bSBjYWxsIGlzIG5vdAo+PiByZXN0YXJ0ZWQuCj4+Cj4+IFNvLCBhcyB5b3Ugbm90ZSBiZWxvdywg dGhlIFVBUEkgZ2V0cyBicm9rZW4gYSBsaXR0bGUuCj4+Cj4+IEhvd2V2ZXIsIGZyb20geW91ciBk ZXNjcmlwdGlvbiBhYm92ZSBJIGhhZCB1bmRlcnN0b29kIHRoYXQKPj4gc29tZXRoaW5nIGxpa2Ug dGhlIGZvbGxvd2luZyBzY2VuYXJpbyAoQikgY291bGQgb2NjdXI6Cj4+Cj4+IDEuIFRhcmdldCBp bnN0YWxscyBzZWNjb21wIGZpbHRlcnMgZm9yIGEgYmxvY2tpbmcgc3lzY2FsbAo+PiAgICAoZXBv bGxfd2FpdCgpIG9yIHBhdXNlKCksIGJvdGggb2Ygd2hpY2ggc2hvdWxkIG5ldmVyIHJlc3RhcnQs Cj4+ICAgIHJlZ2FyZGxlc3Mgb2YgU0FfUkVTVEFSVCkKPj4gMi4gVGFyZ2V0IGluc3RhbGxzIFNJ R0lOVCBoYW5kbGVyIHdpdGggU0FfUkVTVEFSVAo+PiAzLiBTdXBlcnZpc29yIHBlcmZvcm1zIFNF Q0NPTVBfSU9DVExfTk9USUZfUkVDViBvcGVyYXRpb24gKHdoaWNoCj4+ICAgIGJsb2NrcykuCj4+ IDQuIFRhcmdldCBtYWtlcyBhIGJsb2NraW5nIHN5c3RlbSBjYWxsIChlcG9sbF93YWl0KCkgb3Ig cGF1c2UoKSkuCj4+IDUuIFN1cGVydmlzb3IgZ2V0cyBzZWNjb21wIHVzZXItc3BhY2Ugbm90aWZp Y2F0aW9uIChpLmUuLAo+PiAgICBTRUNDT01QX0lPQ1RMX05PVElGX1JFQ1YgaW9jdGwoKSByZXR1 cm5zCj4+IDYuIFNJR0lOVCBnZXRzIGRlbGl2ZXJlZCB0byB0YXJnZXQ7IGhhbmRsZXIgZ2V0cyBj YWxsZWQ7Cj4+ICAgIGFuZCBzeXNjYWxsIGdldHMgcmVzdGFydGVkIGJ5IHRoZSBrZXJuZWwKPj4g Ny4gU3VwZXJ2aXNvciBwZXJmb3JtcyBhbm90aGVyIFNFQ0NPTVBfSU9DVExfTk9USUZfUkVDViBv cGVyYXRpb24KPj4gICAgd2hpY2ggZ2V0cyBhbm90aGVyIG5vdGlmaWNhdGlvbiBmb3IgdGhlIHJl c3RhcnRlZCBzeXN0ZW0gY2FsbC4KPj4KPj4gSG93ZXZlciwgSSBkb24ndCBvYnNlcnZlIHN1Y2gg YmVoYXZpb3IuIEluIHN0ZXAgNiwgdGhlIHN5c2NhbGwKPj4gZG9lcyBub3QgZ2V0IHJlc3RhcnRl ZCBieSB0aGUga2VybmVsLCBidXQgaW5zdGVhZCByZXR1cm5zIC0xL0VJTlRSLgo+PiBQZXJoYXBz IEkgaGF2ZSBtaXNjb25zdHJ1Y3RlZCBteSBleHBlcmltZW50IGluIHRoZSBzZWNvbmQgY2FzZSwg b3IKPj4gcGVyaGFwcyBJJ3ZlIG1pc3VuZGVyc3Rvb2Qgd2hhdCB5b3UgbWVhbnQsIG9yIGlzIGl0 IHBvc3NpYmx5IHRoZQo+PiBjYXNlIHRoYXQgdGhpbmdzIGFyZSBub3QgcXVpdGUgYXMgeW91IHNh aWQ/CgpUaGFua3MgZm9yIHRoZSBjb2RlLCBKYW5uIChpbmNsdWRpbmcgdGhlIGRlbW8gb2YgdGhl IENMT05FX0ZJTEVTCnRlY2huaXF1ZSB0byBwYXNzIHRoZSBub3RpZmljYXRpb24gRkQgdG8gdGhl IHN1cGVydmlzb3IpLgoKQnV0IEkgdGhpbmsgeW91ciBjb2RlIGp1c3QgZGVtb25zdHJhdGVzIHdo YXQgSSBkZXNjcmliZWQgaW4Kc2NlbmFyaW8gQS4gU28sIGl0IHNlZW1zIHRoYXQgSSBib3RoIHVu ZGVyc3Rvb2Qgd2hhdCB5b3UKbWVhbnQgKGJlY2F1c2UgbXkgY29kZSBkZW1vbnN0cmF0ZXMgdGhl IHNhbWUgdGhpbmcpIGFuZAphbHNvIG1pc3VuZGVyc3Rvb2Qgd2hhdCB5b3Ugc2FpZCAoYmVjYXVz ZSBJIHRob3VnaHQgeW91CndlcmUgbWVhbmluZyBzb21ldGhpbmcgbW9yZSBsaWtlIHNjZW5hcmlv IEIpLgoKSSdtIG5vdCBzdXJlIGlmIEkgc2hvdWxkIHdyaXRlIGFueXRoaW5nIGFib3V0IHRoaXMg c21hbGwgVUFQSQpicmVha2FnZSBpbiBCVUdTLCBvciBub3QuIFlvdXIgdGhvdWdodHM/Cgo+IHVz ZXJAdm06fi90ZXN0L3NlY2NvbXAtbm90aWZ5LWludGVycnVwdCQgY2F0IHNlY2NvbXAtbm90aWZ5 LWludGVycnVwdC5jCj4gI2RlZmluZSBfR05VX1NPVVJDRQo+ICNpbmNsdWRlIDxzdGRpby5oPgo+ ICNpbmNsdWRlIDxzaWduYWwuaD4KPiAjaW5jbHVkZSA8ZXJyLmg+Cj4gI2luY2x1ZGUgPGVycm5v Lmg+Cj4gI2luY2x1ZGUgPHVuaXN0ZC5oPgo+ICNpbmNsdWRlIDxzdGRsaWIuaD4KPiAjaW5jbHVk ZSA8c2NoZWQuaD4KPiAjaW5jbHVkZSA8c3RkZGVmLmg+Cj4gI2luY2x1ZGUgPGxpbWl0cy5oPgo+ ICNpbmNsdWRlIDxzeXMvbW1hbi5oPgo+ICNpbmNsdWRlIDxzeXMvc3lzY2FsbC5oPgo+ICNpbmNs dWRlIDxzeXMvcHJjdGwuaD4KPiAjaW5jbHVkZSA8bGludXgvc2VjY29tcC5oPgo+ICNpbmNsdWRl IDxsaW51eC9maWx0ZXIuaD4KPiAjaW5jbHVkZSA8bGludXgvZnV0ZXguaD4KPiAKPiBzdHJ1Y3Qg ewo+ICAgaW50IHNlY2NvbXBfZmQ7Cj4gfSAqc2hhcmVkOwo+IAo+IHN0YXRpYyB2b2lkIGhhbmRs ZV9zaWduYWwoaW50IHNpZywgc2lnaW5mb190ICppbmZvLCB2b2lkICp1Y3R4KSB7Cj4gICBwcmlu dGYoInNpZ25hbCBoYW5kbGVyIGludm9rZWRcbiIpOwo+IH0KPiAKPiBpbnQgbWFpbih2b2lkKSB7 Cj4gICBzZXRidWYoc3Rkb3V0LCBOVUxMKTsKPiAKPiAgIHNoYXJlZCA9IG1tYXAoTlVMTCwgMHgx MDAwLCBQUk9UX1JFQUR8UFJPVF9XUklURSwKPiAgICAgICAgICAgICAgICAgTUFQX0FOT05ZTU9V U3xNQVBfU0hBUkVELCAtMSwgMCk7Cj4gICBpZiAoc2hhcmVkID09IE1BUF9GQUlMRUQpCj4gICAg IGVycigxLCAibW1hcCIpOwo+ICAgc2hhcmVkLT5zZWNjb21wX2ZkID0gLTE7Cj4gCj4gICAvKiBn bGliYydzIGNsb25lKCkgd3JhcHBlciBkb2Vzbid0IHN1cHBvcnQgZm9yaygpLXN0eWxlIHVzYWdl ICovCj4gICBwaWRfdCBjaGlsZCA9IHN5c2NhbGwoX19OUl9jbG9uZSwgQ0xPTkVfRklMRVN8U0lH Q0hMRCwKPiAgICAgICAgICAgICAgICAgICAgICAgICBOVUxMLCBOVUxMLCBOVUxMLCAwKTsKPiAg IGlmIChjaGlsZCA9PSAtMSkgZXJyKDEsICJjbG9uZSIpOwo+ICAgaWYgKGNoaWxkID09IDApIHsK PiAgICAgLyogZG9uJ3Qgb3V0bGl2ZSB0aGUgcGFyZW50ICovCj4gICAgIHByY3RsKFBSX1NFVF9Q REVBVEhTSUcsIFNJR0tJTEwpOwo+ICAgICBpZiAoZ2V0cHBpZCgpID09IDEpIGV4aXQoMCk7Cj4g Cj4gICAgIHByY3RsKFBSX1NFVF9OT19ORVdfUFJJVlMsIDEsIDAsIDAsIDApOwo+ICAgICBzdHJ1 Y3Qgc29ja19maWx0ZXIgaW5zbnNbXSA9IHsKPiAgICAgICBCUEZfU1RNVChCUEZfTER8QlBGX1d8 QlBGX0FCUywgb2Zmc2V0b2Yoc3RydWN0IHNlY2NvbXBfZGF0YSwgbnIpKSwKPiAgICAgICBCUEZf SlVNUChCUEZfSk1QfEJQRl9KRVF8QlBGX0ssIF9fTlJfcGF1c2UsIDAsIDEpLAo+ICAgICAgIEJQ Rl9TVE1UKEJQRl9SRVR8QlBGX0ssIFNFQ0NPTVBfUkVUX1VTRVJfTk9USUYpLAo+ICAgICAgIEJQ Rl9TVE1UKEJQRl9SRVR8QlBGX0ssIFNFQ0NPTVBfUkVUX0FMTE9XKQo+ICAgICB9Owo+ICAgICBz dHJ1Y3Qgc29ja19mcHJvZyBwcm9nID0gewo+ICAgICAgIC5sZW4gPSBzaXplb2YoaW5zbnMpL3Np emVvZihpbnNuc1swXSksCj4gICAgICAgLmZpbHRlciA9IGluc25zCj4gICAgIH07Cj4gICAgIGlu dCBzZWNjb21wX3JldCA9IHN5c2NhbGwoX19OUl9zZWNjb21wLCBTRUNDT01QX1NFVF9NT0RFX0ZJ TFRFUiwKPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTRUNDT01QX0ZJTFRFUl9GTEFH X05FV19MSVNURU5FUiwgJnByb2cpOwo+ICAgICBpZiAoc2VjY29tcF9yZXQgPCAwKQo+ICAgICAg IGVycigxLCAiaW5zdGFsbCIpOwo+ICAgICBwcmludGYoImluc3RhbGxlZCBzZWNjb21wOiBmZCAl ZFxuIiwgc2VjY29tcF9yZXQpOwo+IAo+ICAgICBfX2F0b21pY19zdG9yZSgmc2hhcmVkLT5zZWNj b21wX2ZkLCAmc2VjY29tcF9yZXQsIF9fQVRPTUlDX1JFTEVBU0UpOwo+ICAgICBpbnQgZnV0ZXhf cmV0ID0gc3lzY2FsbChfX05SX2Z1dGV4LCAmc2hhcmVkLT5zZWNjb21wX2ZkLCBGVVRFWF9XQUtF LAo+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJTlRfTUFYLCBOVUxMLCBOVUxMLCAwKTsK PiAgICAgcHJpbnRmKCJ3b2tlICVkIHdhaXRlcnNcbiIsIGZ1dGV4X3JldCk7Cj4gCj4gICAgIHN0 cnVjdCBzaWdhY3Rpb24gYWN0ID0gewo+ICAgICAgIC5zYV9zaWdhY3Rpb24gPSBoYW5kbGVfc2ln bmFsLAo+ICAgICAgIC5zYV9mbGFncyA9IFNBX1JFU1RBUlR8U0FfU0lHSU5GTwo+ICAgICB9Owo+ ICAgICBpZiAoc2lnYWN0aW9uKFNJR1VTUjEsICZhY3QsIE5VTEwpKQo+ICAgICAgIGVycigxLCAi c2lnYWN0aW9uIik7Cj4gCj4gICAgIHBhdXNlKCk7Cj4gICAgIHBlcnJvcigicGF1c2UgcmV0dXJu ZWQiKTsKPiAgICAgZXhpdCgwKTsKPiAgIH0KPiAKPiAgIGludCBmdXRleF9yZXQgPSBzeXNjYWxs KF9fTlJfZnV0ZXgsICZzaGFyZWQtPnNlY2NvbXBfZmQsIEZVVEVYX1dBSVQsCj4gICAgICAgICAg ICAgICAgICAgICAgICAgICAtMSwgTlVMTCwgTlVMTCwgMCk7Cj4gICBpZiAoZnV0ZXhfcmV0ID09 IC0xICYmIGVycm5vICE9IEVBR0FJTikKPiAgICAgZXJyKDEsICJmdXRleCB3YWl0Iik7Cj4gICBp bnQgZmQgPSBfX2F0b21pY19sb2FkX24oJnNoYXJlZC0+c2VjY29tcF9mZCwgX19BVE9NSUNfQUNR VUlSRSk7Cj4gICBwcmludGYoImNoaWxkIGluc3RhbGxlZCBzZWNjb21wIGZkICVkXG4iLCBmZCk7 Cj4gCj4gICBzbGVlcCgxKTsKPiAgIHByaW50ZigiZ29pbmcgdG8gc2VuZCBTSUdVU1IxLi4uXG4i KTsKPiAgIGtpbGwoY2hpbGQsIFNJR1VTUjEpOwo+ICAgc2xlZXAoMSk7Cj4gCj4gICBleGl0KDAp Owo+IH0KPiB1c2VyQHZtOn4vdGVzdC9zZWNjb21wLW5vdGlmeS1pbnRlcnJ1cHQkIGdjYyAtbwo+ IHNlY2NvbXAtbm90aWZ5LWludGVycnVwdCBzZWNjb21wLW5vdGlmeS1pbnRlcnJ1cHQuYyAtV2Fs bAo+IHVzZXJAdm06fi90ZXN0L3NlY2NvbXAtbm90aWZ5LWludGVycnVwdCQgc3RyYWNlIC1mCj4g Li9zZWNjb21wLW5vdGlmeS1pbnRlcnJ1cHQgPi9kZXYvbnVsbAo+IGV4ZWN2ZSgiLi9zZWNjb21w LW5vdGlmeS1pbnRlcnJ1cHQiLCBbIi4vc2VjY29tcC1ub3RpZnktaW50ZXJydXB0Il0sCj4gMHg3 ZmZjYjMxYTBkMDggLyogNDIgdmFycyAqLykgPSAwCj4gYnJrKE5VTEwpICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgID0gMHg1NTY1ODY0YjIwMDAKPiBhY2Nlc3MoIi9ldGMvbGQuc28ucHJl bG9hZCIsIFJfT0spICAgICAgPSAtMSBFTk9FTlQgKE5vIHN1Y2ggZmlsZSBvciBkaXJlY3Rvcnkp Cj4gb3BlbmF0KEFUX0ZEQ1dELCAiL2V0Yy9sZC5zby5jYWNoZSIsIE9fUkRPTkxZfE9fQ0xPRVhF QykgPSAzCj4gZnN0YXQoMywge3N0X21vZGU9U19JRlJFR3wwNjQ0LCBzdF9zaXplPTg5Mjk2LCAu Li59KSA9IDAKPiBtbWFwKE5VTEwsIDg5Mjk2LCBQUk9UX1JFQUQsIE1BUF9QUklWQVRFLCAzLCAw KSA9IDB4N2Y3ZTY4OGU3MDAwCj4gY2xvc2UoMykgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgID0gMAo+IG9wZW5hdChBVF9GRENXRCwgIi9saWIveDg2XzY0LWxpbnV4LWdudS9saWJjLnNv LjYiLCBPX1JET05MWXxPX0NMT0VYRUMpID0gMwo+IHJlYWQoMywgIlwxNzdFTEZcMlwxXDFcM1ww XDBcMFwwXDBcMFwwXDBcM1wwPlwwXDFcMFwwXDBcMjYwQVwyXDBcMFwwXDBcMCIuLi4sCj4gODMy KSA9IDgzMgo+IGZzdGF0KDMsIHtzdF9tb2RlPVNfSUZSRUd8MDc1NSwgc3Rfc2l6ZT0xODI0NDk2 LCAuLi59KSA9IDAKPiBtbWFwKE5VTEwsIDgxOTIsIFBST1RfUkVBRHxQUk9UX1dSSVRFLCBNQVBf UFJJVkFURXxNQVBfQU5PTllNT1VTLCAtMSwKPiAwKSA9IDB4N2Y3ZTY4OGU1MDAwCj4gbW1hcChO VUxMLCAxODM3MDU2LCBQUk9UX1JFQUQsIE1BUF9QUklWQVRFfE1BUF9ERU5ZV1JJVEUsIDMsIDAp ID0gMHg3ZjdlNjg3MjQwMDAKPiBtcHJvdGVjdCgweDdmN2U2ODc0NjAwMCwgMTY1ODg4MCwgUFJP VF9OT05FKSA9IDAKPiBtbWFwKDB4N2Y3ZTY4NzQ2MDAwLCAxMzQzNDg4LCBQUk9UX1JFQUR8UFJP VF9FWEVDLAo+IE1BUF9QUklWQVRFfE1BUF9GSVhFRHxNQVBfREVOWVdSSVRFLCAzLCAweDIyMDAw KSA9IDB4N2Y3ZTY4NzQ2MDAwCj4gbW1hcCgweDdmN2U2ODg4ZTAwMCwgMzExMjk2LCBQUk9UX1JF QUQsCj4gTUFQX1BSSVZBVEV8TUFQX0ZJWEVEfE1BUF9ERU5ZV1JJVEUsIDMsIDB4MTZhMDAwKSA9 IDB4N2Y3ZTY4ODhlMDAwCj4gbW1hcCgweDdmN2U2ODhkYjAwMCwgMjQ1NzYsIFBST1RfUkVBRHxQ Uk9UX1dSSVRFLAo+IE1BUF9QUklWQVRFfE1BUF9GSVhFRHxNQVBfREVOWVdSSVRFLCAzLCAweDFi NjAwMCkgPSAweDdmN2U2ODhkYjAwMAo+IG1tYXAoMHg3ZjdlNjg4ZTEwMDAsIDE0MzM2LCBQUk9U X1JFQUR8UFJPVF9XUklURSwKPiBNQVBfUFJJVkFURXxNQVBfRklYRUR8TUFQX0FOT05ZTU9VUywg LTEsIDApID0gMHg3ZjdlNjg4ZTEwMDAKPiBjbG9zZSgzKSAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgPSAwCj4gYXJjaF9wcmN0bChBUkNIX1NFVF9GUywgMHg3ZjdlNjg4ZTY1MDApID0g MAo+IG1wcm90ZWN0KDB4N2Y3ZTY4OGRiMDAwLCAxNjM4NCwgUFJPVF9SRUFEKSA9IDAKPiBtcHJv dGVjdCgweDU1NjU4NTE4MzAwMCwgNDA5NiwgUFJPVF9SRUFEKSA9IDAKPiBtcHJvdGVjdCgweDdm N2U2ODkyNDAwMCwgNDA5NiwgUFJPVF9SRUFEKSA9IDAKPiBtdW5tYXAoMHg3ZjdlNjg4ZTcwMDAs IDg5Mjk2KSAgICAgICAgICAgPSAwCj4gbW1hcChOVUxMLCA0MDk2LCBQUk9UX1JFQUR8UFJPVF9X UklURSwgTUFQX1NIQVJFRHxNQVBfQU5PTllNT1VTLCAtMSwKPiAwKSA9IDB4N2Y3ZTY4OGZjMDAw Cj4gY2xvbmUoY2hpbGRfc3RhY2s9TlVMTCwgZmxhZ3M9Q0xPTkVfRklMRVN8U0lHQ0hMRCkgPSAy NTU4Cj4gZnV0ZXgoMHg3ZjdlNjg4ZmMwMDAsIEZVVEVYX1dBSVQsIDQyOTQ5NjcyOTUsIE5VTExz dHJhY2U6IFByb2Nlc3MgMjU1OCBhdHRhY2hlZAo+ICA8dW5maW5pc2hlZCAuLi4+Cj4gW3BpZCAg MjU1OF0gcHJjdGwoUFJfU0VUX1BERUFUSFNJRywgU0lHS0lMTCkgPSAwCj4gW3BpZCAgMjU1OF0g Z2V0cHBpZCgpICAgICAgICAgICAgICAgICAgID0gMjU1Nwo+IFtwaWQgIDI1NThdIHByY3RsKFBS X1NFVF9OT19ORVdfUFJJVlMsIDEsIDAsIDAsIDApID0gMAo+IFtwaWQgIDI1NThdIHNlY2NvbXAo U0VDQ09NUF9TRVRfTU9ERV9GSUxURVIsIDB4OCAvKgo+IFNFQ0NPTVBfRklMVEVSX0ZMQUdfPz8/ ICovLCB7bGVuPTQsIGZpbHRlcj0weDdmZmRmN2NjOWI1MH0pID0gMwo+IFtwaWQgIDI1NThdIHdy aXRlKDEsICJpbnN0YWxsZWQgc2VjY29tcDogZmQgM1xuIiwgMjQpID0gMjQKPiBbcGlkICAyNTU4 XSBmdXRleCgweDdmN2U2ODhmYzAwMCwgRlVURVhfV0FLRSwgMjE0NzQ4MzY0NyA8dW5maW5pc2hl ZCAuLi4+Cj4gW3BpZCAgMjU1N10gPC4uLiBmdXRleCByZXN1bWVkPiApICAgICAgID0gMAo+IFtw aWQgIDI1NThdIDwuLi4gZnV0ZXggcmVzdW1lZD4gKSAgICAgICA9IDEKPiBbcGlkICAyNTU4XSB3 cml0ZSgxLCAid29rZSAxIHdhaXRlcnNcbiIsIDE1KSA9IDE1Cj4gW3BpZCAgMjU1N10gd3JpdGUo MSwgImNoaWxkIGluc3RhbGxlZCBzZWNjb21wIGZkIDNcbiIsIDI5KSA9IDI5Cj4gW3BpZCAgMjU1 OF0gcnRfc2lnYWN0aW9uKFNJR1VTUjEsIHtzYV9oYW5kbGVyPTB4NTU2NTg1MTgxMjE1LAo+IHNh X21hc2s9W10sIHNhX2ZsYWdzPVNBX1JFU1RPUkVSfFNBX1JFU1RBUlR8U0FfU0lHSU5GTywKPiBz YV9yZXN0b3Jlcj0weDdmN2U2ODc1Yjg0MH0sIE5VTEwsIDgpID0gMAo+IFtwaWQgIDI1NTddIG5h bm9zbGVlcCh7dHZfc2VjPTEsIHR2X25zZWM9MH0sICA8dW5maW5pc2hlZCAuLi4+Cj4gW3BpZCAg MjU1OF0gcGF1c2UoIDx1bmZpbmlzaGVkIC4uLj4KPiBbcGlkICAyNTU3XSA8Li4uIG5hbm9zbGVl cCByZXN1bWVkPiAweDdmZmRmN2NjOWIxMCkgPSAwCj4gW3BpZCAgMjU1N10gd3JpdGUoMSwgImdv aW5nIHRvIHNlbmQgU0lHVVNSMS4uLiIsIDI0KSA9IDI0Cj4gW3BpZCAgMjU1N10gd3JpdGUoMSwg IlxuIiwgMSkgICAgICAgICAgID0gMQo+IFtwaWQgIDI1NTddIGtpbGwoMjU1OCwgU0lHVVNSMSkg ICAgICAgICA9IDAKPiBbcGlkICAyNTU3XSBuYW5vc2xlZXAoe3R2X3NlYz0xLCB0dl9uc2VjPTB9 LCAgPHVuZmluaXNoZWQgLi4uPgo+IFtwaWQgIDI1NThdIDwuLi4gcGF1c2UgcmVzdW1lZD4gKSAg ICAgICA9ID8gRVJFU1RBUlRTWVMgKFRvIGJlCj4gcmVzdGFydGVkIGlmIFNBX1JFU1RBUlQgaXMg c2V0KQo+IFtwaWQgIDI1NThdIC0tLSBTSUdVU1IxIHtzaV9zaWdubz1TSUdVU1IxLCBzaV9jb2Rl PVNJX1VTRVIsCj4gc2lfcGlkPTI1NTcsIHNpX3VpZD0xMDAwfSAtLS0KPiBbcGlkICAyNTU4XSB3 cml0ZSgxLCAic2lnbmFsIGhhbmRsZXIgaW52b2tlZCIsIDIyKSA9IDIyCj4gW3BpZCAgMjU1OF0g d3JpdGUoMSwgIlxuIiwgMSkgICAgICAgICAgID0gMQo+IFtwaWQgIDI1NThdIHJ0X3NpZ3JldHVy bih7bWFzaz1bXX0pICAgICA9IDM0Cj4gW3BpZCAgMjU1OF0gcGF1c2UoIDx1bmZpbmlzaGVkIC4u Lj4KPiBbcGlkICAyNTU3XSA8Li4uIG5hbm9zbGVlcCByZXN1bWVkPiAweDdmZmRmN2NjOWIxMCkg PSAwCj4gW3BpZCAgMjU1N10gZXhpdF9ncm91cCgwKSAgICAgICAgICAgICAgID0gPwo+IFtwaWQg IDI1NTddICsrKyBleGl0ZWQgd2l0aCAwICsrKwo+IDwuLi4gcGF1c2UgcmVzdW1lZD4pICAgICAg ICAgICAgICAgICAgICA9ID8KPiArKysga2lsbGVkIGJ5IFNJR0tJTEwgKysrCj4gdXNlckB2bTp+ L3Rlc3Qvc2VjY29tcC1ub3RpZnktaW50ZXJydXB0JAoKWy4uLl0KCj4+Pj4gICAgICAgICAgICAg ICBJbiB0aGUgYWJvdmUgc2NlbmFyaW8sIHRoZSByaXNrIGlzIHRoYXQgdGhlIHN1cGVydmlzb3Ig bWF5Cj4+Pj4gICAgICAgICAgICAgICB0cnkgdG8gYWNjZXNzIHRoZSBtZW1vcnkgb2YgYSBwcm9j ZXNzIG90aGVyIHRoYW4gdGhlICB0YXLigJAKPj4+PiAgICAgICAgICAgICAgIGdldC4gICBUaGlz ICByYWNlICBjYW4gYmUgYXZvaWRlZCBieSBmb2xsb3dpbmcgdGhlIGNhbGwgdG8KPj4+PiAgICAg ICAgICAgICAgIG9wZW4gd2l0aCBhIFNFQ0NPTVBfSU9DVExfTk9USUZfSURfVkFMSUQgb3BlcmF0 aW9uIHRvIHZlcuKAkAo+Pj4+ICAgICAgICAgICAgICAgaWZ5ICB0aGF0ICB0aGUgIHByb2Nlc3Mg dGhhdCBnZW5lcmF0ZWQgdGhlIG5vdGlmaWNhdGlvbiBpcwo+Pj4+ICAgICAgICAgICAgICAgc3Rp bGwgYWxpdmUuICAoTm90ZSB0aGF0ICBpZiAgdGhlICB0YXJnZXQgIHByb2Nlc3MgIHN1YnNl4oCQ Cj4+Pj4gICAgICAgICAgICAgICBxdWVudGx5ICB0ZXJtaW5hdGVzLCBpdHMgUElEIHdvbid0IGJl IHJldXNlZCBiZWNhdXNlIHRoZXJlCj4+Pgo+Pj4gVGhhdCdzIHdyb25nLCB0aGUgUElEIGNhbiBi ZSByZXVzZWQsIGJ1dCB0aGUgL3Byb2MvJHBpZCBkaXJlY3RvcnkgaXMKPj4+IGludGVybmFsbHkg bm90IGFzc29jaWF0ZWQgd2l0aCB0aGUgbnVtZXJpYyBQSUQsIGJ1dCwgY29uY2VwdHVhbGx5Cj4+ PiBzcGVha2luZywgd2l0aCBhIHNwZWNpZmljIGluY2FybmF0aW9uIG9mIHRoZSBQSUQsIG9yIHNv bWV0aGluZyBsaWtlCj4+PiB0aGF0LiAoQWN0dWFsbHksIGl0IGlzIGFzc29jaWF0ZWQgd2l0aCB0 aGUgInN0cnVjdCBwaWQiLCB3aGljaCBpcyBub3QKPj4+IHJldXNlZCwgaW5zdGVhZCBvZiB0aGUg bnVtZXJpYyBQSUQuKQo+Pgo+PiBUaGFua3MuIEkgc2ltcGxpZmllZCB0aGUgbGFzdCBzZW50ZW5j ZSBvZiB0aGUgcGFyYWdyYXBoOgo+Pgo+PiAgICAgICAgICAgICAgIEluICB0aGUgYWJvdmUgc2Nl bmFyaW8sIHRoZSByaXNrIGlzIHRoYXQgdGhlIHN1cGVydmlzb3IgbWF5Cj4+ICAgICAgICAgICAg ICAgdHJ5IHRvIGFjY2VzcyB0aGUgbWVtb3J5IG9mIGEgcHJvY2VzcyBvdGhlciB0aGFuICB0aGUg IHRhcuKAkAo+PiAgICAgICAgICAgICAgIGdldC4gICBUaGlzICByYWNlICBjYW4gIGJlIGF2b2lk ZWQgYnkgZm9sbG93aW5nIHRoZSBjYWxsIHRvCj4+ICAgICAgICAgICAgICAgb3BlbigyKSB3aXRo IGEgIFNFQ0NPTVBfSU9DVExfTk9USUZfSURfVkFMSUQgIG9wZXJhdGlvbiAgdG8KPj4gICAgICAg ICAgICAgICB2ZXJpZnkgIHRoYXQgdGhlIHByb2Nlc3MgdGhhdCBnZW5lcmF0ZWQgdGhlIG5vdGlm aWNhdGlvbiBpcwo+PiAgICAgICAgICAgICAgIHN0aWxsIGFsaXZlLiAgKE5vdGUgdGhhdCBpZiB0 aGUgdGFyZ2V0IHRlcm1pbmF0ZXMgYWZ0ZXIgdGhlCj4+ICAgICAgICAgICAgICAgbGF0dGVyICBz dGVwLCBhIHN1YnNlcXVlbnQgcmVhZCgyKSBmcm9tIHRoZSBmaWxlIGRlc2NyaXB0b3IKPj4gICAg ICAgICAgICAgICB3aWxsIHJldHVybiAwLCBpbmRpY2F0aW5nIGVuZCBvZiBmaWxlLikKPj4KPj4g SSB0aGluayB0aGF0J3MgcHJvYmFibHkgZW5vdWdoIGRldGFpbC4KPiAKPiBNYXliZSBtYWtlIHRo YXQgIm1heSByZXR1cm4gMCIgaW5zdGVhZCBvZiAid2lsbCByZXR1cm4gMCIgLSByZWFkaW5nCj4g ZnJvbSAvcHJvYy8kcGlkL21lbSBjYW4gb25seSByZXR1cm4gMCBpbiB0aGUgZm9sbG93aW5nIGNh c2VzIEFGQUlDUzoKPiAKPiAxLiB0YXNrLT5tbSB3YXMgYWxyZWFkeSBnb25lIGF0IG9wZW4oKSB0 aW1lCj4gMi4gbW0tPm1tX3VzZXJzIGhhcyBkcm9wcGVkIHRvIHplcm8gKHRoZSBtbSBvbmx5IGhh cyBsYXp5dGxiIHVzZXJzOwo+ICAgIHBhZ2UgdGFibGVzIGFuZCBWTUFzIGFyZSBiZWluZyBibG93 biBhd2F5IG9yIGhhdmUgYmVlbiBibG93biBhd2F5KQo+IDMuIHRoZSBzeXNjYWxsIHdhcyBjYWxs ZWQgd2l0aCBsZW5ndGggMAo+IAo+IFdoZW4gYSBwcm9jZXNzIGhhcyBnb25lIGF3YXksIG5vcm1h bGx5IG1tLT5tbV91c2VycyB3aWxsIGRyb3AgdG8gemVybywKPiBidXQgc29tZW9uZSBlbHNlIGNv dWxkIHRoZW9yZXRpY2FsbHkgc3RpbGwgYmUgaG9sZGluZyBhIHJlZmVyZW5jZSB0bwo+IHRoZSBt bSAoZS5nLiBzb21lb25lIGVsc2UgaW4gdGhlIG1pZGRsZSBvZiBhY2Nlc3NpbmcgL3Byb2MvJHBp ZC9tZW0pLgo+IChTdWNoIHJlZmVyZW5jZXMgc2hvdWxkIG5vcm1hbGx5IG5vdCBiZSB2ZXJ5IGxv bmctbGl2ZWQgdGhvdWdoLikKPiAKPiBBZGRpdGlvbmFsbHksIGluIHRoZSB1bmxpa2VseSBjYXNl IHRoYXQgdGhlIE9PTSBraWxsZXIganVzdCBjaG9tcGVkCj4gdGhyb3VnaCB0aGUgcGFnZSB0YWJs ZXMgb2YgdGhlIHRhcmdldCBwcm9jZXNzLCBJIHRoaW5rIHRoZSByZWFkIHdpbGwKPiByZXR1cm4g LUVJTyAoc2FtZSBlcnJvciBhcyBpZiB0aGUgYWRkcmVzcyB3YXMgc2ltcGx5IHVubWFwcGVkKSBp ZiB0aGUKPiBhZGRyZXNzIGlzIHdpdGhpbiBhIG5vbi1zaGFyZWQgbWFwcGluZy4gKE1heWJlIHRo YXQncyBzb21ldGhpbmcgcHJvY2ZzCj4gY291bGQgZG8gYmV0dGVyLi4uKQoKVGhhbmtzIGZvciBh bGwgdGhlIGRldGFpbCEgSSBjaGFuZ2VkIHRoZSB0ZXh0IHRvIHNheSAibWF5IiAKaW5zdGVhZCBv ZiAid2lsbCIuCgo+IFsuLi5dCj4+Pj4gTk9URVMKPj4+PiAgICAgICAgVGhlIGZpbGUgZGVzY3Jp cHRvciByZXR1cm5lZCB3aGVuIHNlY2NvbXAoMikgaXMgZW1wbG95ZWQgd2l0aCB0aGUKPj4+PiAg ICAgICAgU0VDQ09NUF9GSUxURVJfRkxBR19ORVdfTElTVEVORVIgIGZsYWcgIGNhbiAgYmUgIG1v bml0b3JlZCAgdXNpbmcKPj4+PiAgICAgICAgcG9sbCgyKSwgZXBvbGwoNyksIGFuZCBzZWxlY3Qo MikuICBXaGVuIGEgbm90aWZpY2F0aW9uICBpcyAgcGVuZOKAkAo+Pj4+ICAgICAgICBpbmcsICB0 aGVzZSBpbnRlcmZhY2VzIGluZGljYXRlIHRoYXQgdGhlIGZpbGUgZGVzY3JpcHRvciBpcyByZWFk 4oCQCj4+Pj4gICAgICAgIGFibGUuCj4+Pgo+Pj4gV2Ugc2hvdWxkIHByb2JhYmx5IGFsc28gcG9p bnQgb3V0IHNvbWV3aGVyZSB0aGF0LCBhcwo+Pj4gaW5jbHVkZS91YXBpL2xpbnV4L3NlY2NvbXAu aCBzYXlzOgo+Pj4KPj4+ICAqIFNpbWlsYXIgcHJlY2F1dGlvbnMgc2hvdWxkIGJlIGFwcGxpZWQg d2hlbiBzdGFja2luZyBTRUNDT01QX1JFVF9VU0VSX05PVElGCj4+PiAgKiBvciBTRUNDT01QX1JF VF9UUkFDRS4gRm9yIFNFQ0NPTVBfUkVUX1VTRVJfTk9USUYgZmlsdGVycyBhY3Rpbmcgb24gdGhl Cj4+PiAgKiBzYW1lIHN5c2NhbGwsIHRoZSBtb3N0IHJlY2VudGx5IGFkZGVkIGZpbHRlciB0YWtl cyBwcmVjZWRlbmNlLiBUaGlzIG1lYW5zCj4+PiAgKiB0aGF0IHRoZSBuZXcgU0VDQ09NUF9SRVRf VVNFUl9OT1RJRiBmaWx0ZXIgY2FuIG92ZXJyaWRlIGFueQo+Pj4gICogU0VDQ09NUF9JT0NUTF9O T1RJRl9TRU5EIGZyb20gZWFybGllciBmaWx0ZXJzLCBlc3NlbnRpYWxseSBhbGxvd2luZyBhbGwK Pj4KPj4gTXkgdGFrZWF3YXkgZnJvbSBDaHJpdGlhbidzIGNvbW1lbnRzIGlzIHRoYXQgdGhpcyBj b21tZW50IGluIHRoZSBrZXJuZWwKPj4gc291cmNlIGlzIHBhcnRpYWxseSB3cm9uZywgc2luY2Ug aXQgaXMgbm90IHBvc3NpYmxlIHRvIGluc3RhbGwgbXVsdGlwbGUKPj4gZmlsdGVycyB3aXRoIFNF Q0NPTVBfUkVUX1VTRVJfTk9USUYsIHJpZ2h0Pwo+IAo+IFllYWguIChXZWxsLCBBRkFJQ1MgdGVj aG5pY2FsbHksIHlvdSBjYW4gYWRkIG1vcmUgZmlsdGVycyB0aGF0IHJldHVybgo+IFNFQ0NPTVBf UkVUX1VTRVJfTk9USUYsIGJ1dCB3aGVuIGEgZmlsdGVyIHJldHVybnMgdGhhdCB3aXRob3V0IGhh dmluZwo+IGEgbm90aWZpZXIgZmQgYXR0YWNoZWQsIHNlY2NvbXAgYmxvY2tzIHRoZSBzeXNjYWxs IHdpdGggLUVOT1NZUzsgaXQKPiB3b24ndCB1c2UgdGhlIG5vdGlmaWVyIGZkIGF0dGFjaGVkIHRv IGEgZGlmZmVyZW50IGZpbHRlciBpbiB0aGUKPiBjaGFpbi4pCgpBaCB5ZXMuIEkgbWlzc3Bva2Uu IEkgbWVhbnQgdG8gc2F5IHRoYXQgb25seSBvbmUgZmlsdGVyIGNhbiBiZSBpbnN0YWxsZWQKd2l0 aCBTRUNDT01QX0ZJTFRFUl9GTEFHX05FV19MSVNURU5FUiAoYW5kIHRoYXQncyB3aGF0IHNlY2Nv bXAoMikKY3VycmVudGx5IHNheXMpLiBBbHNvLCBJIGp1c3QgY2hlY2tlZCwgYW5kIEkgaGF2ZSBh bHJlYWR5IGFkZGVkIHRoZQpkZXRhaWwgYWJvdXQgRU5PU1lTIGluIHNlY2NvbXAoMikuCgogICAg ICAgU0VDQ09NUF9SRVRfVVNFUl9OT1RJRiAoc2luY2UgTGludXggNS4wKQogICAgICAgICAgICAg IC4uLgogICAgICAgICAgICAgIElmIHRoZXJlIGlzIG5vIGF0dGFjaGVkICBzdXBlcnZpc29yICAo ZWl0aGVyICBiZWNhdXNlICB0aGUKICAgICAgICAgICAgICBmaWx0ZXIgICB3YXMgICBub3QgICBp bnN0YWxsZWQgICB3aXRoICAgdGhlICAgU0VDQ09NUF9GSUzigJAKICAgICAgICAgICAgICBURVJf RkxBR19ORVdfTElTVEVORVIgZmxhZyBvciBiZWNhdXNlIHRoZSBmaWxlICBkZXNjcmlwdG9yCiAg ICAgICAgICAgICAgd2FzICBjbG9zZWQpLCAgdGhlICBmaWx0ZXIgcmV0dXJucyBFTk9TWVMgKHNp bWlsYXIgdG8gd2hhdAogICAgICAgICAgICAgIGhhcHBlbnMgd2hlbiBhIGZpbHRlciByZXR1cm5z IFNFQ0NPTVBfUkVUX1RSQUNFIGFuZCAgdGhlcmUKICAgICAgICAgICAgICBpcyAgbm8gIHRyYWNl cikuICAgU2VlICBzZWNjb21wX3VzZXJfbm90aWYoMikgIGZvciBmdXJ0aGVyCiAgICAgICAgICAg ICAgZGV0YWlscy4KClsuLi5dCgo+Pj4+ICAgICAgICAgICAgaWYgKHMgPT0gMCkgewo+Pj4+ICAg ICAgICAgICAgICAgIGZwcmludGYoc3RkZXJyLCAiXHRTOiByZWFkKCkgb2YgL3Byb2MvUElEL21l bSAiCj4+Pj4gICAgICAgICAgICAgICAgICAgICAgICAicmV0dXJuZWQgMCAoRU9GKVxuIik7Cj4+ Pj4gICAgICAgICAgICAgICAgZXhpdChFWElUX0ZBSUxVUkUpOwo+Pj4+ICAgICAgICAgICAgfQo+ Pj4+Cj4+Pj4gICAgICAgICAgICBpZiAoY2xvc2UocHJvY01lbUZkKSA9PSAtMSkKPj4+PiAgICAg ICAgICAgICAgICBlcnJFeGl0KCJjbG9zZS0vcHJvYy9QSUQvbWVtIik7Cj4+Pgo+Pj4gV2Ugc2hv dWxkIHByb2JhYmx5IG1ha2Ugc3VyZSBoZXJlIHRoYXQgdGhlIHZhbHVlIHdlIHJlYWQgaXMgYWN0 dWFsbHkKPj4+IE5VTC10ZXJtaW5hdGVkPwo+Pgo+PiBTbywgSSB3YXMgY3VyaW91cyBhYm91dCB0 aGF0IHBvaW50IGFsc28uIEJ1dCwgKHdoeSkgYXJlIHdlIG5vdAo+PiBndWFyYW50ZWVkIHRoYXQg aXQgd2lsbCBiZSBOVUwtdGVybWluYXRlZD8KPiAKPiBCZWNhdXNlIGl0J3MgcmFuZG9tIG1lbW9y eSBmaWxsZWQgYnkgYW5vdGhlciBwcm9jZXNzLCB3aGljaCB3ZSBkb24ndAo+IG5lY2Vzc2FyaWx5 IHRydXN0LiBXaGlsZSBzZWNjb21wIG5vdGlmaWVycyBhcmVuJ3QgdXNhYmxlIGZvciBhcHBseWlu Zwo+ICpleHRyYSogc2VjdXJpdHkgcmVzdHJpY3Rpb25zLCB0aGUgc3VwZXJ2aXNvciB3aWxsIHN0 aWxsIG9mdGVuIGJlIG1vcmUKPiBwcml2aWxlZ2VkIHRoYW4gdGhlIHN1cGVydmlzZWQgcHJvY2Vz cy4KCkQnb2ghIFllcywgSSBzZWUgdGhhdCBJIGZhaWxlZCBteSBTZWN1cml0eSBFbmdpbmVlcmlu ZyAxMDEgZXhhbS4KCkhvdyBhYm91dDoKCiAgICAvKiBXZSBoYXZlIG5vIGd1YXJhbnRlZXMgYWJv dXQgd2hhdCB3YXMgaW4gdGhlIG1lbW9yeSBvZiB0aGUgdGFyZ2V0CiAgICAgICBwcm9jZXNzLiBU aGVyZWZvcmUsIHdlIGVuc3VyZSB0aGF0ICdwYXRoJyBpcyBudWxsLXRlcm1pbmF0ZWQuIFN1Y2gK ICAgICAgIHByZWNhdXRpb25zIGFyZSBwYXJ0aWN1bGFybHkgaW1wb3J0YW50IGluIGNhc2VzIHdo ZXJlIChhcyBpcwogICAgICAgY29tbW9uKSB0aGUgc3VycGVydmlzb3IgaXMgcnVubmluZyBhdCBh IGhpZ2hlciBwcml2aWxlZ2UgbGV2ZWwKICAgICAgIHRoYW4gdGhlIHRhcmdldC4gKi8KCiAgICAv LyAnbGVuJyBpcyBzaXplIG9mIGJ1ZmZlcjsgJ3MnIGlzIHJldHVybiB2YWx1ZSBmcm9tIHByZWFk KCkKICAgIGludCB6ZXJvSWR4ID0gbGVuIC0gMTsKICAgIGlmIChzIDwgemVyb0lkeCkKICAgICAg ICB6ZXJvSWR4ID0gczsKICAgIHBhdGhbemVyb0lkeF0gPSAnXDAnOwoKT3IganVzdCBzaW1wbHk6 CgogICAgcGF0aFtsZW4gLSAxXSA9ICdcMCc7Cgo/Cgo+Pj4+ICAgICAgICAgICAgLyogRGlzY292 ZXIgdGhlIHNpemVzIG9mIHRoZSBzdHJ1Y3R1cmVzIHRoYXQgYXJlIHVzZWQgdG8gcmVjZWl2ZQo+ Pj4+ICAgICAgICAgICAgICAgbm90aWZpY2F0aW9ucyBhbmQgc2VuZCBub3RpZmljYXRpb24gcmVz cG9uc2VzLCBhbmQgYWxsb2NhdGUKPj4+PiAgICAgICAgICAgICAgIGJ1ZmZlcnMgb2YgdGhvc2Ug c2l6ZXMuICovCj4+Pj4KPj4+PiAgICAgICAgICAgIGlmIChzZWNjb21wKFNFQ0NPTVBfR0VUX05P VElGX1NJWkVTLCAwLCAmc2l6ZXMpID09IC0xKQo+Pj4+ICAgICAgICAgICAgICAgIGVyckV4aXQo Ilx0Uzogc2VjY29tcC1TRUNDT01QX0dFVF9OT1RJRl9TSVpFUyIpOwo+Pj4+Cj4+Pj4gICAgICAg ICAgICBzdHJ1Y3Qgc2VjY29tcF9ub3RpZiAqcmVxID0gbWFsbG9jKHNpemVzLnNlY2NvbXBfbm90 aWYpOwo+Pj4+ICAgICAgICAgICAgaWYgKHJlcSA9PSBOVUxMKQo+Pj4+ICAgICAgICAgICAgICAg IGVyckV4aXQoIlx0UzogbWFsbG9jIik7Cj4+Pj4KPj4+PiAgICAgICAgICAgIHN0cnVjdCBzZWNj b21wX25vdGlmX3Jlc3AgKnJlc3AgPSBtYWxsb2Moc2l6ZXMuc2VjY29tcF9ub3RpZl9yZXNwKTsK Pj4+Cj4+PiBUaGlzIHNob3VsZCBwcm9iYWJseSBkbyBzb21ldGhpbmcgbGlrZSBtYXgoc2l6ZXMu c2VjY29tcF9ub3RpZl9yZXNwLAo+Pj4gc2l6ZW9mKHN0cnVjdCBzZWNjb21wX25vdGlmX3Jlc3Ap KSBpbiBjYXNlIHRoZSBwcm9ncmFtIHdhcyBidWlsdAo+Pj4gYWdhaW5zdCBuZXcgVUFQSSBoZWFk ZXJzIHRoYXQgbWFrZSBzdHJ1Y3Qgc2VjY29tcF9ub3RpZl9yZXNwIGJpZywgYnV0Cj4+PiBpcyBy dW5uaW5nIHVuZGVyIGFuIG9sZCBrZXJuZWwgd2hlcmUgdGhhdCBzdHJ1Y3QgaXMgc3RpbGwgc21h bGxlcj8KPj4KPj4gSSdtIGNvbmZ1c2VkLiBXaHk/IEkgbWVhbiwgaWYgdGhlIHJ1bm5pbmcga2Vy bmVsIHNheXMgdGhhdCBpdCBleHBlY3RzCj4+IGEgYnVmZmVyIG9mIGEgY2VydGFpbiBzaXplLCBh bmQgd2UgYWxsb2NhdGUgYSBidWZmZXIgb2YgdGhhdCBzaXplLAo+PiB3aGF0J3MgdGhlIHByb2Js ZW0/Cj4gCj4gQmVjYXVzZSBpbiB1c2Vyc3BhY2UsIHdlIGNhc3QgdGhlIHJlc3VsdCBvZiBtYWxs b2MoKSB0byBhICJzdHJ1Y3QKPiBzZWNjb21wX25vdGlmX3Jlc3AgKiIuIElmIHRoZSBrZXJuZWwg dGVsbHMgdXMgdGhhdCBpdCBleHBlY3RzIGEgc2l6ZQo+IHNtYWxsZXIgdGhhbiBzaXplb2Yoc3Ry dWN0IHNlY2NvbXBfbm90aWZfcmVzcCksIHRoZW4gd2UgZW5kIHVwIHdpdGggYQo+IHBvaW50ZXIg dG8gYSBzdHJ1Y3QgdGhhdCBjb25zaXN0cyBwYXJ0bHkgb2YgYWxsb2NhdGVkIG1lbW9yeSwgcGFy dGx5Cj4gb2Ygb3V0LW9mLWJvdW5kcyBtZW1vcnksIHdoaWNoIGlzIGdlbmVyYWxseSBhIGJhZCBp ZGVhIC0gSSdtIG5vdCBzdXJlCj4gd2hldGhlciB0aGUgQyBzdGFuZGFyZCBwZXJtaXRzIHRoYXQu IEFuZCBpZiB1c2Vyc3BhY2UgdGhlbiBlLmcuCj4gZGVjaWRlcyB0byBhY2Nlc3Mgc29tZSBtZW1i ZXIgb2YgdGhhdCBzdHJ1Y3QgdGhhdCBpcyBiZXlvbmQgd2hhdCB0aGUKPiBrZXJuZWwgdGhpbmtz IGlzIHRoZSBzdHJ1Y3Qgc2l6ZSwgd2UgZ2V0IGFjdHVhbCBPT0IgbWVtb3J5IGFjY2Vzc2VzLgoK VGhhbmtzLiBHb3QgaXQuIChCdXQgZ29zaCwgdGhpcyBzZWVtcyBsaWtlIGEgZnJhZ2lsZSBBUEkg bWVzcy4pCgpJIGFkZGVkIHRoZSBmb2xsb3dpbmcgdG8gdGhlIGNvZGU6CgogICAgLyogV2hlbiBh bGxvY2F0aW5nIHRoZSByZXNwb25zZSBidWZmZXIsIHdlIG11c3QgYWxsb3cgZm9yIHRoZSBmYWN0 CiAgICAgICB0aGF0IHRoZSB1c2VyLXNwYWNlIGJpbmFyeSBtYXkgaGF2ZSBiZWVuIGJ1aWx0IHdp dGggdXNlci1zcGFjZQogICAgICAgaGVhZGVycyB3aGVyZSAnc3RydWN0IHNlY2NvbXBfbm90aWZf cmVzcCcgaXMgYmlnZ2VyIHRoYW4gdGhlCiAgICAgICByZXNwb25zZSBidWZmZXIgZXhwZWN0ZWQg YnkgdGhlIChvbGRlcikga2VybmVsLiBUaGVyZWZvcmUsIHdlCiAgICAgICBhbGxvY2F0ZSBhIGJ1 ZmZlciB0aGF0IGlzIHRoZSBtYXhpbXVtIG9mIHRoZSB0d28gc2l6ZXMuIFRoaXMKICAgICAgIGVu c3VyZXMgdGhhdCBpZiB0aGUgc3VwZXJ2aXNvciBwbGFjZXMgYnl0ZXMgaW50byB0aGUgcmVzcG9u c2UKICAgICAgIHN0cnVjdHVyZSB0aGF0IGFyZSBwYXN0IHRoZSByZXNwb25zZSBzaXplIHRoYXQg dGhlIGtlcm5lbCBleHBlY3RzLAogICAgICAgdGhlbiB0aGUgc3VwZXJ2aXNvciBpcyBub3QgdG91 Y2hpbmcgYW4gaW52YWxpZCBtZW1vcnkgbG9jYXRpb24uICovCgogICAgc2l6ZV90IHJlc3Bfc2l6 ZSA9IHNpemVzLnNlY2NvbXBfbm90aWZfcmVzcDsKICAgIGlmIChzaXplb2Yoc3RydWN0IHNlY2Nv bXBfbm90aWZfcmVzcCkgPiByZXNwX3NpemUpCiAgICAgICAgcmVzcF9zaXplID0gc2l6ZW9mKHN0 cnVjdCBzZWNjb21wX25vdGlmX3Jlc3ApOwoKICAgIHN0cnVjdCBzZWNjb21wX25vdGlmX3Jlc3Ag KnJlc3AgPSBtYWxsb2MocmVzcF9zaXplKTsKCk9rYXk/CgpUaGFua3MsCgpNaWNoYWVsCgotLSAK TWljaGFlbCBLZXJyaXNrCkxpbnV4IG1hbi1wYWdlcyBtYWludGFpbmVyOyBodHRwOi8vd3d3Lmtl cm5lbC5vcmcvZG9jL21hbi1wYWdlcy8KTGludXgvVU5JWCBTeXN0ZW0gUHJvZ3JhbW1pbmcgVHJh aW5pbmc6IGh0dHA6Ly9tYW43Lm9yZy90cmFpbmluZy8KX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX18KQ29udGFpbmVycyBtYWlsaW5nIGxpc3QKQ29udGFpbmVy c0BsaXN0cy5saW51eC1mb3VuZGF0aW9uLm9yZwpodHRwczovL2xpc3RzLmxpbnV4Zm91bmRhdGlv bi5vcmcvbWFpbG1hbi9saXN0aW5mby9jb250YWluZXJz