• 0 Posts
  • 111 Comments
Joined 2 years ago
cake
Cake day: July 2nd, 2023

help-circle

  • While I get your point that Python is often not the most appropriate language to write certain parts of an OS, I have to object to the supposed necessity of C. In particular, the bolded claim that an OS not written in C is still going to have C involved.

    Such an OS could instead have written its non-native parts using assembly. And while C was intentionally designed to be similar to assembly, it is not synonymous with assembly. OS authors can and do write assembly when even the C language cannot do what they need, and I gave an example of this in my comment.

    The primacy of C is not universal, and has a strong dependency on the CPU architecture. Indeed, there’s a history of building machines which are intended for a specific high-level language, with Lisp Machines being one of the most complex – since Lisp still has to be compiled down to some sort of hardware instructions. A modern example would be Java, which defines the programming language as well as the ISA and byte code: embedded Java processors were built, and thus there would have been zero need for C apart from legacy convenience.


  • As it happens, this is strikingly similar to an interview question I sometimes ask: what parts of a multitasking OS cannot be written wholly in C. As one might expect, the question is intentionally open-ended so as to query a candidate’s understanding of the capabilities and limitations of the C language. Your question asks about Python, but I posit that some OS requirement which a low-level language like C cannot accomplish would be equally intractable for Python.

    Cutting straight to the chase, C is insufficient for initializing the stack pointer. Sure, C itself might not technically require a working stack, but a multitasking operating system written in C must have a stack by the time it starts running user code. So most will do that initialization much earlier, so that the OS’s startup functions can utilize the stack.

    Thjs is normay done by the bootloader code, which is typically written in assembly and runs when the CPU is taken out of reset, and then will jump into the OS’s C code. The C functions will allocate local variables on the stack, and everything will work just fine, even rewriting the stack pointer using intrinsics to cause a context switch (although this code is often – but not always – written in assembly too).

    The crux of the issue is that the initial value of the stack pointer cannot be set using C code. Some hardware like the Cortex M0 family will initialize the stack pointer register by copying the value from 0x00 in program memory, but that doesn’t change the fact that C cannot set the stack pointer on its own, because invoking a C function may require a working stack in the first place.

    In Python, I think it would be much the same: how could Python itself initialize the stack pointer necessary to start running Python code? You would need a hardware mechanism like with the Cortex M0 to overcome this same problem.

    The reason the Cortex M0 added that feature is precisely to enable developers to never be forced to write assembly for that architecture. They can if they want to, but the architecture was designed to be developed with C exclusively, including interrupt handlers.

    If you have hardware that natively executes Python bytecode, then your OS could work. But for x86 platforms or most other targets, I don’t think an all-Python, no-assembly OS is possible.



  • I guess your nephew can start studying to become a network engineer now lol

    In all seriousness, a 16 port managed switch exposes enough complexity to develop a detailed understanding of Ethernet and Layer 2 concepts, while not having to commit to learning illogical CLI commands to achieve basic functionality. 16 ports is also enough to wire up a non-trivial network, with ports to spare for exercising loop detection/protection or STP, but doesn’t consume a lot of electricity.

    I would pair that switch with a copy of The All-New Switch Book, 2nd Edition to go over the networking theory. Yes, that book is a bit dated but networking fundamentals have not changed that much in 15 years. Plus, it can be found cheap, or on the high seas. It’s certainly not something to read cover-to-cover, since you can skip anything about ATM networks.

    Then again, I think students might just simulate switch behaviors and topologies in something like GNS3, so no hardware needed at all.


  • I suspect that PG&E’s smart meters might: 1) support an infrared pulse through an LED on the top of the meter, and 2) use a fairly-open protocol for uploading their meter data to the utility, which can be picked up using a Software Defined Radio (SDR).

    Open Energy Monitor has a write-up about using the pulse output, where each pulse means a quantity of energy was delivered (eg 1 Watt-hour). So counting 1000 of such pulses would be 1 kWh, and that would be a way to track your energy consumption for any timescale.

    What it won’t do is provide instantaneous power (ie kW drawn at this very moment) because the energy must accumulate to the threshold before sending a pulse. For example, a 9 Watt LED bulb that is powered on would only cause a new pulse every 6.7 minutes. But for larger loads, the indication would be very quick; a 5000 W dryer would emit a new pulse after no more than 0.72 seconds.

    The other option is decoding the wireless protocol, which people have done using FOSS software. An RTL-SDR receiver is not very expensive, is very popular, and can also be used for other purposes besides monitoring the electric meter. Insofar as USA law is concerned, unencrypted transmissions are fair game to receive and decode. This method also has a wealth of other useful info in the data stream, such as instantaneous wattage in addition to the counter registers.





  • To make sure we’re all on the same page, this proposal involves creating an account with a service provider, then uploading some sort of preexisting, established proof-of-identity (eg passport data page), and then requesting a token against that account. The token is timestamped and non-fungible, so that when the token is presented to an age-restricted website, that website can query the service provider to verify that: 1) the token is still valid, 2) the person associated with the token is at least a certain age.

    If I understood that correctly, what you’re describing is an account service combined with an identity service, which could achieve the objectives of a proof-of-age service, but does not minimize privacy complications. And we already have account services of varying degrees and complexity: Google Accounts, OAuth, etc. Basically any service where you log-in, since the point of logging in is to associate to a account, although one person can have multiple accounts. Passing around tokens isn’t strictly necessary since you can just ask the user to prove account ownership by signing into their Google Account, for example. An account service need not necessarily verify age, eg signing in to post a comment on a news article.

    Compare this with an identity service like ID.me, which provide records on an individual; there cannot be multiple records for the same live person. This type of service is distinct from an account service, but some accounts are necessarily tied to a single identity, such as online banking. But apart from KYC regulations or filing one’s taxes online, an identity service isn’t required for most day to day activities, and any additional uses pose identify theft concerns.

    Proof-of-age – as I understand it from the Australian legislation – does not necessarily demand an identity service be used to satisfy the law, but the question in this Lemmy thread is whether that’s a distinction without a difference. We don’t want to be checking identities if we don’t have to, for privacy and identity theft reasons.

    In short, can a person be uniquely, anonymously age-verified online? I suspect not. Your proposal might be reasonable for an identity service, but does not move us further towards a theoretical privacy-centric proof-of-age validation mechanism. If such a mechanism doesn’t exist, then the Australian legislation would be mandating identity checks for subject websites, which then become targets for the holder of those identity records. This would be bad.


  • Sadly, this type of scheme suffers from: 1) repudiation, and 2) transferability. An ideal system would be non-repudiable, meaning that when a GUID is used, it is unmistakably an action that could only be undertaken by the age-verified person. But a GUID cannot guarantee that, since it’s easy enough for an adult to start selling their valid GUIDs online to the highest bidder en-masse. And being a simple string, it can easily and confidentially be transferred to the buyer, so that no one but those two would know that the transaction actually took place, or which GUID was passed along.

    As a general rule, when complex questions arise which might possibly be solved by encryption, it’s fairly safe to assume that expert cryptographers have already looked at the problem and that no easy or obvious solution exists. That’s not to say that cryptographers must never be questioned, but that the field is complicated enough that incomplete answers abound.

    IMO, the other comments have it right: there does not exist a general solution to validate age without also compromising anonymity or revealing one’s identity to someone. And that alone is already a privacy compromise.


  • I’m on mobile so I can’t compile this myself, but can you clarify on what you’re observing? Does “nothing” mean no output to stdout and stderr? Or that you did get an error message but it’s not dispositive as to what libcurl was doing? Presumably the next step would be to validate that the program is executing at all, either with a debugger or printf-style debug statements at all junctures.

    Please include as much detail as you can, since this is now more akin to a bug report.

    EDIT: wait a sec. What exactly is this example code meant to do? The Pastebin API call suggests that this is meant to upload a payload to the web, not pull it down. But CURLOPT_WRITEFUNCTION is for receiving data from a URI. What is your intention with running this example program?


  • Unless I’m mistaken, that first example as-written will fetch POST the network resource and then immediately clean up. The fact that CURLOPT_NOPROGRESS is passed means that the typical progress bar for curl in an interactive shell will be suppressed. The comment in the code even says that to make the example do something useful, you’ll have to pass callback pointers, possibly by way of CURLOPT_WRITEFUNCTION or CURLOPT_WRITEDATA.

    From the curl_easy_perform() man page:

    A network transfer moves data to a peer or from a peer. An application tells libcurl how to receive data by setting the CURLOPT_WRITEFUNCTION and CURLOPT_WRITEDATA options. To tell libcurl what data to send, there are a few more alternatives but two common ones are CURLOPT_READFUNCTION and CURLOPT_POSTFIELDS.



  • I was once working on an embedded system which did not have segmented/paged memory and had to debug an issue where memory corruption preceded an uncommanded reboot. The root cause was a for-loop gone amok, intending to loop through a linked list for ever member of an array of somewhat-large structs. The terminating condition was faulty, so this loop would write a garbage byte or two, ever few hundred bytes in memory, right off the end of the 32 bit memory boundary, wrapping around to the start of memory.

    But because the loop only overwrote a few bytes and then overflew large swaths of memory, the loop would continue passing through the entire address space over and over. But since the struct size wasn’t power-of-two aligned, eventually the garbage bytes would write over the crucial reset vector, which would finally reboot the system and end the misery.

    Because the system wouldn’t be fatally wounded immediately, the memory corruption was observable on the system until it went down, limited only by the CPU’s memory bandwidth. That made it truly bizarre to diagnose, as the corruption wasn’t in any one feature and changed every time.

    Fun times lol


  • My recommendation is to start with getting fax to work locally. As in, from port 1 of a single SPA2102 to port 2 of the same. This would validate that your fax machines and the SPA2102 is operational, and is just entertaining in its own right to have a dialtone that “calls” the other port.

    Fortunately, Gravis from the Cathode Ray Dude YouTube channel has a writeup to do exactly that, and I’ve personally followed these steps on an SPA122 with success, although I was doing a silly phone project, not fax project. https://gekk.info/articles/ata-config.html

    If you’re lucky, perhaps fax will Just Work because your machines are very permissive with the signals they receive and can negotiate. If not, you might have to adjust the “fax optimizations” discussed here: https://gekk.info/articles/ata-dialup.html

    And then once local faxing works, you can then try connecting two VoIP devices together over the network. This can be as simple as direct SIP using IP and port number, or can involve setting up a PBX that both devices register against.


  • On one hand, I’m pleased that C++ is answering the call for what I’ll call “safety as default”, since as The Register and everyone else since pointed out, if safety constructs are “bolted on” like an afterthought, then of course it’s not going to have very high adoption. Contrast this to Rust and its “unsafe” keyword that marks all the places where the minimum safety of the language might not hold.

    On the other hand, while this Safe C++ proposal adopts a similar notion of an “unsafe” context, it also adds a “safe” keyword, to specify that a function will conform to compile-time safety checks. But as the proposal readily admits:

    Rust’s functions are safe by default. C++’s are unsafe by default.

    While the proposal will surely continue to evolve before being implemented, I forsee a similar situation as in C where code that lacked initial const-correctness will struggle to work with newer code and libraries. In this case, it would be the “unsafe” keyword that proliferates everywhere just to call older, unsafe code from newer, safe callers.

    Rust has the advantage that there isn’t much/any legacy Rust to upkeep, and that means the volume of unsafe code in Rust proframs is minimal, making them safer overall today. But for Safe C++ code, there’s going to be a lot of unsafe legacy C++ code and that reduces the safety benefit for programs overall, for the time being

    Even as this proposal progresses, the question of whether to start rewriting some code anew in Rust remains relevant. But this is still exciting as a new option to raise the bar in memory safety in C++.


  • A few months ago, my library gained a copy of Cybersecurity For Small Networks by Seth Enoka, published by No Starch Press in 2022. So I figured I’d have a look and see if it it included modern best-practices for networks.

    It was alright, in that it’s a decent how-to guide for a novice to set up sensible, minimum network fortifications. But it only includes an overview of how those fortifications work, without going into the additional depth needed to fine-tune or optimize them for specific environments. So if the reader has zero experience with network security, it’s a worthwhile read. But if you’ve already been operating a network with defenses for a while, there’s not much to gain from this particular text.

    Also, the author suggests that IPv6 should be disabled, which is a terrible idea. Modern best-practice is not to pretend IPv6 doesn’t exist, but to assure that firewalls and other defenses are configured to handle this traffic. There’s a vast difference between “administratively reject IPv6 traffic in/out of the WAN” and “disable IPv6 on all devices and pray no one ever connects an IPv6-enabled device”.

    You might have a look at other books available from No Starch Press, though.