performance – Write a C function to remove all unwanted characters from a string buffer, where buffer argument is changed in-place

The following code was written with the intent to be as efficient as possible, where efficiency includes speed of execution, memory usage, and lines of code, all in support of the primary design constraint that it can change the payload argument buffer in-place.

In its current state:
It does successfully change the buffer in place. This has been tested with a 20Kb text file, and removing all occurrences of up to 26 character values, all from the set of ASCII printable characters. There is no reason I can think of that prevents the sizes of these two arguments from being larger, I just have not run any that are larger. But because the function uses strdup to create a working buffer, speed of execution is affected. And, I am pretty sure it is more verbose than it probably could be in terms of lines of code, which also potentially could result in speed of execution. I believe their could be some positive effects from compiler optimizations, but

I am looking for recommendations for improvements in speed of execution, size of code and memory usage. Any suggestions on any one, or all of these 3 areas will be appreciated.

Code:

////////////////////////////////////////////////////////////////////////////
//
// Description:  Removes all occurrences of characters contained
//               in 'remove buffer' from 'str' buffer.  `str` is 
//               changed and returned
//
// Inputs        char *str     - buffer containing text to be modified
//               char * remove - buffer containing characters to be removed
//
// Outputs       char *str     - modified in place. 
//
// returns       void
//
//  Example:     char buffer() = {"some string with^ sev!eral ***ch###ar@ to& removen"};
//               char s_rem()  = {"^@&*)(#!n"};
//               remove_chars(buffer, s_rem);
//
////////////////////////////////////////////////////////////////////////////
void remove_chars(char *str, char *remove)
{
    const char *o = remove;//original location keeper
    const char *oStr = str;//original location keeper
    int found = 0;
    char *dup = strdup(str);
    if(dup)
    {
        const char *oDup = dup;
        while(*str)//walk through string
        {
            while(*remove)//walk through unwanted list for each string char
            {
                if(*str == *remove)//compare characters, one-by-one
                {
                    remove = o;//place unwanted list to beginning of array
                    found = 1;
                    break;
                }
                else
                {
                    remove++;
                }
            }
            if(found)
            {
                str++;//skip unwanted character if found
                found = 0;
            }
            else
            {
                *dup = *str;// move both pointers if unwanted not found
                dup++;
                str++;      
            }
            remove = o;
        }
        *dup = 0;//NULL terminate
        dup = oDup;//bring pointer to original location
        str = oStr;//bring pointer to original location
        strcpy(str, dup); //place updated string into original   
        free(dup);
    }
}