Skip to content
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

fileobject.c can switch between fread and fwrite without an intervening flush or seek, invoking undefined behaviour #52200

Closed
davidsarah mannequin opened this issue Feb 18, 2010 · 4 comments
Assignees
Labels

Comments

@davidsarah
Copy link
Mannequin

davidsarah mannequin commented Feb 18, 2010

BPO 7952
Nosy @birkenfeld, @pitrou

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = 'https://github.com/pitrou'
closed_at = <Date 2010-08-01.12:23:13.774>
created_at = <Date 2010-02-18.00:21:53.012>
labels = ['type-security', 'invalid', 'expert-IO']
title = 'fileobject.c can switch between fread and fwrite without an intervening flush or seek, invoking undefined behaviour'
updated_at = <Date 2010-08-01.12:23:13.772>
user = 'https://bugs.python.org/davidsarah'

bugs.python.org fields:

activity = <Date 2010-08-01.12:23:13.772>
actor = 'pitrou'
assignee = 'pitrou'
closed = True
closed_date = <Date 2010-08-01.12:23:13.774>
closer = 'pitrou'
components = ['IO']
creation = <Date 2010-02-18.00:21:53.012>
creator = 'davidsarah'
dependencies = []
files = []
hgrepos = []
issue_num = 7952
keywords = []
message_count = 4.0
messages = ['99483', '99492', '99493', '112320']
nosy_count = 3.0
nosy_names = ['georg.brandl', 'pitrou', 'davidsarah']
pr_nums = []
priority = 'normal'
resolution = 'not a bug'
stage = None
status = 'closed'
superseder = None
type = 'security'
url = 'https://bugs.python.org/issue7952'
versions = ['Python 2.7']

@davidsarah
Copy link
Mannequin Author

davidsarah mannequin commented Feb 18, 2010

The C standard (any version, or POSIX), says in the description of fopen that:
{{{
When a file is opened with update mode ( '+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, the application shall ensure that output is not directly followed by input without an intervening call to fflush() or to a file positioning function ( fseek(), fsetpos(), or rewind()), and input is not directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
}}}

Objects/fileobject.c makes calls to fread and fwrite without taking this into account. So calls from Python to read or write methods of a file object opened in any "rw" mode, may invoke undefined behaviour. It isn't reasonable to rely on Python code to avoid this situation, even if were considered acceptable in C. (Arguably this is a bug in the C standard, but it is unlikely to be fixed there or in POSIX, because of differences in philosophy about language safety.)

To fix this, fileobject.c should keep track of whether the last I/O operation was an input or output, and perform a call to fflush whenever an input follows an output or vice versa. This should not significantly affect performance in any case where the behaviour was previously defined (in cases where it wasn't, correctness trumps performance). fflush does not affect the file position and should have no other negative effect, because the stdio implementation is free to flush buffered data at any time (and certainly on I/O operations).

Despite the undefined behaviour, I don't currently know of a platform where this would lead to an exploitable security bug. I'm marking this issue as security-relevant anyway, because it may prevent analysing whether Python applications behave securely only on the basis of documented behaviour.

@davidsarah davidsarah mannequin added topic-IO type-security A security issue labels Feb 18, 2010
@davidsarah
Copy link
Mannequin Author

davidsarah mannequin commented Feb 18, 2010

Correction: when input is followed by output, the call needed to avoid undefined behaviour has to be to a "file positioning function" (fseek, fsetpos, or rewind, but not fflush). Since fileobject.c does not use wide I/O operations, it should be sufficient to use _portable_fseek(fp, 0, SEEK_SET).

(_portable_fseek may call some function that is not strictly defined to be a "file positioning function", e.g. fseeko() or fseek64(). However, it would be insane for a stdio implementation not to treat those as being file positioning functions as far as the intent of the C or POSIX standards is concerned.)

@davidsarah
Copy link
Mannequin Author

davidsarah mannequin commented Feb 18, 2010

"... it should be sufficient to use _portable_fseek(fp, 0, SEEK_SET)."

I meant SEEK_CUR here.

@pitrou
Copy link
Member

pitrou commented Aug 1, 2010

The 2.x file object mostly mirrors abilities of the standard C buffered IO functions (including, for example, special behaviour of text files under Windows). Therefore, Python code should call flush() manually if needed. It should be noted that the 2.x file object has been existing for ages and this issue is, to my knowledge, very rarely brought up.

The 3.x IO library should not have this problem since we wrote our own buffering layer, and we have dedicated tests for mixed reads and writes.

@pitrou pitrou closed this as completed Aug 1, 2010
@pitrou pitrou added the invalid label Aug 1, 2010
@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant