% % Copyright 1995, Michal Jaegermann % % You may print and reprint this article, as long as the author % will be acknowledged. % \ifx\documentclass\undefined \documentstyle[11pt]{article} \else \documentclass[11pt]{article} \fi \newcommand{\command}[1]{\mbox{\tt #1}} \newcommand{\path}[1]{{\tt #1}} \begin{document} \title{Making MakeTeXPK safer for Unix installations} \author{Micha{\l} Jaegermann\\ {\small\tt michal\char`\@ellpspace.math.ualberta.ca,}\\ {\small\tt michal\char`\@gortel.phys.ualberta.ca}} \date{14 February 1995} \maketitle \begin{abstract} Leaving directories open for writing by anybody in the world in order to ensure that \command{MakeTeXPK} will work is often a security concern. This note describes how to avoid that on Unix systems without loosing functionality. \end{abstract} \renewcommand{\thefootnote}{} \footnote{Unix is a registered trademark of AT\&T} \footnote{\TeX{} is a trademark of the American Mathematical Society} \footnote{Metafont is a trademark of the Addison--Wesley Publishing Company} If you run \TeX{} on Unix, or any other Unix-like, system and you are using very convenient and popular setup with an automatic bitmap generation then you undoubtedly noticed that this requires directories with \command{'write'} permissions to everybody. In theory this is not much different than having your \path{/tmp} directory opened that way. In practice, though, especially when your programs were compiled with \command{kpathsea} library with ensuing multiple font directories, this may be some security and administrative headache. For the first and rather feeble line of defense, if your variant of Unix supports that, you should set 'sticky' bit on directories in question like this: \command{chmod a+t pk}. That way files can be removed or overwritten only by their owner(s). Unfortunately this does not prevent a ``denial of service'' attack when a perpetrator may fill out directories with a garbage (like empty) files with proper names. No big harm is done on a long run, but repeated pranks like that may turn into a major nuisance. If you were thinking about running \command{MakeTeXPK} ``suid'' (that means --- in a mode which gives a program all privileges of its {\em owner\/}) then you should drop the idea immediately; especially if \command{MakeTeXPK} is owned by \command{root}. This is a {\em shell script} and for many reasons running shell scripts in suid mode is one of the biggest security holes you may think of. Because of that many Unix variants simply disable such scripts, thus saving you from yourself; but even if this is not the case on some particular system do {\bf not} do that. Problems with ``world writable'' directories pale in a comparison. Fortunately not everything is lost as long as you have a compiler and an editor. \command{MakeTeXPK} and relatives (\command{MakeTeXTFM}, \command{MakeTEXMF}, \ldots) may be executed indirectly, by a small compiled ``wrapper'' program and the last one can be safely made ``suid''. This note describes below steps needed to perform such modification. Details and accompanying sample files are for one particular distribution (some version of \command{teTeX} for Linux) but modifications for other installations should be rather straightforward. It goes without saying that you need a \command{root} access for all (ok, most of) these steps. \begin{itemize} \item Create new user account, say \command{tex}, on your system and include it some innocuous group, e.g.~\command{tex}. \end{itemize} The only purpose of of this ``user'' will be to own common \TeX{} files. You may have already some suitable group, like \command{nogroup} or \command{nobody}, so instead you may include your new user there. \begin{itemize} \item Give \command{tex} account \path{/bin/false} for a login shell and disable password by putting \command{*} in the corresponding field. Home directory is not terribly important. Nobody will be ever logging into this account. \end{itemize} An entry in your password file will look after this somewhat like that: \begin{verbatim} tex:*:117:65535:Owner of TeX files:/usr/local/tex:/bin/false \end{verbatim} \begin{itemize} \item Close a loophole in some mail delivery programs by creating an empty file \path{/usr/spool/mail/tex} executing \command{touch /usr/spool/mail/tex}. You may find the file already in place made by some yours system administration utility. Change owner and a group of this file to those of root (\command{chown root:root /usr/spool/mail/tex}) and remove all read and write permissions on it (\command{chmod 000 /usr/spool/mail/tex}). \item Make sure that \command{MakeTeXPK}, and similar scripts you want to execute the same way, are {\bf not} in your \$PATH, or at least not earlier then an intended location of your ``wrapper'' program(s). \end{itemize} For \command{teTeX} distribution, version 0.2, it is enough to delete links in a directory \path{/usr/local/bin}. Real scripts \command{MakeTeXPK}, \command{MakeTeXMF} and \command{MakeTeXTFM} reside in \path{/usr/local/tex/scripts-0.2/bin/} and we may leave them there. \begin{itemize} \item Edit all scripts in question to replace in invocations programs by their absolute locations. Do not forget to perform this task in other scripts which may be called by our \command{MakeTEX...} scripts (this is \command{append\_db} in \command{teTeX} distribution). Change mode used when creating new files to 444 and to 755 for directories. \end{itemize} A proper way to do that is start a script with a series of shell variable definitions similar to \command{MF="/usr/local/bin/mf"} and replace all later occurences of \command{mf} in the script by \command{\$MF}. That way, if you later move your {\sc Metafont} executables to some other place, script editing will be limited to one place. Similar for other programs. Absolute locations are required since, for security reason, we will limit \command{\$PATH} only to \path{"/bin:/usr/bin"}. This means that in theory you may leave things like \command{test}, \command{echo} or \command{rm} alone. In the later case, for ``dangerous'' commands like \command{rm -f} is still a good idea to replace them with definitions similar to \command{RM="/bin/rm -f"} to get a better control on what you are really executing. As a side effect you will ensure that this is a ``real'' system \command{rm} and not some funky user redefinition which asks a lot of questions before doing anything and confuses \command{MakeTeXPK} in the process. Depending on a level of your mistrust you may use a similar approach to \command{echo} and \command{test} as well, but in bundled sample files I have chosen to be more relaxed. Besides they may anyway be ``built-ins'' for some shells. \begin{itemize} \item Edit, to adjust to your system, and compile a program like this one below. \end{itemize} % \begin{verbatim} /****************************************************/ /* */ /* Executable wrapper for MakeTeX... programs. */ /* Calls its namesake from TOOLS directory. */ /* Provide links with different names to make it */ /* multipurpose. */ /* */ /* Michal Jaegermann, Feb 11 1995 */ /* */ /****************************************************/ #include #include #include #define VERSION_S "0.2" /* * If you do not have ANSI compiler you may use * an "explicit"single string in TOOLS define; this * is just a way to make future modifications easier. */ #define TOOLS "/usr/local/tex/scripts-" VERSION_S "/bin/" #define ASIZE 120 /* * This is a list of names under which we are willing * to execute. It has be NULL terminated. */ const char *accepted[] = { "MakeTeXPK", "MakeTeXTFM", "MakeTeXMF", NULL }; int main(int argc, char **argv) { char doer[ASIZE] = TOOLS; int idx = 0; /* * If your compiler is broken and the construction below * does not work then "tail = strchr(doer, '\0');", or * equivalent, will serve as well. */ char *tail = doer + (sizeof(TOOLS) - 1); char *start; /* find our base name */ start = (start = strrchr(argv[0], '/')) ? (start + 1) : argv[0]; /* check if we are on the list */ while (1) { if (NULL == accepted[idx]) exit(1); /* not on the list - bye-bye */ if (0 == strcmp(accepted[idx], start)) break; /* this is ours */ idx += 1; } /* * Set pretty bland, but hopefuly secure environment; * we intend to run this program 'suid'. */ setenv("PATH", "/bin:/usr/bin", 1); setenv("IFS", " ", 1); /* * You may want/need some other calls to setenv(). * For example, if your system has an environment * variable pointing to shared libraries it should * be set here. */ /* * Attach our name at the end of a directory string. * This assumes that real scripts in TOOLS directory * will be called by their own names (but indirectly) */ strcpy(tail, start); setuid(geteuid()); /* we want priviledges of an owner of this program */ return execv(doer, argv); /* do it and tell results */ } \end{verbatim} \begin{itemize} \item Install results of the compilation somewhere in your \command{\$PATH}. A directory \path{/usr/local/bin} is usually a good place. Go there and name your program \command{MakeTeXPK}. Change its ownership and group to that of user \command{tex} by typing \command{chmod tex:tex MakeTeXPK}. (Depending on your variant of Unix you may have to use dot instead of colon to separate user and its group name, or you may have to do that in two steps, using also another command, \command{chgrp}, to acomplish the above. Use a group to which you assigned your \command{tex} user. This is only an example). The program needs ``execute'' and ``set uid'' priviledges (\command{chmod 4755 MakeTeXPK}). Also for your other \command{MakeTeX...} scripts provide corresponding ``call points'' with their names via file links (\command{ln MakeTeXPK MakeTeXTFM}; \command{ln MakeTeXPK MakeTeXMF}). \item Change ownership of all your font files to \command{tex}. Actually you may make \command{tex} an owner of whole directory trees in \TeX{} system files. Assuming that all you want to asign that way is in a tree rooted in \path{texmf} you may accomplish that by doing \command{chown -R tex:tex texmf}. If your \command{chown} does not understand \command{-R} (recursive) flag, then something similar to the following should do: \begin{verbatim} find texmf -print | xargs -n1 chown tex:tex \end{verbatim} See also \command{chown} caveats in the previous item. \end{itemize} \begin{itemize} \item Remove ``write'' permissions for anybody but owner on all directories in question. A command like this should accomplish that task (careful, you do not want to change non-directories): \begin{verbatim} find texmf -type d -print | xargs -n1 chmod 755 \end{verbatim} \end{itemize} You are done. Now, when \command{MakeTeXPK} will be called, directly from a command line, or by some other program like \command{dvips}, your ``wrapper'' program will be executed instead. It will call in turn a ``real'' script but already with an id of an owner of your font directories. \subsubsection*{Concluding remarks} The presented solution is not entirely without problems. Due to ``out of sync'' ownership and permissions \command{kpathsea} library functions may fail, depending on a moment this happened, when trying to write \path{missfont.log} file in cases when font making was not successful. This can likely be hard to resolve without modifying the library itself. If you will really encounter this, then a simple workaround would be to create an empty \path{missfont.log}, owned by you, and to give on it write permissions for everybody \\(\command{touch missfont.log;} \command{chmod a+w missfont.log}). When you are done simply change permissions back to an original state. Another possible trouble spot will occur when you have your ``private'' fonts, because you are conducting some font making experiments, for example, and you would like to have bitmaps created in places owned by you and not by \command{tex}. Otherwise you will not be able to remove results of failed tests. In that case make yourself a private, executable, copy of \command{MakeTeXPK} script, edit it accordingly and make sure that it can be found {\em earlier} in your \command{\$PATH} than a system program with the same name. You will not able to deposit anything in system directories, but this is likely what you want anyway. Your script does not have to run ``suid'', so repeating all of the above is not necessary. Last, but not least, there is possible somewhat another approach to the whole problem. There are only a few commands (\command{mv}, \command{mkdir}, \command{chmod}) which have to modify \TeX{} ``system'' directories. Instead of running the whole \command{MakeTeX} in ``suid'' mode you may write special versions (\command{texmv}, \command{texmkdir}, \command{texchmod}) of these, which would operate ``suid'' \command{tex}, and use them as replacements in \command{MakeTeXPK} script whenever needed. If this is a better idea depends entirely on your situation and security requirements. \end{document} %%% Local Variables: %%% mode: latex %%% TeX-master: t %%% End: