Date: Sat, 26 Aug 2017 08:49:12 +1000 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Conrad Meyer <cem@freebsd.org> Cc: Alan Somers <asomers@freebsd.org>, src-committers <src-committers@freebsd.org>, "svn-src-all@freebsd.org" <svn-src-all@freebsd.org>, "svn-src-head@freebsd.org" <svn-src-head@freebsd.org> Subject: Re: svn commit: r322893 - head/bin/dd Message-ID: <20170826075540.X976@besplex.bde.org> In-Reply-To: <CAG6CVpVf8TNqnErZzoofuqy-TA9cXoZgf2W8Y2J2vNa63Vmu7Q@mail.gmail.com> References: <201708251531.v7PFVtoZ038242@repo.freebsd.org> <CAG6CVpXmL95eAjf4rXTL8QqnLcu5aQPRZ4cwk3sLGUSR35jnBg@mail.gmail.com> <CAOtMX2gXBcQyxTr_KivoGoKBP6UXL-sq9KhhB89fBgESfWV0yg@mail.gmail.com> <CAG6CVpVf8TNqnErZzoofuqy-TA9cXoZgf2W8Y2J2vNa63Vmu7Q@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 25 Aug 2017, Conrad Meyer wrote: > Well, not negative, just large uint64_t numbers that would be negative > as off_t (int64_t). > > E.g., dd if=/dev/kmem bs=1 iseek=0xfffff...foo count=8. I think we > would like that to work. I don't recall whether it does or not before > this change. This is broken on 64-bit systems, first by the horrible get_off_t(), then by broken range checking in at least old versions of dd. The first bug in get_off_t() is that it uses strtoimax(). This fails for offsets >= INTMAX_MAX. This breaks the natural use of dd to seek to the kernel part of kmem using dd. E.g.: dd if=/dev/kmem bs=1 count=1 iseek=0xffffffff802d2100 This should give a negative offset than then works. (lseek() to negative offsets is implementation-defined for special files, and FreeBSD defines it so that it works for seeking in kmem. This depends on some 2's complement magic to represent large unsigned offsets as negative signed.) However, it doesn't work to double bs and halve iseek. The multiplication is then done by a higher level. It exceeds OFF_MAX, so the lseek() isn't tried. get_off_t() but not the higher level is fixed in my version. It does work to calculate the negative offset in another way inside get_off_t(). E.g., bs=1 iseek=-1 gives -1 which is passed to lseek(). bs=2 iseek=-1 also works to give the correct offset of -2 for lseek(). The arithmetic for converting large number like 0xffffffff802d2100 to a negative value is painful, especially since shells have similar bugs near INTMAX_MAX and UINTMAX_MAX and with signed and/or unsigned types even if they support 64-bit integers. The buggy range checking for bs=2 iseek=0x7fffffff802d2100 seems to be only in old versions of dd. It was in jcl(), and was just for the initial args (multiplying them would exceed OFF_MAX). Now there seems to be no check for overflow. The multiplication in pos_in() just overflows even if the check in jcl() passed, later when the seek point advances past INTMAX_MAX (if this exceeds OFF_MAX, then passing the result of the multiplicating to lseek() starts overflowing before the multiplication does). [Context lost to top posting]. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20170826075540.X976>