Hacker Newsnew | past | comments | ask | show | jobs | submit | jkercher's commentslogin

Tangentially related. Don't ever put "." in your PATH. I used to do this to avoid typing the "./" to execute something in my current directory. BAD IDEA. It can turn a typo into a fork bomb. I took down a production server trying to save typing two characters.


It used to be very common to "own" a unix system by adding a `ls` binary in some folder and waiting for an administrator to run it.


Why would this own a server? ls lists itself, but listing itself shouldn't cause it to run again? Where's the infinite loop that brings the server down?


I think parent comment means "cp badthing ls" and leave it latent for someone to run. Maybe $PATH has CWD first for convenience?


They're not talking about the same scenario. Owning isn't denial of service. And they didn't say the `ls` lists things (though it probably will do that at the end).


I like to follow my own convention where I name files with shell scripts with an extension: .sh for POSIX-compatible scripts, .bash for scripts with bashisms or .zsh for scripts with zshisms.

If I ever wanted to achieve what you initially wanted to achieve - I could use something like

alias -s sh=sh

alias -s bash=bash

alias -s zsh=zsh

Just like I do bind .txt and .conf to 'less', .pdf to 'qpdf', .json to 'ijq', video formats to 'mpv' and so on.


Related: My grad school had a shared bin/ directory with common local tools. Of course, that directory was after /bin and /usr/bin in the PATH so that no one could override “ls” or “more”. So… one grad student added scripts with names that matched common typos: “sl” and “mroe”!

Sure enough, they got run. The scripts didn’t take over your account. They ran “ls” and “more”. They may have also logged your username in a file so he could lord it over you.


Might I ask exactly what the typo was?


Elaborate?? "." has been at the end of my PATH for like 20 years.


I could drop a shell script that does something like

echo "lanyard2 ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/lanyard2 ; ls

if you ran ls in my dir, you would give me sudoers access


If you put . at the end of PATH, isn't it checked last? I would need to have a missing ls installation.

Still viable though for something like rg... Maybe you run it before you install it for the first time on a new machine.


Just to save the trouble of writing './'?


Yes??? :)

I'm not the crazy one here! That's a whole two characters on the same side of the keyboard...


How often do you find yourself running executables from the current directory? Is this a daily thing?


Gamedev! I could run some crazy cmake command to build and run, or I could just bin/build.


For my workflow, yes

I don’t think it’s a severe security vulnerability. The same thing can happen with $home/bin.


I think it's substantially riskier. At the very least, it means you are trusting any directory you cd into, rather than just trusting your $home/bin.

Stuff that would not typically raise eyebrows has been made risky. You might cd into less privileged user's $home, or some web service's data directory, and suddenly you've given whoever had access to those users, access to your user.

Maybe you could argue "well, I just won't cd outside of my $home", but the sheer unexpectedness of the behavior seems deeply undesirable to me.


Why does this go wrong and in what situation?


Somebody mentioned it elsewhere, but it is a security risk: if you end up in a directory that's not under your control, and you do a "ls", it might execute "./ls" instead of /usr/bin/ls, and that can be doing anything, including piping your ~/.ssh/id_* to a remote server.

This can also happen by downloading something off the internet (git clone, or tar xz foo.tar.gz), or on a multi-user system (eg. someone can put any of these common commands into /tmp/ and wait for you to drop into it and try a "ls" there) — if you have any untrusted content anywhere, you are exposed.


> if you end up in a directory that's not under your control, and you do a "ls", it might execute "./ls" instead of /usr/bin/ls,

Not if if you APPEND the dot path to the PATH env: the system traverses the dirs specified in the PATH env from left to right and stops at first match. Your system's ls binary is in the dir that's to the left of your '.' dir.


Yeah, there are ways to reduce the impact (as a sibling comment mentioned, typos or commands missing on a system could still be used to trick the operator), but I was mostly explaining the attack vector in case it is present in the PATH.


Then it's a little bit of a stretch but they could put a script with the name of a common typo similar to commonly run commands there. Maybe "ls-l" without the space in case they miss the space. Yeah, that's a stretch. I went looking for better sources.

> The current directory ( . ) is not in PATH by default, for security reasons. This prevents accidentally running unintended programs in your current directory.

-- POSIX Shell scripting from scratch, By Sultan Zavrak (states it in general terms. They also use ls as an example though, which shouldn't be affected if you have "." at the end.)

Practical UNIX and Internet Security has an example of "." (or having a null entry in the PATH, which also indicates the current directory; I didn't know that![0]) at the beginning, which is obviously a bad idea, but he (Simson Garfinkel) makes a good point:

> More generally, you should never have a path that is writable by other users.

Ah yes, finally, he covers a situation where you have a directory at the end of your path, that is writable by others ("." would count) and having a trojan named "mroe" (for "more") waiting patiently for the superuser to mess up.

He even goes so far to say that root should run commands with full paths, such as /sbin/chown and not just chown. I've never gone that far, except I can see the benefit of doing that in scripts.

So anyway, besides the typo example, there's also a kind of shadowing: let's say you expect a command to fail because the program is not installed. Or maybe you try to run a command you think is installed but it's not. You might even have a command or way of working that tries various commands until one works. If you have a path that someone can write to (including ".") then instead of failing, it will run something unintended, if they have shadowed that command in that directory.

[0] to quote the bash man page: A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon.


Presumably a script that aliases a common thing or something and then it uses the same. E.g. someone adds ./sed that has some default params and calls sed. You’re intended to call it with ~/not-in-path/defaulted/sed and it is supposed to then call sed but instead calls itself if it’s earlier in the path hierarchy.

Might even be as simple as “detect if I’m running gnu sed or bsd sed and use the appropriate one”. Obviously you can not have this problem by being smart about other things but defense in depth right?


Not if if you APPEND the dot path to the PATH env: the system traverses the dirs specified in the PATH env from left to right and stops at first match. Your system's sed binary is in the dir that's to the left of your '.' dir.


Appending is much better than prefixing, but having "." in the path, anywhere, can still open you up to running mistyped commands (arguably a much less common possibility, but still a possibility).

I.e., you have "." as the very last item in your path. You are in /tmp/ (so a directory other uses can write files to). You mean to type "ls -l something" to look for "something" files. But instead, you just miss the space, and type "ls-l something*", and some other nefarious user has left a /tmp/ls-l binary behind just waiting to be run. It could package up your ~/.ssh folder and ship it off to "nefarious" user, and then do a proper "ls -l" so that you may not even notice the typo.

And, if you happen to be root when you are in /tmp and mistype ls-l, and if the ls-l binary checks to see if it is being run as root, it could then do even worse. For example, it could leave behind an suid to root bash or sh executable in 'nefarious user's' home dir, so that 'nefarious' can now become root at some point later and proceed to actually 'own' the system.


Right, that's one way to be half-smart about it. But you have to make sure that's the final thing you append to the path. An easy mistake to make is temporal. You add `.` to the path, and time passes, someone appends `/opt/bin` to the path, and time passes, someone writes `~/not-in-path/defaulted/busybox` that references `/opt/bin/busybox` as just `busybox` and tests it by running `~/not-in-path/defaulted/busybox` while being in `~` and it works so they leave it alone, then you go `cd ~/not-in-path/defaulted/` and run it and die.

"I don't understand. I very specifically appended `.` at the end!"

Of course you can stick a comment "#the following should always be at the end of the file" or whatever or say "we should always make sure to reference binaries by their full path, so always write out `/opt/bin/busybox` rather than just `busybox`" and stuff like that. With enough system you can make this unlikely.


A trip down the recursion hole. Also, scripts will inherit the relative path so they will have different absolute paths from each other. Seems easier to just type ./ so it's kinda funny in a "UNIX haters handbook" kind of way, but it's not even a fault in linux's command interface in that case. We've all been there.

Oh, that's without even going into the security risks and loss of portability.


lol. What a beautiful footgun — for such a tiny optimization.


One of the advantages to the pointer + length approach is free substrings. This inline approach doesn't allow that.


The ability to slice substrings results in a massive speed increase for string handling.


Couldn't agree more. I have a project at work from 2016 that builds multiple different HMIs (C++) along with 2 embedded systems (C). They all have to play nicely with each other as they share some structures and can all be updated in the field with a single file on a USB stick. So there is a bash script that builds everything from a fresh clone, makes update files, and some other niceties. Then, there is a single python script that generates a handful of tables from a json file.

Guess which part of the build I spent fixing the other day... It wasn't the ~200000 lines of c/c++ or the 1000+ line bash script. No. It was 100 lines of python that was last touched 2 years years ago. Python really doesn't work as a scripting language.


I don't think so. I don't play nearly as often as I used to, but I still do alright. Though, I usually play tournaments where "game theory optimal" can only get you so far. There is a lot more nuance in a tournament where your style should change as it progresses.


Super System is old, but I wouldn't call it outdated. Definitely still worth a read. The more books you've read, the bigger your tool set. The key here is that it works in both directions because each style you learn, is a style you may recognize other players using. The pitfall of Super System, is by now, everyone's read it, and it's quite easily recognized:

- limp-shoving under the gun

- always trying to go on runs

- over playing suited connectors (JTs specifically)

But, you still get the advantage of being able to recognize it. There's lots of good wisdom in there that isn't as prescriptive either. Read as many books as you can. Poker is information warfare.


I thought it was outdated to the point of useless when I read it in the mid aughts. I didn't find any real wisdom in it either. I'm open but pretty confused as to what you think someone could get out of it today.


I certainly would not use it prescriptively as I said originally. I wouldn't use any poker book prescriptively. You make your own style and pull pieces from others just like any other trade. I like the way Joe does X.. I like the way Jane does Y.. I have my own way to do Z. That becomes my style.

There are nuggets of wisdom in every poker book I've read even if I disagree with some parts or some are just flat out wrong. Super System, in particular, provided insights into the mind of one of the greatest player of all time. I particularly liked the psychological view on things. If nothing else, it provides context for the ones that came before you. Its been 15+ years since I read it, but beyond the fundamentals, I recall picking up (hopefully not misattributing anything here)...

- a quick, in-your-head method of calculating odds based on outs

- psychology of playing runs and others perceptions of you at the table

- the pitfalls of playing AA

- a realistic look at "tells"

- the general psychology of aggression

- how/where tight players make money and how/where aggressive players make money

Super System is the seminal book of poker. It is the book that your opponents are most likely to have read. As I alluded in my original comment, you wouldn't want to be the only person at the table who doesn't recognize someone playing the super system to the letter. IIRC, the goal was to make the player just appear lucky. It was meant to be confusing. It's like reading K&R as a C programmer. Sure, some of the information might not hold up today, but it provides a lot of context.


Thanks. Maybe it's because I read all the more modern books, the 2+2 library etc, before reading Super System that I don't really appreciate it. I guess also because I was a volume-based online player.

But I do really appreciate hearing your perspective on it.


When I first heard about Odin, I thought, why another C replacement?! What's wrong with rust or zig? Then, after looking into it, I had a very similar experience to the author. Someone made a language just for me! It's for people who prefer C over C++ (or write C with a C++ compiler). It has the things that a C programmer has to implement themselves like tagged unions, slices, dynamic arrays, maps, and custom allocators. While providing quality of life features like distinct typing, multiple return values, and generics. It just hits that sweet spot. Now, I'm spoiled.


It's indeed some kind of sweet spot. It has those things from C I liked. And it made my favorite workflows from C into "first class citizens". Not everyone likes those workflows, but for people like me it's pretty ideal.


May I ask what specifically you dislike about Rust (and Zig)? All the features you mentioned are also present in these languages. Do you care about a safety vs. simplicity of the language, or something else entirely?


Call it a niche use-case, but every time I had the chance to evaluate Rust, I had to write a function taking a callback, sometimes across to a C library. Every time I have to deal with an Fn/FnOnce/FnMut trait signature, remember if I need to box it with dyn, mayhaps it takes a reference as argument so I also need to deal with lifetimes signatures, then remember the `for<'a>` syntax, then it blows up because I need to add `+ 'static` at the end which still makes no sense to me, then I just rage quit. I am decently handy with (unsafe) Rust, wrote a minimal OS in it, but dealing with function pointers makes me want to carve my eyes out.

C doesn’t even care. You can cast an int to a function pointer if you want.

With Odin it’s taken me like 5 minutes including reading the section of the docs for the first time.


`impl Fn/FnOnce/FnMut` don't stand for function pointers, but rather function items in Rust, and as such they are zero sized so Rust can provide optimizations regarding function items specifically at compile time.

They can decay to function pointers (`$(unsafe)? $(extern)? fn($(inp),*) $(-> $(output))?`, example: unsafe extern fn() -> i32), which you can freely cast between function pointers, `*const/mut T` pointers or `usize`s. https://doc.rust-lang.org/reference/types/function-pointer.h...


Rust and Zig are both perfectly fine languages. Odin wins on simplicity and familiarity for me. I'm most productive in C which is what I use at work. So, for me, it's a better C with some quality of life improvements. It's not trying to be too radical, so not much to learn. The result is that I move can fast in Odin, and it is legitimately fun.


Mirrors my experience too. Odin is a joy for us oldie C programmers. Rust; not in the slightest.


Your experience is not universal, there are oldie C programmers who also enjoy Rust.


Zig is similar in spirit but I think it tapped a bit more into the "innovation budget" and thus it might not click to all


Yep. It’s my favorite C-replacement. It compiles fast. It has all of the pieces and abstractions I care about and none of the cruft I don’t.


What's naive?


I'm not looking for an argument, but my knee jerk reaction to seeing 4 or 5 different answers to the question of getting python to C... Why not just learn C?


The python already exists. These efforts enable increasing performance without having to rewrite in a very different language.


I have dabbled in Cython, C and Rust via PyO3.

C is much cleaner and portable. Easy to use in Python directly.


clickhouse-local is pretty slick as well. You can operate directly on text files as if they were tables. I made my own toy text file database thing and thought I was cool because I could outrun similar programs like q, textql, sqlite, etc. But clickhouse-local had me by a factor of 10 easy in every kind of query with every type of data. Those guys know stuff.


Have heard good things about local. Clickhouse more broadly is an awesome project and they're always on standby to help our eng team team as well.


I think he's saying the text should be more muted like the copyright at the bottom.


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

Search: