this post was submitted on 26 Dec 2024
24 points (96.2% liked)

Linux

8323 readers
147 users here now

Welcome to c/linux!

Welcome to our thriving Linux community! Whether you're a seasoned Linux enthusiast or just starting your journey, we're excited to have you here. Explore, learn, and collaborate with like-minded individuals who share a passion for open-source software and the endless possibilities it offers. Together, let's dive into the world of Linux and embrace the power of freedom, customization, and innovation. Enjoy your stay and feel free to join the vibrant discussions that await you!

Rules:

  1. Stay on topic: Posts and discussions should be related to Linux, open source software, and related technologies.

  2. Be respectful: Treat fellow community members with respect and courtesy.

  3. Quality over quantity: Share informative and thought-provoking content.

  4. No spam or self-promotion: Avoid excessive self-promotion or spamming.

  5. No NSFW adult content

  6. Follow general lemmy guidelines.

founded 2 years ago
MODERATORS
top 6 comments
sorted by: hot top controversial new old
[–] [email protected] 7 points 22 hours ago* (last edited 21 hours ago) (1 children)

Rather the difference in dependencies between something written in Rust vs. “traditional” C or C++ is that on Unix systems, all these dependencies are still there, just handled by the system instead of the compiler directly. The distro maintainers do more of the work, and our build systems assume the presence of various system libraries in system places. The only thing new about it is that programmers are exposed to more of the costs of it up-front.

No, that is not the only thing. Here are a few more differences:

  • A distro-supplied dependency undergoes more scrutiny before it reaches users. Security problems are more likely to be caught than they would be in dependencies pulled directly from upstream. For example, the 2024 xz utils back door never made it into Debian Stable.
  • A distro-supplied dependency tends to be shared by multiple applications: Its version, build environment, and build options are usually the same for every program that depends on it, making problems more visible and therefore more likely to be noticed and fixed.
  • A distro-supplied dependency gets security updates along with the rest of the distro. Users don't have to do anything special to get them.

These differences are critically important today, since exploits and supply chain attacks have become common.

(Aside: The author conveniently picked for comparison a program written in C++, and not only that, but one described as "a 3d visualization environment for robots using ROS." In other words, one of the most complicated languages out there, and an application guaranteed to need things beyond the standard and platform libraries. This is what cherry picking looks like.)

If we as software developers are going to be "real" about dependencies, we must acknowledge that they are liabilities that we impose upon users. The responsible thing to do is to minimize them, and be very cautious about the few that we use. Languages (or more accurately, dependency managers) that encourage high dependency counts, including indirect dependencies, are a very real security problem.

Since the article focuses on Rust, it's worth pointing out that Rust (through Cargo) is among the worst in this department, undermining its own value proposition as a security improvement vs. other languages. I hope it will be better some day.

[–] [email protected] 1 points 8 hours ago

The other, IMHO, bigger difference is that is any one of those dependencies breaks or develops a security issue, many things on your system break.

I much prefer statically linked programs with as few extremal runtime dependencies as possible. Many times when a program stops working, it takes forever to trace it to a dynamic dependency. Interpreted languages exacerbate this to ridiculous levels. But my statically linked programs - once they work, they work practically forever; it requires a major core library change - libc, or libm - to break them, and that almost never happens.

I hard disagree with you: build time dependencies are both more secure and more reliable than runtime dependencies.

[–] [email protected] 2 points 1 day ago (1 children)

I'm currently working on a build system and one of the big challenges, I still have is when to re-run a task vs. use a cached result.
In particular, for external CLIs, I had the more-or-less genius idea to run them with strace and then pick out all the paths from the openat calls, to figure out which files they use as inputs.

I knew that strace has a tendency to output a flood of messages, so I tried it with ls first, thinking surely it would just open the directory that's to be listed and then exit.

Yeah... no. 🫠

This is the output, in a directory that contains only a single file:

$ strace ls 2>&1 | grep openat
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib64/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib64/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib64/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/de_DE.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/de_DE.utf8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_NAME", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_PAPER", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/de_DE.UTF-8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/de_DE.utf8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/de_DE.UTF-8/LC_TIME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/de_DE.utf8/LC_TIME", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_BW.UTF-8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_BW.utf8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/en_GB.UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/en_GB.utf8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3

Like, damn, ls loads 4 different libraries and all the locale files, so it can output this:

$ ls
hello.txt

I would really like to know what lead to it always reading out my choice of currency. But ultimately, yeah, that was just one of those moments where I noticed again that even seemingly innocuous programs are just stupidly complex.

[–] [email protected] 4 points 1 day ago (2 children)

The locale is used for sort order.

[–] [email protected] 2 points 1 day ago

Ah, that makes some sense. Thanks.

[–] [email protected] 1 points 1 day ago

Does it still load locales if you invoke it with LC_ALL=C or LC_ALL=POSIX?

That would be a smart optimization, methinks.