Skip to content

Commit

Permalink
Merge pull request #309 from jamezp/LOGMGR-275-2.1
Browse files Browse the repository at this point in the history
[LOGMGR-277] Use privileged actions for rotating files as the securit…
  • Loading branch information
jamezp authored Jun 8, 2020
2 parents df3aaf2 + b711745 commit 0ed5c9f
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
Expand All @@ -36,6 +40,7 @@
*/
public class PeriodicRotatingFileHandler extends FileHandler {

private final AccessControlContext acc = AccessController.getContext();
private SimpleDateFormat format;
private String nextSuffix;
private Period period = Period.NEVER;
Expand Down Expand Up @@ -128,7 +133,7 @@ protected void preWrite(final ExtLogRecord record) {
* @throws IllegalArgumentException if the suffix is not valid
*/
public void setSuffix(String suffix) throws IllegalArgumentException {
final SuffixRotator suffixRotator = SuffixRotator.parse(suffix);
final SuffixRotator suffixRotator = SuffixRotator.parse(acc, suffix);
final String dateSuffix = suffixRotator.getDatePattern();
final SimpleDateFormat format = new SimpleDateFormat(dateSuffix);
format.setTimeZone(timeZone);
Expand Down Expand Up @@ -192,11 +197,11 @@ private void rollOver() {
try {
final File file = getFile();
// first, close the original file (some OSes won't let you move/rename a file that is open)
setFile(null);
setFileInternal(null);
// next, rotate it
suffixRotator.rotate(getErrorManager(), file.toPath(), nextSuffix);
suffixRotator.rotate(SecurityActions.getErrorManager(acc, this), file.toPath(), nextSuffix);
// start new file
setFile(file);
setFileInternal(file);
} catch (IOException e) {
reportError("Unable to rotate log file", e, ErrorManager.OPEN_FAILURE);
}
Expand Down Expand Up @@ -292,6 +297,22 @@ public void setTimeZone(final TimeZone timeZone) {
this.timeZone = timeZone;
}

private void setFileInternal(final File file) throws FileNotFoundException {
// At this point we should have already checked the security required
if (System.getSecurityManager() == null) {
super.setFile(file);
} else {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
try {
super.setFile(file);
} catch (FileNotFoundException e) {
throw new UncheckedIOException(e);
}
return null;
}, acc);
}
}

private static <T extends Comparable<? super T>> T min(T a, T b) {
return a.compareTo(b) <= 0 ? a : b;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.ErrorManager;

import org.jboss.logmanager.ExtLogRecord;
Expand All @@ -38,6 +42,7 @@
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
public class PeriodicSizeRotatingFileHandler extends PeriodicRotatingFileHandler {
private final AccessControlContext acc = AccessController.getContext();
// by default, rotate at 10MB
private long rotateSize = 0xa0000L;
private int maxBackupIndex = 1;
Expand Down Expand Up @@ -148,18 +153,20 @@ public void setOutputStream(final OutputStream outputStream) {
*/
@Override
public void setFile(final File file) throws FileNotFoundException {
checkAccess(this);
synchronized (outputLock) {
// Check for a rotate
if (rotateOnBoot && maxBackupIndex > 0 && file != null && file.exists() && file.length() > 0L) {
final String suffix = getNextSuffix();
final SuffixRotator suffixRotator = getSuffixRotator();
if (suffixRotator != SuffixRotator.EMPTY && suffix != null) {
// Make sure any previous files are closed before we attempt to rotate
setFileInternal(null);
setFileInternal(null, false);
// Previous actions have already performed
suffixRotator.rotate(getErrorManager(), file.toPath(), suffix, maxBackupIndex);
}
}
setFileInternal(file);
setFileInternal(file, false);
}
}

Expand Down Expand Up @@ -224,19 +231,34 @@ protected void preWrite(final ExtLogRecord record) {
return;
}
// close the old file.
setFileInternal(null);
getSuffixRotator().rotate(getErrorManager(), file.toPath(), getNextSuffix(), maxBackupIndex);
setFileInternal(null, true);
getSuffixRotator().rotate(SecurityActions.getErrorManager(acc, this), file.toPath(), getNextSuffix(), maxBackupIndex);
// start with new file.
setFileInternal(file);
setFileInternal(file, true);
} catch (IOException e) {
reportError("Unable to rotate log file", e, ErrorManager.OPEN_FAILURE);
}
}
}

private void setFileInternal(final File file) throws FileNotFoundException {
super.setFile(file);
if (outputStream != null)
outputStream.currentSize = file == null ? 0L : file.length();
private void setFileInternal(final File file, final boolean doPrivileged) throws FileNotFoundException {
if (System.getSecurityManager() == null || !doPrivileged) {
super.setFile(file);
if (outputStream != null) {
outputStream.currentSize = file == null ? 0L : file.length();
}
} else {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
try {
super.setFile(file);
if (outputStream != null) {
outputStream.currentSize = file == null ? 0L : file.length();
}
} catch (FileNotFoundException e) {
throw new UncheckedIOException(e);
}
return null;
}, acc);
}
}
}
68 changes: 68 additions & 0 deletions src/main/java/org/jboss/logmanager/handlers/SecurityActions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2020 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jboss.logmanager.handlers;

import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.function.Supplier;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;

/**
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
class SecurityActions {

static ErrorManager getErrorManager(final AccessControlContext acc, final Handler handler) {
Supplier<ErrorManager> supplier = () -> {
if (System.getSecurityManager() == null) {
return handler.getErrorManager();
}
return AccessController.doPrivileged((PrivilegedAction<ErrorManager>) handler::getErrorManager, acc);
};
return new LazyErrorManager(supplier);
}

private static class LazyErrorManager extends ErrorManager {
private final Supplier<ErrorManager> supplier;
private volatile ErrorManager delegate;

private LazyErrorManager(final Supplier<ErrorManager> supplier) {
this.supplier = supplier;
}

@Override
public synchronized void error(final String msg, final Exception ex, final int code) {
getDelegate().error(msg, ex, code);
}

private ErrorManager getDelegate() {
if (delegate == null) {
synchronized (this) {
if (delegate == null) {
delegate = supplier.get();
}
}
}
return delegate;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@
import java.io.FileNotFoundException;
import org.jboss.logmanager.ExtLogRecord;

import java.io.UncheckedIOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.ErrorManager;

public class SizeRotatingFileHandler extends FileHandler {
private final AccessControlContext acc = AccessController.getContext();
// by default, rotate at 10MB
private long rotateSize = 0xa0000L;
private int maxBackupIndex = 1;
Expand Down Expand Up @@ -136,14 +141,15 @@ public void setOutputStream(final OutputStream outputStream) {
* @throws RuntimeException if there is an attempt to rotate file and the rotation fails
*/
public void setFile(final File file) throws FileNotFoundException {
checkAccess(this);
synchronized (outputLock) {
// Check for a rotate
if (rotateOnBoot && maxBackupIndex > 0 && file != null && file.exists() && file.length() > 0L) {
// Make sure any previous files are closed before we attempt to rotate
setFileInternal(null);
setFileInternal(null, false);
suffixRotator.rotate(getErrorManager(), file.toPath(), maxBackupIndex);
}
setFileInternal(file);
setFileInternal(file, false);
}
}

Expand Down Expand Up @@ -228,7 +234,7 @@ public String getSuffix() {
public void setSuffix(final String suffix) {
checkAccess(this);
synchronized (outputLock) {
this.suffixRotator = SuffixRotator.parse(suffix);
this.suffixRotator = SuffixRotator.parse(acc, suffix);
}
}

Expand All @@ -244,19 +250,34 @@ protected void preWrite(final ExtLogRecord record) {
return;
}
// close the old file.
setFileInternal(null);
suffixRotator.rotate(getErrorManager(), file.toPath(), maxBackupIndex);
setFileInternal(null, true);
suffixRotator.rotate(SecurityActions.getErrorManager(acc, this), file.toPath(), maxBackupIndex);
// start with new file.
setFileInternal(file);
setFileInternal(file, true);
} catch (IOException e) {
reportError("Unable to rotate log file", e, ErrorManager.OPEN_FAILURE);
}
}
}

private void setFileInternal(final File file) throws FileNotFoundException {
super.setFile(file);
if (outputStream != null)
outputStream.currentSize = file == null ? 0L : file.length();
private void setFileInternal(final File file, final boolean doPrivileged) throws FileNotFoundException {
if (System.getSecurityManager() == null || !doPrivileged) {
super.setFile(file);
if (outputStream != null) {
outputStream.currentSize = file == null ? 0L : file.length();
}
} else {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
try {
super.setFile(file);
if (outputStream != null) {
outputStream.currentSize = file == null ? 0L : file.length();
}
} catch (FileNotFoundException e) {
throw new UncheckedIOException(e);
}
return null;
}, acc);
}
}
}
Loading

0 comments on commit 0ed5c9f

Please sign in to comment.