[HN Gopher] size_t-to-int vulnerability in Linux's filesystem layer
___________________________________________________________________
size_t-to-int vulnerability in Linux's filesystem layer
Author : jwilk
Score : 283 points
Date : 2021-07-20 13:00 UTC (9 hours ago)
(HTM) web link (www.openwall.com)
(TXT) w3m dump (www.openwall.com)
| cesarb wrote:
| This kind of issue is the reason why some more modern languages
| like Rust or Go do not have implicit narrowing conversions. For
| instance, on Rust, trying to simply pass an usize (Rust's
| equivalent of size_t) to a function which expects an i32 (Rust's
| equivalent of int) will not compile; the programmer has to write
| "size as i32" (Rust's equivalent of "(int) size"), which makes it
| explicit that it might truncate the value at that point.
|
| (Some Rust developers argue that even "size as i32" should be
| avoided, and "size.try_into()" should be used instead, since it
| forces the programmer to treat an overflow explicitly at runtime,
| instead of silently wrapping.)
| pjmlp wrote:
| Languages of the same age or older than C, also have explicit
| narrowing, but apparently that was seen as programming with a
| straightjacket.
| mytailorisrich wrote:
| The compiler can issue warnings for this.
|
| This os why in C it is a good practice to enable all compiler
| warnings and to have the compiler treat warnings as errors.
| viraptor wrote:
| In theory but not in practice if you're distributing your
| apps sources.
|
| If you write for C compiler Foo 8, there's a decent chance
| Foo 9 will raise a warning which didn't exist before. Now you
| have to handle "why doesn't this compile" issues and
| distributions have to patch your sources to do future
| releases. And that's ignoring bugs like GCC in the past where
| in some versions you could not satisfy specific warnings.
| titzer wrote:
| This is a deep hole for language design.
|
| I thought about this very, very carefully when designing
| Virgil[1]'s numerical tower, which has both fixed-size signed
| and unsigned integers, as well as floating point. Like other
| new language designs, Virgil doesn't have any implicit
| narrowing conversions (even between float and int). Also, any
| conversions between numbers include range/representability
| checks that will throw if out-of-range or rounding occurs. If
| you want to reinterpret _the bits_ , then there's an operator
| to _view_ the bits. But conversions that have to do with
| "numbers" then all make sense in that numbers then exist on a
| single number line and have different representations in
| different types. Conversion between always preserve numbers and
| where they lie on the number line, whereas "view" is a bit-
| level operation, which generally compiles to a no-op.
| Unfortunately, the implications of this for floating point is
| that -0 is not actually an integer, so you can't cast it to an
| int. You must round it. But that's fine, because you always
| want to round floats to int, never cast them.
|
| [1] https://github.com/titzer/virgil
| baby wrote:
| I wish clippy had a lint against downcasts specifically. I aso
| like that rust has no "int" type
| phkahler wrote:
| This wouldn't be a problem if "int" was defined as the same
| size as size_t. The solution is probably to change all those
| functions to take a parameter of size_t instead of int.
|
| IMHO one should always be using C99 types instead of int, but
| Linux predates that.
|
| Also, shouldn't that implicit conversion cause a compiler
| warning?
| chippiewill wrote:
| > IMHO one should always be using C99 types instead of int,
| but Linux predates that.
|
| "Always" is a strong way of putting it, there are often times
| where it makes sense to use the platform's "natural" word
| sizes (which is the entire point of having `int` `long` `long
| long` etc.)
| phkahler wrote:
| >> there are often times where it makes sense to use the
| platform's "natural" word sizes
|
| In those cases we probably don't care about the full range
| of the larger types, so it doesn't hurt to use the smallest
| type for a range of expected values. If it does make a
| difference, the program will behave differently when
| compiled on a different arch or even a different compiler.
|
| But maybe "generally" instead of "always". OTOH even I am
| guilty of using an int to loop over an array.
| tialaramex wrote:
| Linux apparently provides a similarly named set of sized
| integer types to Rust, ie: s8 u8 s16 u16 s32 u32 s64 u64
|
| But of course getting C programmers to use these integer
| types rather than the ones they grew up with isn't easy.
| foobiekr wrote:
| I did a lot of C - a _lot_ - in the mid-90s through the mid
| /late 2000s and have never seen any sizable C code base
| where explicit sizes were not the norm throughout -
| u_int32_t etc. I think this is not the problem, it's the
| implicit conversions.
| cesarb wrote:
| > This wouldn't be a problem if "int" was defined as the same
| size as size_t.
|
| That would lead to a hole in the type sequence (char <= short
| <= int <= long <= long long) for 64-bit targets (where int is
| the 32-bit type while size_t is 64 bits).
|
| > IMHO one should always be using C99 types instead of int,
| but Linux predates that.
|
| On the other hand, on Linux "long" has always been defined as
| the same size as size_t, so using "long" instead of "int"
| everywhere could also be an option.
| kenniskrag wrote:
| so you mean int_fastX_t or int_leastX_t?
| pcwalton wrote:
| > This wouldn't be a problem if "int" was defined as the same
| size as size_t.
|
| ILP64 causes a lot of problems, most notably needlessly-
| increased memory usage and, in C, the inconvenience of
| requesting a 32-bit type when int is 64-bit. It's rather
| uncommon to actually need the extra 64-bit range _except_
| when describing pointer addresses and memory /disk sizes,
| both of which benefit from an explicit intptr_t/size_t type
| for readability if nothing else.
| saagarjha wrote:
| ILP64 also solves a lot of problems if you don't define
| overflow to be UB.
| marcosdumay wrote:
| I think Rust has no language construction for that, but the
| best implementation of "size as i32" should fail on overflow.
|
| In Haskell I would use an exception, and mark the function as
| unsafe, but the stdlib seems to disagree with me here.
| derefr wrote:
| > Some Rust developers argue that even "size as i32" should be
| avoided, and "size.try_into()" should be used instead, since it
| forces the programmer to treat an overflow explicitly at
| runtime, instead of silently wrapping.
|
| It's important to still have the option for efficient
| truncating semantics, though; some software (e.g. emulators)
| needs to chunk large integers into 2/4/8 smaller ones, and
| rotation + truncating assignment is usually the cheapest way to
| do that.
|
| But, importantly, this is a _rare_ case. _Most_ software that
| does demoting casts does not mean to achieve these semantics.
|
| So I wonder -- are there any low-level/systems languages where
| a demoting cast with a generated runtime check gets the
| simple/clean syntax-sugared semantics (to encourage/favor its
| use), while truncating demotion requires a clumsier syntax (to
| discourage its use)?
| chippiewill wrote:
| > are there any low-level/systems languages where a demoting
| cast with a generated runtime check gets the simple/clean
| syntax-sugared semantics (to encourage/favor its use), while
| truncating demotion requires a clumsier syntax (to discourage
| its use)?
|
| Not exactly the same thing, but in a related area C++ does
| this a bit.
|
| In C++ you can always still do a c-style cast `(int)
| some_var` (and the implicit casts obviously), but in general
| you're meant to use the C++ style explicit casts like
| `static_cast` and `const_cast`. These are generally tidy, but
| the most powerful and dangerous of these casts is
| deliberately awkwardly named as
| `reinterpret_cast<int>(some_var)` rather than something
| terse.
|
| It's always easy to spot during a code review.
| gumby wrote:
| You can have your compiler warm about c-style casts
| tialaramex wrote:
| Right, this is a small infelicity in Rust, it is easier to
| write let x = size as i32;
|
| ... even if what you meant was closer to let
| x: i32 = size.try_into().expect("We are 100% sure size is
| small enough to fit into x");
|
| But at least it isn't C or C++ where you might accidentally
| write x = size;
|
| ... and the compiler doesn't even warn you that size is
| bigger than x and you need to think about what you intended.
|
| It's really hard to fix this in C++. Some of the Epoch
| proponents want to do so using epochs to get there, basically
| you'd have a "new" epoch of C++ in which narrowing must be
| explicit, and old code would continue to have implicit
| narrowing so it doesn't break.
| dkirill wrote:
| > and the compiler doesn't even warn you that size is
| bigger than x
|
| That's not true tho, compiler with reasonable flags set
| will definitely warn you and if you _really_ don 't like
| this kind of code you can force compiler to issue an error
| instead
| tialaramex wrote:
| Fair point although it seems "reasonable" varies from one
| platform to another, it doesn't warn out of the box for
| me but people have reported MSVC gets warnings here.
| simias wrote:
| What flags you have in mind? Because this code doesn't
| generate any warning with GCC 11.1.0 with -Wall -Wextra:
| int main(void) { int some_int = 1234567;
| char c = some_int; return c; }
| ridiculous_fish wrote:
| -Wconversion will do it.
| stjohnswarts wrote:
| -Wconversion will catch this
| aaronmdjones wrote:
| -Wall -Wextra -Wpedantic does not enable all diagnostics.
|
| This is GNU's idea of "all".
|
| Contrast to Clang's -Weverything, which will.
| lazide wrote:
| It seems though that the point is made, right? Even
| 'good' approaches miss on what should be a clear 'whoa,
| are you sure?' type warning. There are a lot of footguns
| wandering around in C/C++ land.
| BoorishBears wrote:
| No, the point was you want don't get a warning and it
| will silently wrap. You can scroll up if you've
| forgotten.
|
| And it is false. My default configuration C++ project
| created in Clion shows it very clearly, and even pesters
| to use int32/int64 over int/long.
|
| But as usual the default fallback when you're wrong about
| C++ is "uh yeah but lotta footguns amirite"
|
| As if there aren't enough that we need to start making
| them up...
| gumby wrote:
| > This is GNU's idea of "all".
|
| Unfortunately, over the years people baked the semantics
| of -Wall into their builds so new diagnostics could not
| be added to that flag.
|
| And clang's -Weverything shows how the opposite can fail
| as well
| not2b wrote:
| There are some very wrong-headed warning options in gcc,
| such that turning them on and avoiding getting them will
| make your code worse. So -Wall means 'all recommended
| warnings'.
|
| Also there are some warnings that won't be produced if
| you compile without optimization, because the needed
| analysis isn't performed.
| rocqua wrote:
| The reason for this decision is so that compiler upgrades
| with -Wall and -Werror don't break builds.
|
| I can see the reason behind it, but I feel that this
| behavior is something you opt into when you use -Werror.
| derefr wrote:
| > The reason for this decision is so that compiler
| upgrades with -Wall and -Werror don't break builds.
|
| It feels like the "right thing" here would instead be for
| the compiler to allow build scripts to reference a
| specific point-in-time semantics for -Wall.
|
| For example, `-Wall=9.3.0` could be used to mean "all the
| error checks that GCC v9.3.0 knew how to run".
|
| Or better yet (for portability), a date, e.g.
| `-Wall=20210720` to mean "all the error checks built into
| the compiler as of builds up-to-and-including [date]."
|
| To implement this, compilers would just need to know what
| version/date each of their error checks was first
| introduced. Errors newer than the user's specifier, could
| then be filtered out of -Wall, before -Wall is applied.
|
| With such a flag, you could "lock" your CI buildscript to
| a specific snapshot of warnings, just like you "lock"
| dependencies to a specific set of resolved versions.
|
| And just like dependency locking, if you have some time
| on your hands one day, you could "unlock" the error-
| check-suite snapshot, resolve all the new error-checks
| introduced, and then re-lock to the new error-check-suite
| timestamp.
| antoinealb wrote:
| I think it might be more of an headache: what if somebody
| fixes a bug in an analyzer so that it catches things it
| used to miss ? Should it be a breaking change ?
|
| Personally i would vote for "Wall with Werror" means no
| guarantee for your build.
| wheybags wrote:
| The real solution: leave Werror off by default, activate
| it only during CI builds
| HanyouHottie wrote:
| MSVC has this[1]. .NET code analyzers are also
| versioned[2].
|
| [1]:https://docs.microsoft.com/en-us/cpp/error-
| messages/compiler... [2]:https://docs.microsoft.com/en-
| us/dotnet/fundamentals/code-an...
| 130e13a wrote:
| keep in mind though that -Weverything is not intended to
| be used in production:
| https://quuxplusone.github.io/blog/2018/12/06/dont-use-
| wever...
| kllrnohj wrote:
| Clang-tidy has a check for it:
| https://clang.llvm.org/extra/clang-
| tidy/checks/cppcoreguidel...
| rualca wrote:
| >What flags you have in mind?
|
| -Wconversion
|
| https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
|
| This is common knowledge for ages. Any cursory Google
| search returns countless answers.
|
| Take this post made over a decade ago.
|
| https://stackoverflow.com/questions/1730255/gcc-shouldnt-
| a-w...
| nly wrote:
| Narrowing within { } initialization is forbidden C++ now
| [deleted]
| glaze wrote:
| If you initialize it like this you get a warning:
|
| x = { size };
| jacoblambda wrote:
| It can impact compile time performance but Boost Safe
| Numerics provides some nice wrappers to prevent narrowing
| (or restrict it to specific classes of narrowing) and throw
| warnings or errors at compile time similar to what you see
| in Rust.
| frogblast wrote:
| In swift: // a is a UInt64 let a =
| Int.random(in: 0..<Int.max) // causes a
| fatal runtime error if out of range, halts execution
| let b = UInt32(a) // returns a UInt32?,
| which will be nil if out of range let c =
| UInt32(exactly: a) // another approach for
| exact conversion: guard let d = UInt32(exactly: a)
| else { // conversion failed //
| handle error and return return }
| // 'd' is a UInt32 without any bits lost //
| always succeeds, will return a UInt32, either clamped or
| truncated. Truncation just cuts off the high bits.
| let e = UInt32(clamping: a) let f =
| UInt32(truncatingIfNeeded: a)
| londons_explore wrote:
| It would be nice if CPU's had an instruction for "read the
| low 8 bits of this register, and require the high bits all be
| zeros (otherwise throw an exception)".
|
| Then safety is free...
| derefr wrote:
| What does "otherwise throw an exception" mean at the CPU
| level?
|
| I know Erlang's BEAM VM has a "fail jump pointer register",
| where instructions that can fail have relative-jump offsets
| encoded as immediates for those instructions, and if the
| instruction "fails" in whatever semantic sense, it takes
| the jump.
|
| But most CPUs don't have anything like that.
|
| Would you want it to trap, like with integer division by
| zero?
|
| CPU traps are pretty hard to handle in most language
| runtimes, such that most compilers generate runtime checks
| to work around them, rather than attempting to handle them.
| [deleted]
| simias wrote:
| I assume they meant throwing an exception like divisions
| by zero usually do, i.e. a hardware trap.
|
| I always thought that overflows should be checked in
| hardware, I suppose it's not a stretch to extend that to
| truncation. It's controversial though, and obviously
| mostly a thought experiment anyway unless we manage to
| convince some CPU manufacturer to extend their ISA that
| way.
|
| MIPS does have (optional) trapping overflow on signed
| add/sub overflow, so at least there's a small precedent
| for it.
| ridiculous_fish wrote:
| Swift checks all arithmetic by default:
| https://swift.godbolt.org/z/rW614G5aq
|
| It seems obvious that future Apple CPUs will have
| hardware support for this, if they don't already.
| saagarjha wrote:
| I don't see this happening unless it makes it into the
| ARM ISA.
| hermitdev wrote:
| I'm not familiar with ARM ISA, but from the godbolt
| disassembly, it doesn't look like anything special going
| on here - just the ASM being generated. What's happening
| here is it just does the add, jumps on overflow flag set
| to an invalid opcode...
| saagarjha wrote:
| The suggestion was a custom instruction or architectural
| extension to have this happen in hardware, rather than
| needing to write out extra code for this.
| gumby wrote:
| I don't know the terms of Apple's license with ARM, do
| you? I'm quite interested.
|
| Given that Apple was one of the original founders of ARM
| it's quite possible that their license allows much more
| latitude anyone else's.
| saagarjha wrote:
| Adding new instructions to userspace programs is almost
| certainly not going to fly. All of their extensions have
| been hidden behind an opaque API, or limited to use in
| the kernel.
| titzer wrote:
| In Virgil, casts are written "type.!(expr)". Casts between
| numbers check ranges and roundability (for float<->int
| conversion). Reinterpreting the bits is written
| "type.view(expr)" and ignores signs, looks at the raw float
| bits, etc.
|
| edit: a cast will throw an exception if it fails, in case
| that was not clear from context.
| dathinab wrote:
| As a interesting side note:
|
| The "as" operator is often considered to have been a mistake.
| Both because of unchecked casts and because of "doing to
| much".
|
| So I wouldn't be surprised if in the (very) long term there
| will be a rust edition deprecating `as` casts (after we have
| alternatives to all cast done with `as`, which are: Pointer
| casts, dyn casts/explicit coercion and truncating integer
| casts, for some we already have alternatives for on stable
| for other not).
|
| And for all who want to not have `as` today you can combine
| extension traits (which internally still use `as`) + clippy
| lint against any usage of `as`.
|
| EDIT: I forgot widening integer casts in the list above ;-).
| eloff wrote:
| I would prefer not to see that happen, I'm fine with as and
| the safer options as they are currently. It would be a big
| job to update all the code in the wild when you want to
| move to the newer edition.
| cdirkx wrote:
| Isn't this something that could be done automatically by
| rustfix?
| wizzwizz4 wrote:
| You don't need to do that. Rust editions are fully
| backwards-compatible, since they can depend on code from
| different editions.
| eloff wrote:
| I'm aware of that, which is why I specified when you want
| to move to the newer edition.
| tialaramex wrote:
| I don't see it as a big job. Am I wrong?
|
| Imagine there's a suitable narrow::<type>() function
| introduced which has the same consequence, always
| narrowing, if your data was too wide it may drop
| important stuff on the floor, and narrow() just says
| that's too bad.
|
| Rust 2030 can introduce narrow::<type>(), warn for
| narrowing as usage and then Rust 2035 can error for as.
| The Rust 2030 -> 2035 conversion software can consume
| code that does { x as y } and write { x.narrow::<y>() }
| instead. This code is not _better_ but it 's still
| working in Rust 2035 and this explicit narrow() function
| is less tempting for new programmers than as IMO.
| scns wrote:
| Yes, BUT the correct thing to do would be more tedious to
| write that way.
| mnw21cam wrote:
| Add Java to that list.
| csharptwdec19 wrote:
| Same for C#. Any narrowing truncation needs to be an explicit
| cast. Widening is typically allowed implicitly, although in
| the case of the 'decimal' (128 bit struct representing a
| 'higher precision' floating point) type you still need an
| explicit cast from a 'double', since there are cases where
| that conversion can still change the value or fail (i.e.
| Infinity/NaN)
| pjmlp wrote:
| Microsoft is considering turning on by default checked
| arithmetic in the 2022 Visual Studio templates, by the way.
| paulddraper wrote:
| Noo! This idea is super new and was invented by Go/Rust.
| irogers wrote:
| It can catch people by surprise that Java's narrowing
| conversions may not preserve the sign. For example, the
| following is broken:
|
| class TimestampedObject implements
| Comparable<TimestampedObject> { long timestamp; int
| compareTo(TimestampedObject other) { return (int)(timestamp -
| other.timestamp); } ... }
|
| ErrorProne catches this:
| https://errorprone.info/bugpattern/BadComparable
| nly wrote:
| Long and int are the same size on Windows. The fact that these
| sizes aren't well defined is the cause of the issue.
| mgraczyk wrote:
| That's cool! And some languages like Go don't even allow
| implicit widening conversions:
| https://play.golang.org/p/a5C5jsHypmu
| est31 wrote:
| Rust doesn't allow them either: https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
|
| Adding .into() works though, which is the recommended method
| if the conversion can be statically guaranteed (otherwise
| try_into should be used, which will become easier in the 2021
| edition as the TryInto trait will become part of the
| prelude).
| ridiculous_fish wrote:
| into() does _not_ work from size. It 's rather frustrating
| in practice.
| https://stackoverflow.com/questions/62832438/why-is-rusts-
| us...
| masklinn wrote:
| > It's rather frustrating in practice.
|
| All explicit conversions, more so fallible, are
| "frustrating in practice" especially when coming from a
| language without those foibles.
|
| But given the semantics of usize/isize, it is perfectly
| reasonable, nay, a good thing, that they're considered
| neither widenings nor narrowings of other numeric types.
| ridiculous_fish wrote:
| usize should be Into<u64> iff usize is <= 64 bit.
|
| usize is already on that hook: `0x100000000usize` will
| fail to compile in 32 bit, so you already risk compile
| errors when switching archs.
|
| As it is I'm just writing `as u64` which is clearly
| worse.
| eloff wrote:
| Yeah, that is frustrating since there are no platforms
| where that would fail today, and it's hard to imagine why
| we would ever want one with 256bit pointers.
|
| We don't even use full 64bit pointers today on x64.
| pornel wrote:
| Even worse, there are platforms with >=128-bit pointers
| but 64-bit address space. Rust has chosen usize to be
| uintptr_t rather than size_t, even though it mostly uses
| it as if it was size_t. A ton of code is going to subtly
| break when these two sizes ever differ. Rust is likely
| already doomed on >64-bit platforms, and is going to be
| forced to invent its own version of a LLP64 workaround.
| fulafel wrote:
| Maybe a fat pointer llvm target ala SoftBound running on
| a machine with 128 bit bare pointers, like as/400.
| est31 wrote:
| When 16 bit computers went to 32 bit, people probably
| thought that one wouldn't ever need 64 bit computers
| either. That being said, by the time 128 bit run out we
| have probably boiled earths oceans :).
|
| You could think of checked memory models where half of
| the 256 bit address is a 128 bit random key needed to
| access some allocation, or maybe even a decryption key.
| Similar things are done with the extra space of x64 as
| well.
|
| Also, 128 bit numbers are still quite uncommon in Rust.
| Easy conversion of usize to them wouldn't be that useful
| if conversions of the other number types don't work.
| mgraczyk wrote:
| The Ethereum virtual machine addresses it's storage with
| 256 bits, so there's one wild example. Although in this
| case you'd probably not want to use usize directly to
| represent storage.
| eloff wrote:
| I'm not familiar with the Ethereum virtual machine, are
| these really memory pointers? Surely it's represented
| differently?
| mgraczyk wrote:
| EVM is a stack machine, and it has durable storage which
| is addressed using 256 bit "pointers". So you can do
| something like push x // 256 bit
| constant LOAD // top of stack now
| contains storage[x]
| ronsor wrote:
| Shout out to Zig, which requires explicit casting also.
| WalterBright wrote:
| D doesn't allow implicit narrowing conversions. The user has to
| have an explicit cast, like `cast(int) size`. Cast is made into
| a keyword so all those explicit conversions can be found with a
| simple grep.
|
| We consider it best practice to try and organize the types such
| that explicit casts are minimized.
| cjensen wrote:
| C/C++ compilers commonly have warnings for narrowing
| conversions, and separate warnings for mixing signed/unsigned
| conversions for same-sized values.
|
| While some folks aren't too fussed about warnings like this,
| those folks generally aren't writing secure code like kernels.
| I'm very surprised that kind of conversion was permitted in the
| code.
| mnw21cam wrote:
| I love the little nugget in the mitigations section. You can plug
| the hole for a normal filesystem, but then FUSE filesystems have
| an additional problem: "if an attacker FUSE-mounts a long
| directory (longer than 8MB), then systemd exhausts its stack,
| crashes, and therefore crashes the entire operating system (a
| kernel panic)."
|
| If there's one place other than the kernel where truly defensive
| programming should be applied, it is systemd.
| josefx wrote:
| What the hell is systemd doing that a 8MB long file path can
| exhaust its stack? Is it doing some recursive parsing or is it
| just doing something plain stupid like using a VLA to store
| user provided data?
| megous wrote:
| Probably unbounded alloca() as always.
| merb wrote:
| was that a guess? wtf... btw. it would probably be hard to
| make the same mistake in rust. unless you write your own
| code for strings or use strdupa, too via libc.
|
| I also do never understand why some libraries use "faster"
| methods everywhere, unless safer ones. it's not like all
| interfaces to systemd would need to be fast. but they
| should be secure.
| megous wrote:
| Yes. It happened before, so it was not exactly hard to
| guess.
|
| https://capsule8.com/blog/exploiting-systemd-journald-
| part-1...
| megous wrote:
| Yep: https://github.com/systemd/systemd/commit/b34a4f0e6729
| de292c...
|
| strdupa(input) without any length check
|
| Fix is to replace it with unbounded malloc() instead of
| checking for sane length first.
| stjohnswarts wrote:
| Good find thanks for sharing. And everyone at work gripes
| about me carrying the size around with a lot of my
| variables in the form of a struct. It's strictly a
| reminder to always be checking the size since I'm
| juggling with shotguns.
| unmole wrote:
| Wait how does a user space daemon exhausting its stack lead to
| a kernel panic?
| paulddraper wrote:
| Because it's PID 1.
| mjevans wrote:
| Poorly designed security architecture and division of labor.
| A more idealized init / systemd would have all of the
| execution flow of PID 1 mathematically provably correct, and
| correspondingly have as small a footprint as possible there.
| All additional functions would run under one or more child
| processes (where the bulk of systemd would execute).
| monocasa wrote:
| PID 1 is special in Unix systems. As the parent of all other
| processes (and child to none) it's not clear to the kernel
| what should happen when it exits.
| comex wrote:
| Because the kernel intentionally panics [1] if the init
| process would otherwise exit in any way - whether because it
| called exit(), it was killed, or, in this case, it crashed.
|
| This is likely because Unix semantics treat the init process
| specially: any process whose parent dies is re-parented to
| the init process. It's not clear what should happen to these
| processes if the init process itself went away, so the kernel
| just gives up.
|
| [1] https://elixir.bootlin.com/linux/latest/source/kernel/exi
| t.c...
| Denvercoder9 wrote:
| I wonder if just restarting PID1 could be viable
| alternative?
| jerf wrote:
| It's generally dangerous to restart PID1 in an enviroment
| where, by definition, something happened to PID1 that it
| wasn't expecting. The state of the system is now
| unreliable, and it's exactly the sort of unreliable in
| exactly the right place that tends to lead to whopping
| security issues. Far too easy to end up with "Crash PID1
| with 'blah blah blah', then when it restarts it ends up
| doing bad things X & Y".
| cameronh90 wrote:
| Perhaps a distinction here can be made between running as
| a server OS and a desktop OS.
|
| In a server I generally want a crash immediately. But on
| a desktop I'd rather it limp along and give me a chance
| to finish writing my Hackernews post.
| londons_explore wrote:
| On a server I'd usually want it to limp along too...
| Better fire an alert but keep happy customers than cause
| a massive outage just because of someone's overly strict
| checkfail...
|
| It depends really what your server does, and what the
| consequences of it doing the wrong thing are.
| CrazyPyroLinux wrote:
| systemd? More like systemK! But seriously, are non-systemd
| systems not vulnerable to the FUSE portion of this?
| (CVE-2021-33910)
| saurik wrote:
| FWIW, I feel like your comment is responding to an implicit
| critique of systemd, but even if one was warranted I didn't
| read that comment as implying such (as the premise would just
| be that systemd is a key place in the stack where you would
| need to be super careful, not that it is somehow less careful
| than other projects... even if I might claim as such for at
| least logging ;P); it could be that I am misinterpreting your
| comment, though?
| Faaak wrote:
| Anyone knows how to try the PoC
| (https://www.openwall.com/lists/oss-security/2021/07/20/1/1) ?
|
| For me it crashes into the fork_userns:177
|
| PS: don't need to downvote. Sometimes managers want you to prove
| that there's a need to patch. It's dumb but it's what it is
| ploxiln wrote:
| Your linux distro may already have unprivileged user namespaces
| disabled. See the "mitigations" section of the post, and check
| /proc/sys/kernel/unprivileged_userns_clone
| airocker wrote:
| Can we not have one integer type in c that can grow like in js as
| required and become bigint if too big?
| wyldfire wrote:
| Yes, arbitrary precision integers could theoretically become a
| C language/library feature. But let's say that it gets proposed
| and accepted and it's integrated into popular compiler
| toolchains. The kernel wouldn't leverage it here or likely
| anywhere else because of its cost.
|
| A newly designed OS kernel could perhaps take on this kind of
| feature. This would be the kind of OS that could be formally
| verified and would be willing to pay that runtime cost for
| arbitrary precision.
| airocker wrote:
| Perhaps such type of things have been put in Kernel before.
| kaba0 wrote:
| C doesn't have the abstraction power to make anything with
| such a datatype.
| dbrgn wrote:
| Haha, yeah JS integers "can grow". Kind of. And then they bite
| you in the worst way possible. Especially when combined with
| cryptography (e.g. nonces).
|
| Try this: >> const x = 288230376151711740;
| >> x == x + 1 true
|
| Or this: >> 2\*1024 Infinity
|
| JS doesn't even have integers. It only has floats. JS is by far
| the worst language I know of when it comes to integer support.
|
| If you want a better example of arbitrary precision integers,
| try Python, for example.
| _moof wrote:
| I was working at Twitter when we learned this the hard way.
| We switched to a separate service for generating tweet IDs
| (instead of MySQL sequences), which for various distributed
| systems reasons meant IDs started taking up more bits. And
| when we stuck those bigger IDs into JSON responses in the
| API... well, we learned the dumbest lesson possible about the
| intersection between JSON, JavaScript, and double-precision
| floating-point. Later that day the "id_str" fields were born.
| dbrgn wrote:
| Yep, I can totally relate. I found multiple bugs in a
| MessagePack JS implementation that were related to this
| issue.
|
| I also worked on a project once where unique IDs of objects
| could get quite large (because they were random u64
| integers). Those IDs were serialized and sent to a browser.
| Sometimes two objects were viewed as "the same" in the
| browser application because their IDs were truncated by the
| floating point precision issue.
| johndough wrote:
| Neat trick. Math.pow(2, 53) == Math.pow(2,
| 53) + 1
|
| This is a bit clearer I think. The addition just barely
| overflows the 53 mantissa bits of the IEEE 754 double
| precision floating point number.
|
| By the way, JS has BigInts these days, which are supported by
| all major browsers: https://caniuse.com/bigint
| >> const x = 288230376151711740n; >> x == x + 1n
| false
| mirekrusin wrote:
| 2**53 == 2**53+1
|
| ^^ even more clear.
|
| That's why _Number.isSafeInteger(a)_ exists.
|
| Integers up to +/- 9007199254740991 (
| _Number.MAX_SAFE_INTEGER_ ) are fine.
| thayne wrote:
| GP may have been referring to BigInt.
|
| Although, C does have an equivalent to that: the GNU MP
| library (and probably others as well).
| airocker wrote:
| I was referring to bigint not js bigint, checking for
| overflows if optimized could be just 1 instruction.
| vbezhenar wrote:
| We can. But it would be very inefficient. There's no point to
| use C at all, if you can accept that level of performance.
| jerf wrote:
| We don't need arbitrary-sized integers; we need exceptions on
| overflow (or underflow, but I'll stick to overflow for the rest
| of this post) to be the default, or similar language features
| as appropriate.
|
| I for one am tired of the chicken & egg issue of "CPUs don't
| support efficient overflow checking because nobody uses it, so
| it's slow" and "Overflow checking is slow because the CPU
| doesn't support it, so nobody uses it". For all the other good
| security work done in both software and hardware, much for
| things far more complex than this, this seems like an
| absolutely batshit insane oversight considering the
| cost/benefits for fixing this.
| airocker wrote:
| CPU would raise a signal just as null pointer exception? And
| it seems a lot of code (for eg, safeintadd metioned below)
| assumes no exception. Would not all that code get messed up?
|
| Would it be possible to just silently replace with arbitrary
| sized integer and not break any code like safeintadd?
| dahfizz wrote:
| CPUs don't raise exceptions, that is a software concept.
| CPUs do have traps, like for division by zero, but those
| are not exceptions in the way you think.
|
| Null pointers are also handled by the kernel, not the CPU.
| Its called a segmentation fault because you are trying to
| access a memory segment that the OS doesn't want you to.
| airocker wrote:
| I dont think kernel handles NPEs:
| https://stackoverflow.com/questions/63091446/what-
| happens-at...
| jerf wrote:
| In C, you can't "just" replace with arbitrary-sized
| integers. They are fundamentally different memory shapes.
|
| You may not be able to turn enforcement on for all code
| immediately. There's even the rare bits of code that depend
| on current overflow behavior. (Due to our human brains and
| the fact that we can easily name these bits of code, making
| the cognitively available, people often grotesquely
| overestimate the amount of code that operates this way. I'm
| sure it's only a matter of how _many_ zeros belong in the
| 0.001%.) But we need this support to be available for code
| to be turn on easily and cheaply.
|
| But what really boggles my mind, again given all the
| security work we've done, is that the reaction to this
| remains a combination of silence and "we can't do that!",
| when it seems to me the reaction ought to be "well _duh_
| jerf we all know that already. " I don't get this. I don't
| get this attitude at all. This is a _huge_ source of
| errors, a good fraction of which are security bugs, and
| nobody seems to care. Incomprehensible. This is, arguably,
| the _number one_ thing that could be getting changed right
| now to fix security issues, and I just get slack-jawed
| "whaaaa?" in response to the idea.
|
| One hundred plus one hundred is not negative fifty six!
| Here we are trying to hold together megabytes upon
| megabytes of security-critical code in a world where 100 +
| 100 = -56. Is it any wonder that writing any sort of code
| to maintain security invariants is tough in an environment
| where 100 + 100 = -56?
| airocker wrote:
| I feel like carefully planned with compiler level
| errors(not warnings), and some glibc non-backward
| compatible changes. we can achieve this in software
| layer.
| gruez wrote:
| >that can grow like in js
|
| I thought js "integers" are just floating point numbers?
| OnlyLys wrote:
| I believe the poster you were replying to was talking about
| JS's new `BigInt` type.
|
| https://developer.mozilla.org/en-
| US/docs/Web/JavaScript/Refe...
| vbezhenar wrote:
| Good example of that feature is Python. Also, AFAIR, Scheme
| (and probably some other lisps) support it.
| wyager wrote:
| No, because that would require implicit dynamic allocation,
| which would defeat the entire point of using C.
| airocker wrote:
| Only when limits are getting breached, otherwise it is one if
| statement extra on every access. This happens in Java and
| other languages.
| wyager wrote:
| It doesn't matter if it only happens occasionally. It's
| completely inappropriate for C, which has no implicit
| memory allocation. There's not even a clear way to include
| implicit allocation in the semantics of C.
| infamouscow wrote:
| We can do this in software because there's virtually no limit
| to the abstractions people make, but hardware doesn't work like
| that. At some point in the software stack we need to draw a
| line and say this is a 64-bit signed integer that hardware can
| understand.
| airocker wrote:
| But should it be everywhere including the fs/virtual fs
| layer? Could we limit it only to device drivers? Not a kernel
| expert here and would love to hear thoughts.
| dahfizz wrote:
| This doesn't have anything to do with filesystems or
| kernels.
|
| The x86 assembly uses fixed width immediates. CPU registers
| are a fixed width. For any code to compile and run, it
| needs to make decisions about how large stack frames need
| to be, and how much heap memory to allocate.
|
| This was the parent's point about abstractions. You can
| make a library that pretends to be a variable sized
| integer, but to implement such a library you need to make a
| decision about how much space to allocate and the width of
| variables in order to compile. There is no getting away
| from how the hardware works.
| Zababa wrote:
| > Unfortunately, this size_t is also passed to functions whose
| size argument is an int (a signed 32-bit integer), not a size_t.
|
| Is this the type of things that could be caught by a linter or
| strict compilation rules? This seems to be to be a failure of the
| type system.
| gruez wrote:
| AFAIK most compilers by default will output a warning in this
| case.
| usefulcat wrote:
| GCC's -Wconversion has some issues. For example, good luck
| getting gcc to /not/ emit a warning for this code, in C or
| C++. I have yet to find the appropriate cast to avoid a
| warning. Clang does not warn for this.
| typedef struct { unsigned value : 4; } S;
| void foo(S* s, unsigned value) { // error:
| conversion from 'unsigned int' to 'unsigned char:4' may
| change value s->value = value; }
|
| I mean, I guess I can see the rationale.. it's just annoying
| to have to resort to using pragmas to turn off -Wconversion
| whenever I need to assign to a bitfield.
| Denvercoder9 wrote:
| Does it still warn if you do `s->value = value & 0x0F`?
| That seems like a reasonable alternative to pragmas if it
| works.
| im3w1l wrote:
| Too bad that most projects are so full of integer size and
| signedness warnings that people get warning fatigue and just
| completely ignore them.
| loeg wrote:
| GCC and Clang (the predominant Linux and Mac compilers)
| mostly don't warn by _default_ , you need -Wall or other
| flags (-Wextra, -Weverything, or specific flags like
| -Wconversion).
| jeffbee wrote:
| I don't see any warnings for this narrowing parameter
| conversion. #include "stddef.h"
| short foo(short a) { return a % 42; } size_t
| bar(void) { size_t sz = ~0UL; return
| foo(sz); }
|
| https://godbolt.org/z/3ec9v8Pa4
| xeeeeeeeeeeenu wrote:
| It warns if you add -Wconversion. Unfortunately, that flag
| generates lots of false positives (at least in gcc), so
| using it isn't always a good idea.
| jeffbee wrote:
| It isn't ever a good idea. C programmers are just
| supposed to know about the conversion and promotion
| rules, every time they add a line, even though the rules
| are actually insanely complicated. Compiler warnings
| can't overcome this because programmers have no way of
| just discovering one of GCC's 726 warning flags, only a
| few of which are enabled by -Wall and -Wextra, most of
| which are way too noisy to serve a useful purpose.
| ototot wrote:
| In my own small projects, I always add -Wconversion to
| build configuration. I think the false positive is
| affordable when you start from small piece of code.
| morio wrote:
| What kind of false positives are you seeing with gcc?
|
| Personally I have never seen gcc spitting out a false
| positive. IMO it's always a good idea to explicitly
| downcast even if you know that it's 'safe'. That way
| someone else will see instantly what's going on. The fact
| that Rust requires it should tell us something.
| xeeeeeeeeeeenu wrote:
| For example, I've just reported this:
| https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101537
|
| You can find more cases in the bugtracker. To be fair, it
| seems many of them were fixed in recent releases.
| saurik wrote:
| Yeah; AFAIK you need something like clang-tidy's
| cppcoreguidelines-narrowing-conversions check (which
| everyone should definitely be using). (edit: But I'm wrong!
| That check is apparently similar to the -Wconversion
| mentioned by someone else.)
| gruez wrote:
| On MSVC, default project settings I get:
| warning C4267: 'argument': conversion from 'size_t' to
| 'short', possible loss of data
|
| https://godbolt.org/z/nYeWT7zv6 (/W3 is the default warning
| level when creating a new project)
|
| I saw these warnings so often that I assumed that _every_
| compiler had them.
| nly wrote:
| They can't warn by default, because on some platforms
| long->int isnt a narrowing conversion.
| aaronmdjones wrote:
| The compiler knows what platform it's compiling the code
| for, though.
| ainar-g wrote:
| At this point, you can--and probably should--consider C and
| "C-with-analysers" two different languages. If you use static
| (and dynamic, if you have tests) code analysis, making software
| without these issues is way easier, and doing so without these
| tools is essentially impossible. Both because of the C language
| itself as well as because of the culture of "bytes go brrr" and
| "just use a debugger" that a lot of middle-level C programmers
| have in my experience.
| kllrnohj wrote:
| Yes, it is the type of thing caught by a linter or strict
| compilation rules.
|
| https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidel...
|
| But strict compilation rules (eg, clang's -Weverything) mainly
| only work if you treat them as errors (so -Werror), and then
| some of those strict are then also questionable at best, and
| just outright annoyingly wrong at worst. For example, unused
| parameter warnings on virtual methods are a waste of time to
| deal with. It's not a symptom of a bug most of the time, so it
| being an error just generates workaround churn or you end up
| just disabling the warning and then maybe that bites you the
| few times it would have pointed out an actual issue.
|
| Beyond the blanket ones like clang's -Weverything, it can
| otherwise be a job to keep up with compiler upgrades and the
| _vast_ number of warning options they have.
| habibur wrote:
| > deep directory structure whose total path length exceeds 1GB
| [...]
|
| Oh, I didn't know Linux supports GB long path name. On Windows
| it's limited to something like MAX_PATH_LENGTH which was defined
| as 200+ chars when I worked on it.
| Already__Taken wrote:
| Windows lifted that limit a few years ago
| paavohtl wrote:
| AFAIK the limit has been lifted since Windows NT (so since
| the 90s), but only if you use the obscure NT path prefix
| (\\\?\\).
| divingdragon wrote:
| IIRC you still need to use a special flag to enable it,
| right?
| dragonwriter wrote:
| > Windows lifted that limit a few years ago
|
| IIRC, its a mess because it was lifted inconsistently for
| different access methods (APIs, and as a consequence UI/CLI
| methods that depend on them), and at least for some in ways
| which also are or were dependent on how paths are expressed.
|
| So it is, or at least has historically been after it was
| first "lifted", a minefield of inconsistent, surprising
| behaviors with plenty of gotchas if you didn't treat it as if
| it were still a limit.
| formerly_proven wrote:
| Windows goes to 260 chars, but the underlying system supports
| something like 64K, which means you can have files on Windows
| which are largely untouchable by built-in tools (Windows
| Explorer, file dialogs etc.)
| tinus_hn wrote:
| Why does the compiler not warn if you use a 64 bit unsigned
| integer when a 32 bit signed integer is required?
| snvzz wrote:
| $ ls -l /boot/vmlinuz-linux -rw-r--r-- 1 root root 9464864 Jul 16
| 12:59 /boot/vmlinuz-linux
|
| That's over 9MB, running in supervisor mode.
|
| 2021, and people are still surprised every time a kernel bug with
| security implications is found.
|
| Maybe it is time to look at different OS designs. Large companies
| such as Google (Fuchsia) or Huawei (HarmonyOS) have begun to pick
| up on this.
| melbourne_mat wrote:
| I wonder if we're going to see some more of Torvald's excellent
| management technique?
|
| >PATCH 3.12 108/142] fs/seq_file: fallback to vmalloc allocation
|
| >Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
|
| Oh maybe not this time :-)
| veltas wrote:
| B doesn't have these issues because it only has one integer size,
| take that C.
| spijdar wrote:
| Well, for that matter the original C on PDP-11 wouldn't have
| either, it also only had one integer size. We should all just
| blame ISO C ;-)
| drummer wrote:
| C++ engineers check out: Cppcon 2018: Safe numerics by Robert
| Ramey https://m.youtube.com/watch?v=93Cjg42bGEw
| kvathupo wrote:
| Cached mirror -
| https://webcache.googleusercontent.com/search?q=cache:LwH96X...
|
| I'm clueless about security: where does this fall on the scale of
| non-issue to critical? It strikes me as tending towards the
| latter, given that it enables unprivileged users to become root.
| Any insight into past Linux Kernel vulnerabilities that were
| severe?
| vbezhenar wrote:
| Local root escalation is very common vulnerability. It's almost
| pointless to expect that attacker will not be able to escalate
| his privileges given enough time, if he got user account
| access. One weak layer of defense at most.
| McGlockenshire wrote:
| Pulling this attack off requires enough access to the machine
| to either run the unprivileged commands needed to create the
| exploit condition or to upload a binary/script that runs
| unprivileged that in turn creates the exploit condition.
|
| If the attacker already has that level of unauthorized access,
| you're already doomed.
| tptacek wrote:
| Attacks like this break multitenant computing environments.
| It's not a threat to your desktop computer or your phone. But
| it can be a very big deal for hosting environments.
|
| It also breaks sandboxing. To whatever extent you're trying
| to run programs that are somehow jailed, so you can download
| and run them without worrying about them taking over your
| system, kernel LPEs break those assurances.
| verytrivial wrote:
| I honestly think all the automatic type promotion and conversion
| rules of the C family should be officially classified as "cute",
| namely an example of a childish simplification of a serious
| issue. I'm a C++ programmer of 20+ years experience and I have
| never, NEVER, caught myself thinking "gee, I'm glad I don't need
| to cast this." You ALWAYS think it, you just don't TYPE it, and
| that is the utterly wrong metric to optimise for. My 2c anyway.
| MauranKilom wrote:
| I've had my fair share of annoyance from situations like "I
| have between one and four hard-coded insertions into this
| vector, but the compiler yells at me if I try to store the
| resulting size in an int".
|
| Also, tangentially related is the signed/unsigned business
| which tends to get in the way frequently. For example, OpenMP
| 2.0 (the only OpenMP version you get to use with MSVC)
| _requires_ loop indices to be signed, but both
| std::vector::size and std::vector::operator[] deal with
| unsigned integers. Casts guaranteed!
| ryandrake wrote:
| I've always thought implicit parameter conversion in general
| (narrowing or otherwise) was fraught at worst, and code smell at
| best. If some function takes a size_t, why are you passing
| something other than a size_t to it? If your eventual call into
| "code you don't control" takes type X, make sure the value that
| you eventually pass is type X all the way through the code you do
| control. Even casting is kind of the lazy way out. I used to be
| pretty dogmatic about this and more than a few times got called a
| pedantic nitpicker (size_t is just like an int, bro! Don't worry
| about it--we got to ship in a week!). You can probably find
| serious bugs in any C or C++ software project simply by turning
| on the implicit cast warnings.
| _kst_ wrote:
| And it's not just parameter passing. It can apply to anything
| that acts like an assignment. That includes assignment (of
| course), parameter passing, and returning a value from a
| function.
| Deukhoofd wrote:
| I see in the mail that Red Hat sent out patches to resolve this.
| Are those patches already merged, or is this a CVE about a live
| exploit?
| GrayShade wrote:
| Still not fixed in the mainline kernel, it seems.
| megous wrote:
| It's fixed in 5.13.4.
| wolf550e wrote:
| This is the fix, it seems:
|
| https://git.kernel.org/pub/scm/linux/kernel/git/stable/linu
| x...
| userbinator wrote:
| _Our exploit requires approximately 5GB of memory and 1M inodes_
|
| ...so basically 32-bit systems are totally unaffected (and I
| believe size_t and int are the same size there anyway), but I
| think bugs like this are easily prevented by simply imposing sane
| limits --- there is zero reason to even consider allowing a path
| more than a few K in length, and IMHO even that is overly
| generous.
|
| While I know there's a lot of hate for Windows' traditional
| 260-char limit, I personally haven't run into it as a developer
| except by accident (e.g. runaway recursion) and it's very
| comforting to know that the limit is there so code will fail
| before it consumes the disk or memory entirely.
| saagarjha wrote:
| > I think bugs like this are easily prevented by simply
| imposing sane limits
|
| In general, no. Attackers are clever and can usually find their
| way around arbitrary limits when a bug exists. Sometimes such a
| restriction might stop them, but more often than not they'll
| bypass it some other way.
| mishac wrote:
| > I personally haven't run into it as a developer
|
| Clearly not a nodejs developer then! npm's insanely nested
| dependency graph caused me to hit the 260 character limit
| relatively regularly. (though this was several years ago, so
| maybe they have mitigations for that now)
| pfraze wrote:
| IIRC this is partly why node_modules moved to a flat
| structure
| MauranKilom wrote:
| We've had trouble (and had to occasionally shorten module names
| to something dumb like mdlWthVclsRmvd) because some part of
| some toolchain would create a path like C:/cu
| rrent/working/directory/that/is/reasonably/deep/testrun/YYYY_MM
| _DD_hh_mm_ss/code/moduleName/src/build/bin/../../../../../../ou
| tputs/moduleName/YYYY_MM_DD_hh_mm_ss/outputFolder/moduleName_te
| strun_results.txt
|
| or some garbage like that (you get the picture). Yes, half the
| path was taken by descending into some directory that it went
| out of again straight away. Test runs would fail because of the
| 260 char limit unless we cut down the module name length.
| (Thankfully this did not need to be done in the code itself,
| just in the test run invocation.)
| jeffbee wrote:
| A fun fact is there are 196 instances of `int buflen` in
| Torvalds' tree today, 95 instances of `int namelen`, and 13
| instances of `int pathlen`, also 3000+ `int size`.
| ddoubleU wrote:
| Afaik this should work on Android for some time now too right?
|
| Got unrootable old (but still fully working) phone there, might
| try to play with it.
| pitaj wrote:
| I'd love to see that. Please share if you end up doing so.
| spijdar wrote:
| ... do Android kernels normally build with and allow non-
| privileged users to make namespaces? I'd be really surprised.
| cannabis_sam wrote:
| I'm still amazed that we allow compilation of so obviously faulty
| programs.
|
| It's like you sent a 1kg package through the postal service, and
| then the recipient gets an envelope containing a piece of
| cardboard from the original packaging.. And everyone involved is
| somehow A-OK with all of this.
|
| If your programming language silently converts between types (in
| any direction), just to accommodate the programmer, instead of
| them specifying what they actually want to compute, you simply
| have failed as a programming language designer.
| andyjohnson0 wrote:
| > you simply have failed as a programming language designer
|
| That's some hubris. The C language is 49 years old. Dennis
| Ritchie made reasonable design decisions for the time he found
| himself in. I think we should be understanding of that, and the
| network effects that lead to large parts of the world's
| critical software infrastructure being implemented in C. I
| don't think he failed at anything.
|
| I used to be a C developer. I know how easy it is shoot your
| foot off in C. I think that, arguably, as an industry we should
| think twice before building more big and/or critical systems in
| C. There are better tools now.
|
| But we are where we are and it's important to understand how we
| got here. Castigating our predecessors as failures does them a
| disservice.
| kaba0 wrote:
| Though one should mention that most languages can evolve and
| overcome some of their problems, eg. see PHP which used to be
| objectively a shitty language and nowadays it is somewhat
| usable - C underwent basically no improvements in that
| ridiculous timeframe. So it is not against the original
| creator but everyone responsible for the language since then.
| cannabis_sam wrote:
| >The C language is 49 years old.
|
| That's my point, no shade on K&R though.
| cat199 wrote:
| meanwhile, lisp.
|
| age is orthogonal to good design.
| greesil wrote:
| https://org.cs.pub.ro/dragos.tarcatu/llvmlinux/commit/058504...
|
| m->size must be of type size_t. It's slightly mind-blowing to me
| that casting to a smaller unsigned int can cause a vulnerability.
| But I guess unintended behavior (not undefined) can do that.
| anyfoo wrote:
| It's very common. All that needs to happen, as just one
| example, is the variable of the smaller type being used as an
| index into an array. You might get an out of bounds access, or
| even just an access to the wrong element.
___________________________________________________________________
(page generated 2021-07-20 23:00 UTC)