#248122 msttcorefonts: Please run wget as user nobody instead of as root

Package:
msttcorefonts
Source:
msttcorefonts
Submitter:
Justin Pryzby
Date:
2023-09-30 08:21:03 UTC
Severity:
wishlist
Tags:
#248122#5
Date:
2004-05-09 10:22:44 UTC
From:
To:
Unless I've missed it, there's no privlege dropping, and I'd like wget
to run as a normal user (specifically: nobody).  This should be easily
implemented, as the script is just writing to /tmp/.

#248122#10
Date:
2004-08-05 14:31:11 UTC
From:
To:
Well, that's not entirely true. It's not writing to /tmp/, it's writing
to /tmp/msttcorefonts/, which is root.root 755.  If wget were to switch
uid to nobody, it would not be able to put its output in this directory.

I don't think it would be more secure to switch the download directory
be writable by user nobody.  This may open up some of this issues
raised in bug #98408, which was solved by making sure that only root
could write to the download directory.

Do you have a way around this?

Eric

#248122#15
Date:
2004-08-05 14:31:11 UTC
From:
To:
Well, that's not entirely true. It's not writing to /tmp/, it's writing
to /tmp/msttcorefonts/, which is root.root 755.  If wget were to switch
uid to nobody, it would not be able to put its output in this directory.

I don't think it would be more secure to switch the download directory
be writable by user nobody.  This may open up some of this issues
raised in bug #98408, which was solved by making sure that only root
could write to the download directory.

Do you have a way around this?

Eric

#248122#20
Date:
2004-08-05 14:53:51 UTC
From:
To:
Debian's tempfile(1) should do it.  tempfile -n $name will request a
name.  But it'd be better to not specify -n actually, because otherwise
you'd have a security race condition if you didn't deal with the return
value anyway.

file=`tempfile`;
wget -O $file;

Cheers,
Justin

#248122#25
Date:
2005-12-11 00:03:54 UTC
From:
To:
Have you given any thought to this bug?  It seems like it would be
easy and desirable to avoid running wget as root.  Indeed, *two* of
the outstanding RC bugs in the months leading up to the etch release
were security problems with wget.

#248122#30
Date:
2005-12-12 13:54:44 UTC
From:
To:
* Justin Pryzby

| Have you given any thought to this bug?  It seems like it would be
| easy and desirable to avoid running wget as root.  Indeed, *two* of
| the outstanding RC bugs in the months leading up to the etch release
| were security problems with wget.

If so, I don't think I would want it to run as nobody, but rather
having a special user created for this sole task, which seems rather
overkill.  Else, any other process running as nobody could subvert the
download and possibly make root run arbitrary code.

#248122#35
Date:
2005-12-12 14:27:48 UTC
From:
To:
I don't suppose md5sums are available?  Does the file change
sufficiently often such that its not reasonable to hardcode an MD5?

Though I'm not sure what the requirements are for this kind of user,
is there any problem adding a user, running wget as that user, and
then removing the user?

Ah, maybe this bug is moot anyway.  I seem to recall a thread on LKML
(or was it a debian bug log?) where it was pointed out that there is
no way to drop privileges in such a way that you can't get them back
with seteuid(getsuid()).  In which case, this bug lies in your hands,
since I can't think of a clean way to have it run as a user which
cannot regain privileges.

#248122#40
Date:
2005-12-12 15:03:34 UTC
From:
To:
* Justin Pryzby

| I don't suppose md5sums are available?  Does the file change
| sufficiently often such that its not reasonable to hardcode an MD5?

It doesn't change, and I have the hashes, so that might be a workable
approach.

| Ah, maybe this bug is moot anyway.  I seem to recall a thread on LKML
| (or was it a debian bug log?) where it was pointed out that there is
| no way to drop privileges in such a way that you can't get them back
| with seteuid(getsuid()).  In which case, this bug lies in your hands,
| since I can't think of a clean way to have it run as a user which
| cannot regain privileges.

setuid(2) seems to disagree with you (for suid root, and we wouldn't
be suid, we would be run by root).

#248122#45
Date:
2005-12-13 01:23:13 UTC
From:
To:
Bah, I don't know.

Hows this?

  md5good="d41d8cd98f00b204e9800998ecf8427e" # NEEDS CHANGING
  f=`mktemp` || exit 1;
  su -c "wget -O $f http://..." nobody;
  echo "$md5good  $f" |md5sum -c || { echo >&2 $0: MD5Sum failed!!; exit 1; }

I don't know if it works in posix sh like posh or dash..

#248122#50
Date:
2006-03-01 19:33:58 UTC
From:
To:
Can I expect to see this bug fixed for etch?

http://bugs.debian.org/248122

Justin

#248122#55
Date:
2006-06-30 05:16:27 UTC
From:
To:
As root (assuming running with set -e):

  d=`mktemp -d`
  install -d -m 700 -o nobody "$d"/writable
  (cd "$d"/writable && su nobody -c 'wget ...')

User `nobody' can write into this `writable' directory, but only for a
process that has already cd'd into it as root before becoming nobody:
the "$d" directory is executable only by root.

pjrm.

#248122#60
Date:
2006-06-30 18:39:01 UTC
From:
To:
I think it is intended that "nobody" never owns any files.  So the
right way to do it probably involves dynamically creating a user, or
using some user guaranteed to exist, like "sys" or "operator".

Justin

#248122#65
Date:
2006-07-04 06:43:32 UTC
From:
To:
I believe that the reason for this is so that no `nobody'-owned process
can read/write non-world-accessible files other than its own.  The above
approach does achieve this result even though it does literally create a
file as `nobody': no other non-root process can access the file.

I believe that many things would benefit at least slightly in security
from such a facility: even things that don't need to read/write files
would still be less exposed to denial of service by being killed by
other nobody-owned processes.

However, in the short term, I suggest using the only-root-readable
directory approach: it already gets us most of the way there, avoiding
giving the wget executable privileges of an important user like
root (or sys or operator).

pjrm.

#248122#70
Date:
2006-07-05 13:41:43 UTC
From:
To:
* Peter Moulder

| I believe that the reason for this is so that no `nobody'-owned process
| can read/write non-world-accessible files other than its own.  The above
| approach does achieve this result even though it does literally create a
| file as `nobody': no other non-root process can access the file.

That's not strictly true.  Another process running as nobody could
ptrace the wget process and do harm.

I'm going to make it download as nobody and check the md5sums as root
and throw a big warning if the md5sum doesn't match.  This should make
everybody happy, I just need the get a round tuit first.

#248122#75
Date:
2006-10-12 08:39:46 UTC
From:
To:
Hi Justin,

No, I'm sorry it's too late for that in the release cycle now. I've only
just taken over the package and I'll make any non-trivial fixes only
after etch's release.


Thijs

#248122#80
Date:
2006-12-15 13:05:00 UTC
From:
To:
Hi,

I've seen the discussion in this bug, and I wonder whether it makes sense
to actually go the way to drop these privileges. A user running apt-get
update or apt-get upgrade is already performing many HTTP requests and
downloading numerous files from relatively untrusted sources (they are
verified after downloading), as root.

Would it make sense to change msttcorefonts for this while an admin will
already be doing this with APT?


Thijs

#248122#85
Date:
2007-04-19 18:45:51 UTC
From:
To:
Hi,

I will not fix this bug as per the reasoning in my previous message,
some months ago.


Thijs

#248122#90
Date:
2007-04-19 19:27:20 UTC
From:
To:
Hi, Will you at least consider using checksums?

I still think running wget as root should be avoided.  The apt code
was written with this in mind, but wget is typically run by normal
users.

Anyway, I know more about setuid and friends now.  A root process can
(and will by default) change all its UIDs with setuid.  Using
setresuid you can control all the UIDs independantly.  Anyway
something like this should be sufficient.

f=`tempfile`
adduser mstwget
su -c "wget -O '$f'" mstwget
chown root:root "$f"
deluser msgwget
for m in $validmd5
do
	[ "$m" = "`md5sum "$f" |sed -e 's/ .*//'`" ] && break
done

[ $? -eq 0 ] || {
	echo "$0: error: md5sum failed to match any correct value"
	exit 1
} >&2

Justin

#248122#95
Date:
2007-04-20 12:52:44 UTC
From:
To:
reopen 248122
tags 248122 wontfix
thanks

Because there's still discussion in this bug I'm reopening it, but
tagging it wontfix for now since that's my current opinion.

I don't understand... we're already using checksums to verify the
downloaded files. Or am I missing something?

this needs a `chown mstwget $f` I think.

I'm not opposed to running wget non-privileged in principle, but am
concerned about extra fragility introduced in the process, offset
against the risk that running wget as root could bring. Since wget is
very widely used, and also in quite some packages as root automatically,
I think the risk of wget being faulty is relatively small.

msttcorefonts is not the only 'downloader' package. What I think would
be a nice solution, is if some system is developed that serves as common
downloader-package code, and that code is used by the downloading
packages. While I don't feel like maintaining my own system for
privilege dropping when other packages are not doing that, or doing it
differently, I am open to use a system as long as this is common for all
downloaders, hence increasing the testing and reducing duplication.

Maybe some kind of "downloaders-common" like "dbconfig-common"?


Thijs

#248122#104
Date:
2007-04-20 13:29:35 UTC
From:
To:
Great; I didn't realize that this was implemented.  It seems that the
md5sum happens only for the extracted files; shouldn't it happen for
the originally downloaded file?
Yea, prolly; it wasn't actually meant to be working code, but I got
carried away.
Do you know where it's run as root?  This might be a nonissue if it's
really a common assumption.
This would be neat indeed.

Justin

#248122#109
Date:
2007-04-20 13:52:35 UTC
From:
To:
Ah, in that sense. It's only checked currently when (re)using previously
downloaded files. I'll see whether I can easily expand that to checking
the .cabs before extracting them, which sounds like a good feature.

Since the package is undergoing some real work now, I think this can be
included before the next upgrade.

From the top of my head at least flashplugin-nonfree and quake2-data.
But I really doubt that those are the only other ones. Maybe a package
search on "downloader" would yield some more results.


Thijs

#248122#116
Date:
2017-08-02 20:35:02 UTC
From:
To:
Hi Thijs,

I'm sorry to resurrect this from the dead. I came across this bug
looking for something completely different...

APT uses its own much smaller special-purpose HTTP implementation. It
also spawns a sub-process just for the HTTP method which I think used to
run as an unprivileged user. On a jessie system the latter doesn't
currently happen any more but that would be a bug in APT.

As for msttcorefonts, a straightforward approach would be to have wget
output to stdout and avoid file system access by wget altogether:

# su - wgetuser -c "wget -O - $url/$file" > ./$file

I haven't tested it but this should run wget as wgetuser yet write to
./$file as root while the destination path is controlled by the shell
not wget.

Cheers,

Rene

#248122#121
Date:
2023-09-30 08:18:53 UTC
From:
To:
(reposting, I think my last comment may have been blocked for using a fake email)

Hi,

I too noticed that wget STILL runs as root:root.
Nothing with root privileges should ever connect to the internet unless absolutely necessary.

Fixing this is as simple as changing two lines in ttf-mscorefonts-installer.postinst:

	SCRATCHDIR=`mktemp -t -d ttf-mscorefonts-installer.XXXXXX
becomes
	SCRATCHDIR=`sudo -u _apt mktemp -t -d ttf-mscorefonts-installer.XXXXXX

and
	if ! wget --continue --tries=1 --connect-timeout=60 [...]
becomes
	if ! sudo -u _apt wget --continue --tries=1 --connect-timeout=60 [...]

I don't know if _apt user is standard debian or just part of the distro I'm using.
sudo -u nobody worked just as well.

This is a serious and completely unnecessary security threat where a remote code execution vulnerability could get an attacker full root access. Why???