From owner-freebsd-hackers@FreeBSD.ORG Thu Oct 7 05:38:12 2010 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C3B8D106564A; Thu, 7 Oct 2010 05:38:12 +0000 (UTC) (envelope-from yanegomi@gmail.com) Received: from mail-iw0-f182.google.com (mail-iw0-f182.google.com [209.85.214.182]) by mx1.freebsd.org (Postfix) with ESMTP id 5DDA78FC0A; Thu, 7 Oct 2010 05:38:12 +0000 (UTC) Received: by iwn8 with SMTP id 8so15205iwn.13 for ; Wed, 06 Oct 2010 22:38:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:sender:received :in-reply-to:references:date:x-google-sender-auth:message-id:subject :from:to:cc:content-type; bh=KquTfLp1PnwhowBAxIQ7rJ3AMWoab/23J3XytufV5jA=; b=JPtkac8ZBiQSoCPw9XypPROwDohmtW2Qk0csKnrJ4WLFvcMV5KvXoKGMIlMxfhTnzm ChjHtB24Xjffa1Z4xB4Lij16llDbfhygW3A1c7mrnD2CXPZAygsQWMRmen7+9+9N3BtB sSDVr6t7MiRQ7eTA2T5JhSCJlqYHZhV5dLV2U= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type; b=VOZ9o7SUq5t44QB85SfAbxzL3lkp6QcnorFEPiHjURDOdOWxGTDHM3PGg+WNG58PVq UFu0mecsis2ayVArCDlKZ3KENFl5ddzOJ0ojC+xHKBtp7G6fBT0YNioH33lbf+FcNfaK 0HG6px34LOESQdXin+wV5vSV3mifVW3Z3/yZs= MIME-Version: 1.0 Received: by 10.231.193.81 with SMTP id dt17mr284736ibb.177.1286429863838; Wed, 06 Oct 2010 22:37:43 -0700 (PDT) Sender: yanegomi@gmail.com Received: by 10.231.184.3 with HTTP; Wed, 6 Oct 2010 22:37:43 -0700 (PDT) In-Reply-To: References: <20101005235054.GA45827@freebsd.org> <20101006173522.GA92402@freebsd.org> <20101006193827.GA13528@freebsd.org> Date: Wed, 6 Oct 2010 22:37:43 -0700 X-Google-Sender-Auth: EOt7Aq_nsrXxrUCnfqQmRs1KZlk Message-ID: From: Garrett Cooper To: Garrett Cooper Content-Type: multipart/mixed; boundary=0050450172391002ee0492004b28 Cc: Alexander Best , Sergey Kandaurov , freebsd-hackers@freebsd.org Subject: Re: issue with unsetting 'arch' flag X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Oct 2010 05:38:12 -0000 --0050450172391002ee0492004b28 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Wed, Oct 6, 2010 at 4:03 PM, Garrett Cooper wrote: > On Wed, Oct 6, 2010 at 3:01 PM, Sergey Kandaurov wrot= e: >> On 6 October 2010 23:38, Alexander Best wrote: >>> On Wed Oct =A06 10, Garrett Cooper wrote: >>>> On Wed, Oct 6, 2010 at 10:35 AM, Alexander Best = wrote: >>>> > On Wed Oct =A06 10, Garrett Cooper wrote: >>>> >> On Tue, Oct 5, 2010 at 4:50 PM, Alexander Best wrote: >>>> >> > hi there, >>>> >> > >>>> >> > i think the following example shows the problem better than a lon= g explanation: >>>> >> > >>>> >> > `touch ftest && chflags arch ftest && chflags -vv 0 ftest`. >>>> >> > =A0^^non-root =A0 =A0 ^^root =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0^^non= -root >>>> >> > >>>> >> > chflags claims to have cleared the 'arch' flag (which should be i= mpossible as >>>> >> > non-root user), but indeed has done nothing. >>>> >> > >>>> >> > i've tried the same with 'sappnd' and that works as can be expect= ed. >>>> >> > >>>> >> > The issue was confirmed to exist in HEAD (me), stable/8 (pgollucc= 1, jpaetzel) >>>> >> > and stable/7 (nox). >>>> >> > On stable/6 it does NOT exist (jpaetzel). chflags properly fails = with EPERM. >>>> >> >>>> >> =A0 =A0 Fails for me when I call the syscall directly, as I would e= xpect, >>>> >> and passes when I'm superuser: >>>> >> >>>> >> $ ./test_chflags >>>> >> (uid, euid) =3D (1000, 1000) >>>> >> test_chflags: chflags: Operation not permitted >>>> >> test_chflags: lchflags: Operation not permitted >>>> >> $ sudo ./test_chflags >>>> >> (uid, euid) =3D (0, 0) >>>> >> >>>> >> =A0 =A0 According to my basic inspection in strtofflags >>>> >> (.../lib/libc/gen/strtofflags.c), it works as well. >>>> >> =A0 =A0 And last but not least, executing the commands directly on = the CLI work: >>>> >> >>>> >> $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >>>> >> $ chflags arch $tmpfile >>>> >> chflags: /tmp/chflags.nQm1IL: Operation not permitted >>>> >> $ rm $tmpfile >>>> >> $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >>>> >> $ sudo chflags arch $tmpfile >>>> >> $ sudo chflags noarch $tmpfile >>>> >> $ rm $tmpfile >>>> > >>>> > thanks for your test app and helping out with this problem. i'm not = sure >>>> > however you understood the problem. probably i didn't explain it rig= ht: >>>> > >>>> > $ sudo rm -d /tmp/chflags.XXXXXX >>>> > $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >>>> > $ sudo chflags arch $tmpfile >>>> > $ chflags noarch $tmpfile >>>> > >>>> > is what's causing the problem. the last chflags call should fail, bu= t it >>>> > doesn't. >>>> >>>> Sorry... my CLI based example was stupid. I meant: >>>> >>>> $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >>>> $ chflags arch $tmpfile >>>> chflags: /tmp/chflags.V2NpXR: Operation not permitted >>>> $ chflags noarch $tmpfile >>>> $ rm $tmpfile >>>> >>>> Currently chflags(2) states: >>>> >>>> =A0 =A0 =A0The SF_IMMUTABLE, SF_APPEND, SF_NOUNLINK, and SF_ARCHIVED f= lags may only >>>> =A0 =A0 =A0be set or unset by the super-user. =A0Attempts to set these= flags by non- >>>> =A0 =A0 =A0super-users are rejected, >>> attempts by non-superusers to= clear >>>> flags that >>>> =A0 =A0 =A0are already unset are silently ignored. <<< =A0These flags = may be set at any >>>> =A0 =A0 =A0time, but normally may only be unset when the system is in = single-user >>>> =A0 =A0 =A0mode. =A0(See init(8) for details.) >>>> >>>> So this behavior is already well documented :). The EPERM section >>>> should really note SF_ARCHIVED though (whoever added the flag forgot >>>> to add that particular item to the ERRORS section). >>> >>> that's perfectly alright. clearing an unset flag shouldn't cause any er= ror to >>> be returned. however in my example arch *does* get set and still trying= to >>> unset it as normal user doesn't return an error. >>> >> >> It's even more interesting. >> >> As far as I could parse the code: >> - UFS has no special handling for SF_ARCHIVED (I found only it for msdos= fs) > > =A0 =A0_very_ interesting: > > [/sys]$ grep -r SF_ARCHIVED kern/ fs/ ufs/ | grep -v svn > fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 vap->va_flags |=3D SF= _ARCHIVED; > fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 if (vap->va_flags & ~= SF_ARCHIVED) > fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 if (vap->va_flags & S= F_ARCHIVED) > > =A0 =A0The commit that introduced this change probably wasn't doing the > right thing: http://svn.freebsd.org/viewvc/base/head/sys/fs/msdosfs/msdos= fs_vnops.c?revision=3D5241&view=3Dmarkup > ; cp(1) probably should have been fixed in lieu of `fixing' msdosfs. > >> - ufs_setattr() does not handle unsetting SF_ARCHIVED, >> =A0so all what it does is simply return zero. > > =A0 =A0 [EOPNOTSUPP] =A0 =A0 =A0 The underlying file system does not supp= ort file > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flags. > > =A0 =A0So I would expect for invalid flags to return EOPNOTSUPP. > > ... > > $ ~/test_chflags_negative > test_chflags_negative: should not get here > $ sudo ~/test_chflags_negative > test_chflags_negative: should not get here > > *facepalm* > > =A0 =A0I think the problem in part is here (sys/stat.h): > > =A0* > =A0* Super-user and owner changeable flags. > =A0*/ > #define UF_SETTABLE =A0 =A0 0x0000ffff =A0 =A0 =A0/* mask of owner change= able flags */ > #define UF_NODUMP =A0 =A0 =A0 0x00000001 =A0 =A0 =A0/* do not dump file *= / > #define UF_IMMUTABLE =A0 =A00x00000002 =A0 =A0 =A0/* file may not be chan= ged */ > #define UF_APPEND =A0 =A0 =A0 0x00000004 =A0 =A0 =A0/* writes to file may= only append */ > #define UF_OPAQUE =A0 =A0 =A0 0x00000008 =A0 =A0 =A0/* directory is opaqu= e wrt. union */ > #define UF_NOUNLINK =A0 =A0 0x00000010 =A0 =A0 =A0/* file may not be remo= ved or renamed */ > /* > =A0* Super-user changeable flags. > =A0*/ > #define SF_SETTABLE =A0 =A0 0xffff0000 =A0 =A0 =A0/* mask of superuser ch= angeable flags */ > #define SF_ARCHIVED =A0 =A0 0x00010000 =A0 =A0 =A0/* file is archived */ > #define SF_IMMUTABLE =A0 =A00x00020000 =A0 =A0 =A0/* file may not be chan= ged */ > #define SF_APPEND =A0 =A0 =A0 0x00040000 =A0 =A0 =A0/* writes to file may= only append */ > #define SF_NOUNLINK =A0 =A0 0x00100000 =A0 =A0 =A0/* file may not be remo= ved or renamed */ > #define SF_SNAPSHOT =A0 =A0 0x00200000 =A0 =A0 =A0/* snapshot inode */ > > =A0 =A0Note the *_SETTABLE macros, and the fact that they allow for more > functionality than what's currently slotted with the one-hot encoded > flags currently available. > =A0 =A0SF_ARCHIVED is not present in the other BSDs or Mac OSX either (I > did some hunting for a python bug related to chflags a few weeks > ago)... and I'm not even sure what this functionality really buys us > because it's not well described (but I'd be happy to get an > explanation/history lesson). > >> - /bin/chflags doesn't check the actual flags value from inode after >> calling chflags() syscall, and blindly assumes all is well, if chflags() >> returns with zero, > > =A0 =A0Yeah... but ideally tests should be written for this stuff and > exercised on all filesystems and exercised whenever code in this > particular path is changed, because that would potentially turn into a > noticeable performance hit [depending on how it's implemented in > chflags(1)]. And lo and behold it already does exist under > .../tools/regression/fstest/tests/chflags . I'll audit this once I get > back home... For starters, the tests were moved to .../tools/regression/pjdfstest . This fixes the manpage and the negative flags testcase at least. I ran the pjdfstest on a UFS2 partition on my test machine and tmpfs, and it passed chflags with flying colors. msdosfs unfortunately isn't supported yet, but I did some manual testing and everything seemed ok. I also need to check and see whether or not pjdfstest is doing the right job with negative testcases. I didn't have a ext2/3 or zfs pool to test with, so if someone could poke around with those filesystems it would be much appreciated :). And finally, here are all of the references in the sourcebase to SF_ARCHIVED: # /usr/local/bin/svnversion 213377M # grep -r SF_ARCHIVED /usr/src/ | grep -v svn grep: /usr/src/tools/regression/pjdfstest/pjdfstest_5aaec5b222b60945b16daa0= e8d61313d/pjdfstest_b4353ca81458e0bfc9ec5be8ff741eb2/usr/src/tools/regressi= on/priv/priv_vfs_chflags.c: flags |=3D SF_ARCHIVED; /usr/src/tools/regression/priv/priv_vfs_chflags.c: flags |=3D SF_ARCHIVED; /usr/src/tools/regression/priv/priv_vfs_chflags.c: flags |=3D SF_ARCHIVED; /usr/src/tools/regression/pjdfstest/tests/chflags/00.t: allflags=3D"UF_NODU= MP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF= _APPEND,SF_NOUNLINK" /usr/src/tools/regression/pjdfstest/tests/chflags/00.t: systemflags=3D"SF_A= RCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK" Binary file /usr/src/tools/regression/pjdfstest/pjdfstest matches /usr/src/tools/regression/pjdfstest/pjdfstest.c:#ifdef SF_ARCHIVED /usr/src/tools/regression/pjdfstest/pjdfstest.c: { SF_ARCHIVED, "SF_ARCHIVE= D" }, : Operation not supported grep: warning: /usr/src/sys/modules/tmpfs/@: recursive directory loop /usr/src/lib/libc/gen/strtofflags.c: { "noarch", SF_ARCHIVED, 0 }, /usr/src/lib/libc/gen/strtofflags.c: { "noarchived", SF_ARCHIVED, 0 }, /usr/src/lib/libc/sys/chflags.2:.It Dv SF_ARCHIVED /usr/src/lib/libc/sys/chflags.2:.Dv SF_ARCHIVED /usr/src/lib/libc/sys/chflags.2:.Dv SF_ARCHIVED , SF_IMMUTABLE , SF_APPEND = , /usr/src/lib/libc/sys/chflags.2:.Dv SF_ARCHIVED , SF_IMMUTABLE , SF_APPEND = , /usr/src/lib/libarchive/archive_entry.c:#ifdef SF_ARCHIVED /usr/src/lib/libarchive/archive_entry.c: { "noarch", L"noarch", SF_ARCHIVED, 0 }, /usr/src/lib/libarchive/archive_entry.c: { "noarchived", L"noarchived", SF_ARCHIVED, 0 }, /usr/src/sys/fs/msdosfs/msdosfs_vnops.c: vap->va_flags |=3D SF_ARCHIVED; /usr/src/sys/fs/msdosfs/msdosfs_vnops.c: if (vap->va_flags & ~SF_ARCHIVED) /usr/src/sys/fs/msdosfs/msdosfs_vnops.c: if (vap->va_flags & SF_ARCHIVED) /usr/src/sys/sys/stat.h:#define SF_ARCHIVED 0x00010000 /* file is archived = */ /usr/src/sys/sys/stat.h:#define SF_SETTABLE (SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND | \ So it doesn't look like anything's utilizing the functionality, other than msdosfs, and all that really does is tweak the following attribute: #define ATTR_ARCHIVE 0x20 /* file is new or modified */ and vice versa. I vaguely remember archive file types in FAT32 from the Win95 days, but my memory is a bit hazy as to what the attribute actually does. Thanks, -Garrett --0050450172391002ee0492004b28 Content-Type: application/octet-stream; name="note-EPERM-SF_ARCHIVED-requirement.diff" Content-Disposition: attachment; filename="note-EPERM-SF_ARCHIVED-requirement.diff" Content-Transfer-Encoding: base64 X-Attachment-Id: f_gez5wqb21 SW5kZXg6IGxpYi9saWJjL3N5cy9jaGZsYWdzLjIKPT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQotLS0gbGliL2xpYmMvc3lz L2NoZmxhZ3MuMgkocmV2aXNpb24gMjEzMzc3KQorKysgbGliL2xpYmMvc3lzL2NoZmxhZ3MuMgko d29ya2luZyBjb3B5KQpAQCAtMTQ4LDE0ICsxNDgsMTQgQEAKIHRoZSBlZmZlY3RpdmUgdXNlciBJ RCBpcyBub3QgdGhlIHN1cGVyLXVzZXIuCiAuSXQgQnEgRXIgRVBFUk0KIE9uZSBvZgotLkR2IFNG X0lNTVVUQUJMRSAsIFNGX0FQUEVORCAsCisuRHYgU0ZfQVJDSElWRUQgLCBTRl9JTU1VVEFCTEUg LCBTRl9BUFBFTkQgLAogb3IKIC5EdiBTRl9OT1VOTElOSwogaXMgc2V0IGFuZCB0aGUgdXNlciBp cyBlaXRoZXIgbm90IHRoZSBzdXBlci11c2VyIG9yCiBzZWN1cmVsZXZlbCBpcyBncmVhdGVyIHRo YW4gMC4KIC5JdCBCcSBFciBFUEVSTQogQSBub24tc3VwZXItdXNlciB0cmllcyB0byBzZXQgb25l IG9mCi0uRHYgU0ZfSU1NVVRBQkxFICwgU0ZfQVBQRU5EICwKKy5EdiBTRl9BUkNISVZFRCAsIFNG X0lNTVVUQUJMRSAsIFNGX0FQUEVORCAsCiBvcgogLkR2IFNGX05PVU5MSU5LIC4KIC5JdCBCcSBF ciBFUEVSTQo= --0050450172391002ee0492004b28 Content-Type: application/octet-stream; name="fail-chflags-with-bad-flags.diff" Content-Disposition: attachment; filename="fail-chflags-with-bad-flags.diff" Content-Transfer-Encoding: base64 X-Attachment-Id: f_gez6b9ry2 SW5kZXg6IHN5cy9rZXJuL3Zmc19zeXNjYWxscy5jCj09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLS0tIHN5cy9rZXJuL3Zm c19zeXNjYWxscy5jCShyZXZpc2lvbiAyMTMzNzcpCisrKyBzeXMva2Vybi92ZnNfc3lzY2FsbHMu Ywkod29ya2luZyBjb3B5KQpAQCAtMjcxMiw2ICsyNzEyLDggQEAKIAlpbnQgdmZzbG9ja2VkOwog CiAJQVVESVRfQVJHX0ZGTEFHUyh1YXAtPmZsYWdzKTsKKwlpZiAoKHVhcC0+ZmxhZ3MgJiAoU0Zf U0VUVEFCTEUgfCBVRl9TRVRUQUJMRSkpICE9IHVhcC0+ZmxhZ3MpCisJCXJldHVybiAoRU9QTk9U U1VQUCk7CiAJTkRJTklUKCZuZCwgTE9PS1VQLCBGT0xMT1cgfCBNUFNBRkUgfCBBVURJVFZOT0RF MSwgVUlPX1VTRVJTUEFDRSwKIAkgICAgdWFwLT5wYXRoLCB0ZCk7CiAJaWYgKChlcnJvciA9IG5h bWVpKCZuZCkpICE9IDApCkluZGV4OiBzeXMvc3lzL3N0YXQuaAo9PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci0tLSBzeXMv c3lzL3N0YXQuaAkocmV2aXNpb24gMjEzMzc3KQorKysgc3lzL3N5cy9zdGF0LmgJKHdvcmtpbmcg Y29weSkKQEAgLTI2MSwyMiArMjYxLDI4IEBACiAgKgogICogU3VwZXItdXNlciBhbmQgb3duZXIg Y2hhbmdlYWJsZSBmbGFncy4KICAqLwotI2RlZmluZQlVRl9TRVRUQUJMRQkweDAwMDBmZmZmCS8q IG1hc2sgb2Ygb3duZXIgY2hhbmdlYWJsZSBmbGFncyAqLwogI2RlZmluZQlVRl9OT0RVTVAJMHgw MDAwMDAwMQkvKiBkbyBub3QgZHVtcCBmaWxlICovCiAjZGVmaW5lCVVGX0lNTVVUQUJMRQkweDAw MDAwMDAyCS8qIGZpbGUgbWF5IG5vdCBiZSBjaGFuZ2VkICovCiAjZGVmaW5lCVVGX0FQUEVORAkw eDAwMDAwMDA0CS8qIHdyaXRlcyB0byBmaWxlIG1heSBvbmx5IGFwcGVuZCAqLwogI2RlZmluZSBV Rl9PUEFRVUUJMHgwMDAwMDAwOAkvKiBkaXJlY3RvcnkgaXMgb3BhcXVlIHdydC4gdW5pb24gKi8K ICNkZWZpbmUgVUZfTk9VTkxJTksJMHgwMDAwMDAxMAkvKiBmaWxlIG1heSBub3QgYmUgcmVtb3Zl ZCBvciByZW5hbWVkICovCisKKwkJCQkJLyogbWFzayBvZiBzdXBlcnVzZXIgY2hhbmdlYWJsZSBm bGFncyAqLworI2RlZmluZQlVRl9TRVRUQUJMRQkoVUZfTk9EVU1QIHwgVUZfSU1NVVRBQkxFIHwg VUZfQVBQRU5EIHwgVUZfT1BBUVVFIHwgXAorCQkJIFVGX05PVU5MSU5LKQogLyoKICAqIFN1cGVy LXVzZXIgY2hhbmdlYWJsZSBmbGFncy4KICAqLwotI2RlZmluZQlTRl9TRVRUQUJMRQkweGZmZmYw MDAwCS8qIG1hc2sgb2Ygc3VwZXJ1c2VyIGNoYW5nZWFibGUgZmxhZ3MgKi8KICNkZWZpbmUJU0Zf QVJDSElWRUQJMHgwMDAxMDAwMAkvKiBmaWxlIGlzIGFyY2hpdmVkICovCiAjZGVmaW5lCVNGX0lN TVVUQUJMRQkweDAwMDIwMDAwCS8qIGZpbGUgbWF5IG5vdCBiZSBjaGFuZ2VkICovCiAjZGVmaW5l CVNGX0FQUEVORAkweDAwMDQwMDAwCS8qIHdyaXRlcyB0byBmaWxlIG1heSBvbmx5IGFwcGVuZCAq LwogI2RlZmluZQlTRl9OT1VOTElOSwkweDAwMTAwMDAwCS8qIGZpbGUgbWF5IG5vdCBiZSByZW1v dmVkIG9yIHJlbmFtZWQgKi8KICNkZWZpbmUJU0ZfU05BUFNIT1QJMHgwMDIwMDAwMAkvKiBzbmFw c2hvdCBpbm9kZSAqLwogCisJCQkJCS8qIG1hc2sgb2Ygc3VwZXJ1c2VyIGNoYW5nZWFibGUgZmxh Z3MgKi8KKyNkZWZpbmUJU0ZfU0VUVEFCTEUJKFNGX0FSQ0hJVkVEIHwgU0ZfSU1NVVRBQkxFIHwg U0ZfQVBQRU5EIHwgXAorCQkJIFNGX05PVU5MSU5LIHwgU0ZfU05BUFNIT1QpCisKICNpZmRlZiBf S0VSTkVMCiAvKgogICogU2hvcnRoYW5kIGFiYnJldmlhdGlvbnMgb2YgYWJvdmUuCg== --0050450172391002ee0492004b28--