Hacker Timesnew | past | comments | ask | show | jobs | submit | nickcw's commentslogin

That brings back fond memories of my first employer in the early 90s.

They used to rent a single scan line (VBI) of the TV broadcast to use as a data transmission method encoded the same way Teletext was. IIRC you could fit 45 bytes in a single scan line, with 50 per second that gives you a nationwide data broadcast capability of something like 18 kbit/s. We had a 19,200 bits/second leased line to send the data.

That scan line was really really expensive I seem to remember! If your TV wasn't quite adjusted properly you could see the data scan lines at the top of the screen as flickering white dots and lines which was fun.

The data got sent to financial institutions for real time stock feeds and nationwide networks of shops.

I never worked on the code for that part of the business though - I worked on the replacement system which ran via satellite with much more bandwidth at much lower cost.

Eventually the internet killed that too :-)


I love learning about pre-internet ways of transferring data on the back of other things. Another cool example is that the UK is only shutting down its longwave AM radio service this month (as opposed to decades ago) because the carrier is phase-modulated with data telling older electric meters to switch over. For years this was the only reason such an antiquated radio system stayed alive.

You should check out the Media Archeology Lab, they are very interested in alternate networks of all types! https://www.mediaarchaeologylab.com/

> I love learning about pre-internet ways of transferring data on the back of other things

See Minitel from France and Telidon from Canada as other examples of data systems riding on analogue TV and/or POTS telephone systems.


In Munich (Germany), a lot of the displays at bus and tram stations get their data via a side leg on the FM radio broadcast of local station B5 aktuell [1]. More details are here [2], apparently it's called "Axentia iBus FM/DARC".

[1] https://www.mikrocontroller.net/topic/232846

[2] https://apollo.open-resource.org/mission:log:2014:08:08:darc...


I love learning about pre-internet ways of transferring data on the back of other things.

I once worked for a radio station that made 90% of its revenue from carrying data feeds on subcarriers, and not from main music programs.

Because of the geographic location and size of the signal, it was a vital link between two major cities before planting fiber optic lines became cheap.


I’m looking forward to cell phones un-shackling themselves from telecom oligopolies through a mix of repurposed satellite uplink and where available: some FM spectrum downlink utilization.

Just stream me the weather, traffic, text msgs & some news stories that a TTS can read out to me.

Won’t work well for streaming a video but for most of us generally on wifi except out-of-doors, I can live with it.


Just stream me the weather, traffic, text msgs & some news stories that a TTS can read out to me.

SiriusXM is half way there. It supplies weather and traffic as a data service.

I knew about traffic from way back when the service was new, and found out Sirius Marine Weather a few years ago, but recently rented a car that also had Sirius-delivered weather and traffic alerts.

It was very useful as I was deeply off the grid (no radio stations at all during the day and AM skywave only at night), and the car alerted me to nearby lightning and thunderstorms that I couldn't see because of the terrain.


Up here in the north of Scotland the various council water and drainage departments often had to send data from remote data loggers (high tech stuff in the early 80s). Some of them would transmit a little ping of data every few seconds and if it heard a reply it would send several bursts of data quickly, using meteor scatter[1] to get it back to the receiving station hundreds of miles away.

All gone now, it's all 4G.

A few hours drive north of me is Mormond Hill, formerly the site of one part of the North Atlantic Radio System[2]. This used tropospheric scattering and huge dish aerials to communicate radar data down to RAF Fylingdales. There's not much up there now. There were various BT microwave links for offshore oil installations and assorted UHF and VHF links up, but the masts are pretty bare now.

[1] https://en.wikipedia.org/wiki/Meteor_burst_communications

[2] https://en.wikipedia.org/wiki/North_Atlantic_Radio_System


> If your TV wasn't quite adjusted properly you could see the data scan lines at the top of the screen as flickering white dots and lines which was fun.

There was a stock fault on BRC 1400 series valve TVs where a resistor in the brightness network would drift high in value and cause uncontrollable bright flyback lines in the upper half of the screen, and you could see those wriggly dotty crawlies ;-) I can't remember the component number - I think I last replaced one when I was 15 or 16, they were the teenage bedroom hand-me-down set of choice in the 80s, absolutely scads of them about in all sizes - but I can still picture in my mind's eye exactly where on the board it is, 220kΩ, red red yellow.

All long gone now, I expect.

If you find one do not re-cap it - the capacitors will be fine. They always are, there aren't any tantalums in it. Instead pay attention to everything above about 200kΩ and find out which ones are now closer to 1 meg!


They used to rent a single scan line (VBI) of the TV broadcast to use as a data transmission method

In the days before cable TV was widespread, there were over-the-air devices to give you a "TV Guide" page, like your cable/satellite service does now.

It was a tiny gray box about the size of a VHS tape, with a cute antenna sticking out of the top.

It constantly received program listing data through scan line data services, and filtered the listing by your ZIP Code. It displayed its TV Guide page on channel 3 or 4, and passed through the rest of the spectrum from your antenna. Because of this, it could even switch channels for you.

It cost something like $40, and after that was a totally free service, with no advertisements.

I'm pretty sure I got mine at Radio Shack, so it's probably listed in the catalogs around 1994 or so.


I found a similar vulnerability in the Zeus Web Server ( https://en.wikipedia.org/wiki/Zeus_Web_Server ) in January 2000.

Zeus had a great feature where you could set up virtual servers just by creating directories. So if you wanted to host www.example.com and www.anotherexample.com you just created two directories of those names like that and away you went.

I discovered that the if you sent `Host:` headers which started with `/` then you could use it to traverse the file system and read any file you wanted.

Plus ça change, plus c'est la même chose!


If you read the advisory and are wondering what starlette is, from it's web page: starlette is a lightweight ASGI framework/toolkit, which is ideal for building async web services in Python.

It's used a lot in the data heavy AI world for it's efficiency shipping large files. This includes lots and lots of production servers.

From the advisory: this includes LLM inference servers like vLLM, LLM proxy servers like LiteLLM, AI agent frameworks, MCP gateways, and custom APIs. MCP servers are especially at risk because the MCP spec mandates unauthenticated OAuth discovery endpoints, providing a reliable path for exploitation.


Notably, Starlette powers FastAPI, an extremely popular Python framework for building HTTP services.

Is this still true?

You may be thinking of Litestar (previously named Starlite) that was based on Starlette akin to FastAPI but then went their own direction implementing a framework rather than relying on an upstream for their core product.


..And?

FastAPI depends on "starlette>=0.46.0"

And? It's a non-sequitur to my comment.

Yes, it's literally the first bullet point on the project's website.

Ironically typing ‘make sure my server is secure’ into an LLM either wasn’t done, or missed it until now.

The posted page has an entire section titled "Why didn't Mythos find this?"

tl;dr: the bug spans three components in different code bases that when looked at in isolation each do reasonable things. The bug is in the interaction, in the assumed properties of the value that eventually gets exposed as request.url.path. That was apparently too subtle for current Anthropic models to spot


So an LLM was unable to reason about a codebase to find cross-library vulnerabilities.

Your response was a weak excuse, it’s a clear demonstration of the shortcomings of LLMs which will inevitably cause headlines in the future.


If you point an LLM at a middleware and ask it to find vulnerabilities, then not finding this is a shortcoming.

Whether "LLM failed to spot vulnerability that took humans 8 years to find" is a great headline about shortcomings of LLMs is questionable, but it is a good example of a category of bug that is particularly hard to spot for humans and LLMs alike


When the past month has been full of headlines claiming that Mythos et al. will be the end of secure software as well know it, it's fair game to emphasize the places we know already are not going to be covered by them.

The posted page said that finding logic bugs of this kind requires ‘understanding’ which LLM cannot.

Go doesn't have colored functions due to its nice fat runtime hiding all the async magic away for us.

That makes it a pleasure to code concurrent stuff for IMHO.

It does have its own similar problems though - does a function return an error? If so you are going to need to plumb the error return through all the callers. Does a function need a context.Context? Ditto.

I guess you can't win them all :-)


And Haskell is an ensemble of rainbows. It's very fun and pretty to look at.

Type classes can smooth over some of it but it's not unusual to have to do some plumbing.


Same with the BEAM languages like Erlang, Elixir, and Gleam. Though it still bothers me that they call their green threads "processes".

They are (lightweight) processes since they have no shared memory. Each process has its own stack and heap.

I've never thought about it that way, but that makes sense!

That's mostly because BEAM uses an actor-style approach while predating the concept of actors, isn't it? Interesting artefact of history if so

Edit: upon rechecking, apparently that's not exactly right, and Erlang designers learned of actors after designing the language, which makes it all the more interesting


I've spent the last decade in erlang / elixir / OTP. I think a lot of the naming comes from the early use of erlang as effectively an "OS" for telecom switches.

I always joke that BEAM wants to be the operating system.


> I've spent the last decade in erlang / elixir / OTP.

Do you have a blog? I would love a peek into your unique experience.


Actors predate both Erlang and BEAM by significant factor

The terminology in Erlang predates green threads by a decade or so.

This is a subtle point that I've seen missed repeatedly, but: The reason that "color" is important is that if you have a function ten layers down in your stack that is the wrong "color", you now have to change that top-level function. There is no other option.

Propagating errors up the stack is not the same, because the top-level function is not developing an error return because of the 10-level-nested function. It is developing one because the function it called has one, and apparently, it needs to return it to its local caller. It's a local consideration. It is true that it may be a recursive local consideration where this was true 10 times, but the reason it is different is that it doesn't have to be that way. It could have been the case that the function 7 layers down handled the error somehow and it stopped propagating up the stack. But at each point, the consideration was local, and as such, amenable to local solutions other than just tossing the error up. If you choose to "correctly" plumb the error through all your functions, well, good on you for apparently being willing to apply good software engineering practices even when it's annoying, but this is just normal day-to-day function activity stuff.

By contrast, in a function coloring situation, if the color is wrong 10 layers down, you must change the calling function. It's a non-local consideration. You don't get to decide not to change it. You can't encapsulate it. You don't get a choice. It pollutes the entire stack, forcibly.

Another way to look at it is, if the function 10 levels down developed what you think is a color, but there is a way for the function 9 levels down to hide the color from the rest of the stack, even via a hack like simply dropping an error you really need or hackily constructing an object of some type to pass in, then it is by definition not a color. A color change can't be stopped by any way of writing an intermediate function. It must be propagated all the way up the stack.

If you don't have this, you don't have "color". Like, some people will say that in their language that maybe there is some way to encapsulate "async". If you can, then you don't have an async color. Although I will say that if your "encapsulation" is basically to run it in a non-concurrent environment, that's really not encapsulation. It isn't really "encapsulation" if you're giving up an entire major feature of the language, because that is something very visible to the rest of the program.

Go's context.Context is similarly not a color. You can always just create a context.Background() and pass that down. If you didn't have any context already in hand, which means you must not care about any of the features context offers, then that is usually a fine thing to do. Context is trivially bypassed if you don't want it. It can be encapsulated within a portion of the stack without "polluting" the rest of the stack like any other function parameter.

The key aspect of color is that it is not optional. It isn't something that you can just decide to ignore and stop passing up, or trivially create a value for passing down to other functions. You have to change the "color". Async is a color in many environments. There aren't really that many colors in programming languages because they are very, very quickly inconvenient and we tend to squeeze them out. (Haskell really sticks out here as a language that is not only capable of creating arbitrary colors, but where this is an explicit tool used by the community rather than a limitation, and they even have ways of combining colors together deliberately.) Statement versus expression distinctions are another one, where a "statement" may not be usable in an "expression", and you'll note how languages have in general erased that one over time because it's really just a cost without much benefit.


That's just not true. Let's say you have a form validation library with a public api that supports custom validators Validate(name string, value string) bool. Then you decide that your validator now needs to make an HTTP request. This request needs context so that tracing is propagated and needs to return (bool, error) so that error is propagated up instead of silently ignoring it or logging it and returning false. This is coloring. You can use context.Background the same way you can use blocking in other languages. It just doesn't feel right and it breaks things.

If "caring about arguments" is "color" then the concept is useless and who cares? If everything is a "color", nothing is.

The color concept is interesting precisely because it isn't just "arguments to functions". The difference I describe is a real one that has real effects at scale. Trying to collapse it down to "it's just function arguments" doesn't make it go away, it just makes it so anyone who refuses to draw the distinction loses the ability to see it. It's not a good idea and it's not a good argument. You're just smearing vaseline on your eyes.


With (unchecked) exceptions the custom validator can abort the whole stack non locally and transport the error to the original call stack, the validation library being none the wiser.

With stackful coroutines, the custom validator can transport the error to the original call site, handle it and resume back into the validation library if the error was recovered, or abandon the validation (as with exceptions) if unrecoverable.

With HKTs, the validation library can be agnostic on the specific return type of the custom validator.


> Propagating errors up the stack is not the same, because the top-level function is not developing an error return because of the 10-level-nested function. It is developing one because the function it called has one, and apparently, it needs to return it to its local caller. It's a local consideration ...

> By contrast, in a function coloring situation, if the color is wrong 10 layers down, you must change the calling function. It's a non-local consideration. You don't get to decide not to change it. You can't encapsulate it. You don't get a choice. It pollutes the entire stack, forcibly.

I think this is an interesting perspective, where I would raise a counterpoint. Both result types and async/await are instances of monads (the abstraction which approximates the article's idea of a function color, since you mentioned Haskell, I assume you know this). Just as you can "eliminate" the result type by explicitly handling the success and error cases, you could, theoretically, "eliminate" the async function by blocking on it. Doing so would treat the entire async subprogram, at the top-level function boundary, as synchronous IO, while the async subprogram would still benefit from concurrency internal to the function.

Compare Example #1:

    int topLevel() {
      return match fallibleSubprogram() {
        Ok(()) => 0,
        Err(_) => 255,
      };
    }

    Result<(), Err> fallibleSubprogram() {
      let x = f()?;
      let y = g()?;
      return h(x, y);
    }
Compare Example #2:

    int topLevel() {
      block_on(asyncSubprogram);
      return 0;
    }

    async void asyncSubprogram() {
      let promiseX = f();
      let promiseY = g();
      let [x, y] = await Promise.all([promiseX, promiseY]);
      return await h(x, y);
    }
In the above pseudo-code, you have the same program "structure," but the first uses results and the second uses promises. In the latter example, asyncSubprogram() gets called as if it were synchronous, but you still benefit from asynchronicity because f() and g() can execute concurrently within its body.

The main difference is that compared to pattern matching on Result types, programming languages typically make it unidiomatic to block on a promise. There are various reasons why this is the case, but my point is that Result types and async/await are more similar than they may initially appear.


"Just as you can "eliminate" the result type by explicitly handling the success and error cases, you could, theoretically, "eliminate" the async function by blocking on it"

You really can't. Shutting down the async loop doesn't just do damage to the performance of the program, it can actually affect correctness. It doesn't fix the color problem. That's why I said 'Although I will say that if your "encapsulation" is basically to run it in a non-concurrent environment, that's really not encapsulation. It isn't really "encapsulation" if you're giving up an entire major feature of the language, because that is something very visible to the rest of the program.'

Monads actually aren't really relevant, either. A monad can express something you can't escape from, but it isn't required; "Option" isn't a color because you can still deconstruct it any time you like. It's specifically IO, which traps you not because it is a "monad" but because it has no escape hatches at all. (Modulo "unsafe", which is always something we have to say, but we also always tend to ignore unsafe in these discussions because otherwise everything collapses to one big unsafe pile in all languages of note.)


I'd argue that Go and all other implicit async approaches do have function colours. You're much less likely to notice the colour, but in the edge cases where it can be noticed such systems are harder to work with.

LLMs are very prone to priming in my experience. That is the human psychology name for what you are describing; whether it should be applied to LLMs I don't know, but it describes the phenomenon perfectly.

Makes sense as priming is at the core of how an LLM is trained.

“Given these words, predict the next word.”


I just merged a commit for exactly this in rclone

https://github.com/rclone/rclone/commit/ad8a108453f3ce983fb6...

It is interesting to dig into why.

There was a security vulnerability in golang.org/x/net/http2/h2c which meant govulncheck warned about it in the CI.

So I updated it and got a warning from the linter that the h2c sub package was deprecated in the latest version, so I removed it.

That is a lot of great tooling working to make things more secure in the Go ecosystem.

It does make work for maintainers though, and the Cambrian explosion of AI discovered security vulnerabilities has been particularly trying!


Great demo! Very interesting to see that if you wiggle the hunter (1) back and forth the accuracy improves.

I think this is expected but interesting to see as you see humans and animals doing exactly this to better gauge how far away something is.

The accuracy also improves (but not as much) if you wiggle the target (2) back and forth which I wasn't expecting.


The Z80 spawned the 64180 which was a Z80 with loads of stuff built in (from Wikipedia)

Execution and bus access clock rates up to 10 MHz

Memory Management Unit supporting 512K bytes of memory (one megabyte for the HD64180 packaged in a PLCC)

I/O space of 64K addresses

12 new instructions including 8 bit by 8 bit integer multiply, non-destructive AND and illegal instruction trap vector

Two channel Direct Memory Access Controller (DMAC)

Programmable wait state generator

Programmable DRAM refresh

Two channel Asynchronous Serial Communication Interface (ASCI)

Two channel 16-bit Programmable Reload Timer (PRT)

1-channel Clocked Serial I/O Port (CSI/O)

Programmable Vectored Interrupt Controller

As a consequence it was really popular in the 90s as an embedded processor just when I was starting my career. This lead to me writing thousands of lines of Z80 assembly. You could program it in C but the compiler was useless at making stuff go fast.

One of those things I wrote was an LZ77 decompressor used in a satellite broadcast system. It took me about a week to write it, test it and optimise it. Quite a challenge! I remember optimising it about the LDIR instruction to copy memory.

The compressor was written in C and ran on the PCs of the day.


Ha. When I was a teenager I used to build 555s into timers for the same purpose using a no PCB rats nest construction.

Though surprising the family at dinner with a small explosion was a much more innocent purpose.


I love photorec and dd rescue. I have recovered many many disks and memory cards with it.

I even recovered a card that had been off to professional recovery and deemed unrecoverable. I think half the memory chips in the card were fried so I used DD rescue to recover what data I could and then photorec to sift the wreckage. The owner was delighted to receive some of the photos.

If you ever have to do this, use DD rescue to image the source media as a first step. Sometimes you don't get a second read!


You say it. A few years ago my homeserver behalved odd and i needed reboots. I took out the SSD, used dd-rescue and after that The SSD did not even show up as storage any more. Yhea. I also have backups since then. :)


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: