-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move compilation daemon portfile to homedir #6108
Conversation
Store the compilation daemon's administrativia (port file, redirection) under `~/.scalac/`, instead of the less standard `/tmp/scala-devel/${USER:shared}/scalac-compile-server-port`. On creation, remove group- and other-permissions from these private files, ditto for the repl's history file. On Java 6 on Windows, opt in to compilation daemon using `-nc:false`.
|
||
|
||
trait OwnerOnlyChmod { | ||
/** Remove group/other permisisons for `file`, it if exists */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo (permissions)
|
||
private def defaultUseCompdaemon = { | ||
// can't reliably lock down permissions on the portfile in this environment => disable by default. | ||
!scala.util.Properties.isWin || scala.util.Properties.isJavaAtLeast("7") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should print a warning here rather than silently giving different behavior
val secret = new SecureRandom().nextInt.toString | ||
val secretBytes = new Array[Byte](16) | ||
new SecureRandom().nextBytes(secretBytes) | ||
val secretDigits = new BigInteger(secretBytes).toString().getBytes("UTF-8") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these 3 lines of code are quite mystifying. some comments explaining the motivation would be good
def chmod(file: File): Unit = if (file.exists()) { | ||
def clearAndSetOwnerOnly(f: (Boolean, Boolean) => Boolean): Unit = { | ||
def fail() = throw new IOException("Unable to modify permissions of " + file) | ||
// attribute = false, ownerOwnly = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo here and 2 lines down: ownly -> only
val aclEntryPermissionValues = aclEntryPermission_class.getDeclaredMethod("values") | ||
val aclEntryType_ALLOW = aclEntryType_class.getDeclaredField("ALLOW") | ||
} | ||
private val reflectors = try { new Reflectors } catch { case ex: Throwable => null } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we log the swallowed exception?
protected lazy val historyFile: File = FileBackedHistory.defaultFile | ||
// For a history file in the standard location, always try to restrict permission, | ||
// creating an empty file if none exists. | ||
// For a user-specified location, only lock down permissions on if we're the ones |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing word in this sentence
try OwnerOnlyChmod().chmodOrCreateEmpty(p.jfile) | ||
catch { case NonFatal(e) => | ||
if (interpreter.isReplDebug) e.printStackTrace() | ||
interpreter.replinfo(s"Warning: history file ${p}'s permissions could not be restricted to owner-only.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is warning and continuing considered sufficiently secure?
@retronym, ready for final review |
@szeiger could you give this a go on your surface and any other windows desktops at your disposal ? |
} finally { | ||
fos2.close() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that creating a file then changing the permissions on the file allows a race condition where an attacker on the system can open the file between the file create and the permissions change. It is far safer to use open(2) to set the permissions restrictive while creating the file.
Furthermore if this code is ever run on a directory with shared writing permissions, it's possible for an attacker to unlink(file), set a symlink in place, and have the process change modes of any target that the process has privileges to modify. fchmod(2) is the safe way to change permissions on a file that is already open, though that won't fix the above race condition. So consider this just an aside.
Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. Could you suggest how to do this on Java 6? I agree the race condition is a security hole, but couldn't figure out how to do this atomically with the API we have available. I think our NIO-based implementation on Java 8 is closer to what you're suggesting: https://github.com/scala/scala/pull/6120/files#diff-3578ac76088d22b5d9912e984dee3affR46.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review.
We implemented things that way (or at least, tried to) in the 2.12 branch where we could link against the Java 8 NIO API. Scala 2.11 still supports Java 6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adriaanm a minute ago
retronym 29 seconds ago
Speaking of race conditions :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The #diff-3578ac7.. link above looks like it may have the same race condition.
I don't know Java particularly well any longer, so it's hard to suggest a replacement. Two possibilities come to mind:
- set the umask to 0077 (octal), create the file, set the modes, and then reset umask to whatever the user wanted
- chmod 0700 (octal) the containing directory, create the file, set the file modes, then reset the directory to whatever permissions it should have.
I hope this helps. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about: create the file with some temporary name/location, do what you need to do and then move it. file moves are atomic.
Store the compilation daemon's administrativia (port file, redirection)
under
~/.scalac/
, instead of the less standard/tmp/scala-devel/${USER:shared}/scalac-compile-server-port
.On creation, remove group- and other-permissions from these
private files, ditto for the repl's history file.
On Java 6 on Windows, opt in to compilation daemon using
-nc:false
.