4

The man page of strncpy states:

char *strncpy(char *dest, const char *src, size_t n);

The strcpy() and strncpy() functions return a pointer to the destination string dest.

Is it possible that strncpy(buff, "something", 9) == 0 be true if char buff[100]?

UPDATE

I also consider it as not very probable but it's part of a program that I should make to bufferoverflow and this condition stays on my way to achieve this.

Community
  • 1
  • 1
Brozorec
  • 1,163
  • 9
  • 15
  • Why is that supposed to return 0? – cdonts Nov 07 '15 at 17:45
  • 1
    The only case when it can return NULL (I guess) would be `strncpy(NULL, "something", 0)`... – Alex Lop. Nov 07 '15 at 17:47
  • Since it returns the destination string, and when compared with `0`, a pointer is checked for being `NULL`, and `NULL` is not a valid memory location to copy to, hence no, this function cannot legally return a pointer that compares equal to 0. – The Paramagnetic Croissant Nov 07 '15 at 17:49
  • 1
    But when you pass `NULL` pointer the function does not return 0. *"If strDest or strSource is a NULL pointer, or if count is less than or equal to zero, the invalid parameter handler is invoked, as described in Parameter Validation. If execution is allowed to continue, these functions return -1 and set errno to EINVAL"* (MSVC). – Weather Vane Nov 07 '15 at 17:51
  • 2
    @WeatherVane also, cppreference [says](http://en.cppreference.com/w/c/string/byte/strncpy): "The behavior is undefined if either dest or src is not a pointer to a character array." – I couldn't find this clause in my copy of the C99 standard, but I've also read somewhere that when "a pointer to…" is required, and the standard does not explicitly say that the supplied pointer may be `NULL` in some circumstances, then it should not be `NULL`. – The Paramagnetic Croissant Nov 07 '15 at 17:52
  • @WeatherVane: That may be true for MSVC, but I don't believe it's in any sort of C standard... – psmears Nov 07 '15 at 17:53
  • If you want to use some buffer overflow/stack smashing then sure, you can get it to return anything you want. But that's implementation dependent, and totally changes this question. I might suggest opening a new question if that's what you want to ask. – Cornstalks Nov 07 '15 at 18:20
  • @Cornstalks You're right, I just wanted some opinions if it's possible in normal conditions. – Brozorec Nov 07 '15 at 18:26
  • 1
    @Zozo - in *normal* conditions? No, it won't happen. But if your process does `mmap()` with `MAP_FIXED`, and somehow `NULL` gets passed to `mmap` as the first parameter, you will find that `NULL` references valid memory. There are probably other memory-management functions that can do the same (although `shmat()` seems immune to this type of abuse because of the way it's specified. See http://pubs.opengroup.org/onlinepubs/009695399/functions/shmat.html) – Andrew Henle Nov 07 '15 at 18:31
  • 2
    @AndrewHenle: pointing out that there are (abnormal) ways to get it to return null is neat, but spamming it across all the answers is just going to cause confusion to readers, given the fact that no, it can't return null under normal circumstances. – Cornstalks Nov 07 '15 at 18:33
  • @Zozo: If your interest is in normal conditions, then I might suggest you remove your **UPDATE**, as that's modifying the question to include abnormal conditions. – Cornstalks Nov 07 '15 at 18:36
  • @Cornstalks As I pointed out in response to other (now deleted and cleaned) comments, the preconditions are not *that* hard to cause to happen inadvertently. Answers that unequivocally state **NO** are simply incorrect. – Andrew Henle Nov 07 '15 at 18:37
  • 1
    @AndrewHenle: No, they, aren't incorrect. mmaping null as a writable fixed region of memory and then passing it to strcpy is not normal (yes, it can be useful, but no, it's not normal). I'm pretty sure the OP means well-defined/well-behaved execution when referring to "normal conditions." Answers that state "no" don't authoritatively override the meaning of undefined behavior, and as such, if your program has undefined behavior, then yeah, sure, expect anything. But nasal demons aren't normal (or at the very least, shouldn't be). – Cornstalks Nov 07 '15 at 18:43
  • @Cornstalks - They **are** incorrect. I've demonstrated that. What Zozo does with the information I've provided is up to him - only he really knows the entire context of his question. Continually trying to minimize the information I've posted is imposing your beliefs on his context. – Andrew Henle Nov 07 '15 at 18:49
  • "They are incorrect. I've demonstrated that." -- You have done no such thing. The question is about `char buff[100]; strncpy(buff, "something", 9)` ... that *cannot* return NULL because `buff` *cannot* be NULL. – Jim Balter Nov 13 '15 at 08:39
  • OP is asking the wrong question. The bug most likely has to do with the fact that `strncpy` doesn't NUL-terminate the destination. – Jim Balter Nov 13 '15 at 08:51
  • @AlexLop. C11 states: " Where an argument declared as `size_t n` specifies the length of the array for a function, `n` can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4." – S.S. Anne Aug 24 '19 at 17:39

5 Answers5

5

No.

Judging from the facts that

  1. The null pointer constant NULL's value equals 0
  2. A NULL pointer shall not point to a valid object. From the C11 standard, §6.3.2.3:

    [...] a null pointer [,] is guaranteed to compare unequal to a pointer to any object or function.

and that the corresponding man page does not mention the possibility of dest == NULL,
it is not allowed to.

Community
  • 1
  • 1
cadaniluk
  • 15,027
  • 2
  • 39
  • 67
  • It *can* return `NULL` if a valid character array exists at an address that corresponds to the value of `NULL`. Pass `NULL` to `mmap()` with `MAP_FIXED` set and it will likely happily map away at a virtual address of zero. – Andrew Henle Nov 07 '15 at 18:27
4

Think about it. What does the man page say? It says it returns dest. Therefore, if dest is not NULL, then the return value will not be NULL.

Since buff will never be NULL (assuming it's char buff[100]), then you can say with certainty that no, it will never return NULL.

If it does, it's got a bug.

Cornstalks
  • 37,137
  • 18
  • 79
  • 144
  • `mmap()` a writeable page at address 0 on a system that uses zero for a `NULL`. Your system will probably allow that. Then call `strcpy( NULL, s );`, and it will return `NULL`. UB is UB - any result can happen, and it's not a bug if it does. – Andrew Henle Nov 07 '15 at 17:59
  • Actually, I have to find the bug in the given program and to make a bufferoverflow. – Brozorec Nov 07 '15 at 18:15
  • 1
    Well yeah, sure, if you want to play with undefined behavior, then anything can happen. But I think that's out of the scope of the question (at least the original question). The original question had no mention of undefined behavior, and clearly mentioned the pointer passed to the function wasn't `NULL` (and didn't involve any buffer overflows). – Cornstalks Nov 07 '15 at 18:21
  • @Zozo - *Actually, I have to find the bug in the given program and to make a bufferoverflow.* Don't go about searching for memory errors by manually hunting for them - use a tool like `valgrind`. Looking for memory errors manually is unlikely to work - if it were easy, the original code wouldn't have the error. – Andrew Henle Nov 07 '15 at 18:41
  • 1
    @AndrewHenle: FYI, I state if `dest` is not `NULL`, then the return value will not be `NULL`. I never said anything about it not returning `NULL` if `dest` is `NULL` itself. – Cornstalks Nov 07 '15 at 18:46
  • "Don't go about searching for memory errors by manually hunting for them - use a tool like valgrind. Looking for memory errors manually is unlikely to work - if it were easy, the original code wouldn't have the error." -- This is completely clueless. The OP has an exploitable program and is tasked with figuring out the exploit. valgrind is irrelevant. – Jim Balter Nov 13 '15 at 08:36
2

In my opinion if the executed code doesn't contain any undefined behavior, the given code cannot return NULL.

The only case when it can return NULL is if the destination is NULL. In such case (most likely) the execution will segfault unless the number of copied characters is 0.

In the given example:

strncpy(buff, "something", 9)

Neither the destination can be NULL ( since it is char buff[100]), nor number of copied characters can be 0 since it is given as 9.

Alex Lop.
  • 6,810
  • 1
  • 26
  • 45
1

According to the ISO/IEC 9899:2011 standard §7.24.2.4/c4 The strncpy: function

Synopsis

1   #include <string.h>
    char *strncpy(char * restrict s1,
    const char * restrict s2,
    size_t n);

Description

2 The strncpy function copies not more than n characters (characters that > follow a null character are not copied) from the array pointed to by s2 to the array pointed to by

3 If the array pointed to by s2 is a string that is shorter than n characters, > null characters are appended to the copy in the array pointed to by s1, until n characters in all have been written.

Returns

4 The strncpy function returns the value of s1. s1. If copying takes place between objects that overlap, the behavior is undefined.

As such, the only way for strncpy to return 0 (i.e., NULL) with out causing undefined behaviour is if s1 is NULL and n is zero.

LIVE DEMO

101010
  • 41,839
  • 11
  • 94
  • 168
0

Yes strncpy() can return NULL. Just mmap a writeable page at address zero on a system that defines NULL as a pointer with zero as its numeric value:

#include <sys/mman.h>
#include <stdio.h>
#include <strings.h>

int main( int argc, char **argv )
{
    char *p;
    char *buf = mmap( ( void * ) 0, 4096,
        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0 );
    p = strncpy( buf, "string", strlen( "string" ) );
    printf( "p: %p\n", p );
    printf( "NULL: %p\n", NULL );
    return( 0 );
}

Yes, this is intentionally violating the C standard requirement that NULL must not point to a valid object, so it's undefined behavior.

But it CAN happen.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • 1
    Did you actually *try* that code? While it is true that Linux will allow you to mmap page 0 using `MAP_FIXED`, only the privileged user has permissions to do so. Running your code as a normal user will segfault because the mmap returns (void*)(-1) with errno set to EPERM. Also, `#include ` is wrong (and will result in `strncpy` not being declared), and if you compile in a strict environment (eg `-std=c11`), then you need `#define _BSD_SOURCE` (or `_GNU_SOURCE`) in order for `MAP_ANON` to be defined. See http://ideone.com/hM6MkH – rici Nov 08 '15 at 00:57
  • @rici The POSIX **standard** for `mmap()` (http://pubs.opengroup.org/onlinepubs/009695399/functions/mmap.html) lists no such restrictions. The world extends beyond Linux. – Andrew Henle Nov 08 '15 at 01:37
  • 1
    The POSIX **standard** doesn't include MAP_ANON, which is why you need a non-standard feature-test macro to get it defined. – rici Nov 08 '15 at 01:46