Skip to content

Commit

Permalink
[LOGMGR-275] Use privileged actions for rotating files as the securit…
Browse files Browse the repository at this point in the history
…y context is not guaranteed to be the system level context in WildFly.

https://issues.redhat.com/browse/LOGMGR-275
  • Loading branch information
jamezp committed Jun 8, 2020
1 parent cc4ecc7 commit 0a2da60
Show file tree
Hide file tree
Showing 5 changed files with 302 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 @@ -37,6 +41,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 @@ -129,7 +134,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 @@ -193,11 +198,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 @@ -293,6 +298,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:jperkins@redhat.com">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,19 @@ public void setOutputStream(final OutputStream outputStream) {
*/
@Override
public void setFile(final File file) throws FileNotFoundException {
checkAccess();
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);
suffixRotator.rotate(getErrorManager(), file.toPath(), suffix, maxBackupIndex);
}
}
setFileInternal(file);
setFileInternal(file, false);
}
}

Expand Down Expand Up @@ -224,19 +230,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);
}
}
}
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.ext.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:jperkins@redhat.com">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 @@ -23,12 +23,17 @@
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;
import org.jboss.logmanager.handlers.FileHandler;

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 @@ -137,14 +142,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();
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 @@ -229,7 +235,7 @@ public String getSuffix() {
public void setSuffix(final String suffix) {
checkAccess();
synchronized (outputLock) {
this.suffixRotator = SuffixRotator.parse(suffix);
this.suffixRotator = SuffixRotator.parse(acc, suffix);
}
}

Expand All @@ -245,19 +251,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 0a2da60

Please sign in to comment.